summaryrefslogtreecommitdiffstats
path: root/btif
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2012-12-12 16:00:35 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2012-12-12 16:00:35 -0800
commit5738f83aeb59361a0a2eda2460113f6dc9194271 (patch)
treebf9fb1c890a681253207fe5d48e2cd56b94de3a7 /btif
downloadexternal_bluetooth_bluedroid-5738f83aeb59361a0a2eda2460113f6dc9194271.zip
external_bluetooth_bluedroid-5738f83aeb59361a0a2eda2460113f6dc9194271.tar.gz
external_bluetooth_bluedroid-5738f83aeb59361a0a2eda2460113f6dc9194271.tar.bz2
Snapshot cdeccf6fdd8c2d494ea2867cb37a025bf8879baf
Change-Id: Ia2de32ccb97a9641462c72363b0a8c4288f4f36d
Diffstat (limited to 'btif')
-rw-r--r--btif/co/bta_ag_co.c132
-rw-r--r--btif/co/bta_av_co.c1504
-rw-r--r--btif/co/bta_dm_co.c417
-rw-r--r--btif/co/bta_fs_co.c1181
-rw-r--r--btif/co/bta_hh_co.c276
-rw-r--r--btif/co/bta_hl_co.c459
-rw-r--r--btif/co/bta_pan_co.c334
-rw-r--r--btif/co/bta_sys_co.c57
-rw-r--r--btif/include/btif_api.h328
-rw-r--r--btif/include/btif_av.h116
-rw-r--r--btif/include/btif_av_api.h210
-rw-r--r--btif/include/btif_av_co.h173
-rw-r--r--btif/include/btif_common.h183
-rw-r--r--btif/include/btif_config.h77
-rw-r--r--btif/include/btif_config_util.h62
-rw-r--r--btif/include/btif_dm.h49
-rw-r--r--btif/include/btif_hh.h102
-rw-r--r--btif/include/btif_hl.h366
-rw-r--r--btif/include/btif_media.h248
-rw-r--r--btif/include/btif_pan.h36
-rw-r--r--btif/include/btif_pan_internal.h118
-rw-r--r--btif/include/btif_profile_queue.h37
-rw-r--r--btif/include/btif_sm.h118
-rw-r--r--btif/include/btif_sock.h36
-rw-r--r--btif/include/btif_sock_rfc.h38
-rw-r--r--btif/include/btif_sock_sdp.h39
-rw-r--r--btif/include/btif_sock_thread.h49
-rw-r--r--btif/include/btif_sock_util.h65
-rw-r--r--btif/include/btif_storage.h313
-rw-r--r--btif/include/btif_util.h73
-rw-r--r--btif/include/uinput.h590
-rw-r--r--btif/src/bluetooth.c413
-rwxr-xr-xbtif/src/btif_av.c970
-rw-r--r--btif/src/btif_config.c744
-rw-r--r--btif/src/btif_config_util.cpp674
-rwxr-xr-xbtif/src/btif_core.c1431
-rwxr-xr-xbtif/src/btif_dm.c1876
-rwxr-xr-xbtif/src/btif_hf.c1200
-rw-r--r--btif/src/btif_hh.c1630
-rw-r--r--btif/src/btif_hl.c5224
-rwxr-xr-xbtif/src/btif_media_task.c2287
-rw-r--r--btif/src/btif_pan.c668
-rw-r--r--btif/src/btif_profile_queue.c187
-rw-r--r--btif/src/btif_rc.c492
-rw-r--r--btif/src/btif_sm.c205
-rw-r--r--btif/src/btif_sock.c182
-rw-r--r--btif/src/btif_sock_rfc.c985
-rw-r--r--btif/src/btif_sock_sdp.c443
-rw-r--r--btif/src/btif_sock_thread.c593
-rw-r--r--btif/src/btif_sock_util.c266
-rwxr-xr-xbtif/src/btif_storage.c1410
-rw-r--r--btif/src/btif_util.c462
52 files changed, 30128 insertions, 0 deletions
diff --git a/btif/co/bta_ag_co.c b/btif/co/bta_ag_co.c
new file mode 100644
index 0000000..cd969f8
--- /dev/null
+++ b/btif/co/bta_ag_co.c
@@ -0,0 +1,132 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+#include "gki.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bte_appl.h"
+
+#define LOG_TAG "BTA_AG_CO: "
+
+#ifndef LINUX_NATIVE
+#include <cutils/properties.h>
+#include <cutils/log.h>
+#else
+#include <stdio.h>
+#define LOGI(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#define LOGD(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#define LOGV(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#define LOGE(format, ...) fprintf (stderr, LOG_TAG format"\n", ## __VA_ARGS__)
+#endif
+
+
+/*******************************************************************************
+**
+** Function bta_ag_co_init
+**
+** Description This callout function is executed by AG when it is
+** started by calling BTA_AgEnable(). This function can be
+** used by the phone to initialize audio paths or for other
+** initialization purposes.
+**
+**
+** Returns Void.
+**
+*******************************************************************************/
+void bta_ag_co_init(void)
+{
+ BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_co_audio_state
+**
+** Description This function is called by the AG before the audio connection
+** is brought up, after it comes up, and after it goes down.
+**
+** Parameters handle - handle of the AG instance
+** state - Audio state
+** BTA_AG_CO_AUD_STATE_OFF - Audio has been turned off
+** BTA_AG_CO_AUD_STATE_OFF_XFER - Audio has been turned off (xfer)
+** BTA_AG_CO_AUD_STATE_ON - Audio has been turned on
+** BTA_AG_CO_AUD_STATE_SETUP - Audio is about to be turned on
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_co_audio_state(UINT16 handle, UINT8 app_id, UINT8 state)
+{
+ BTIF_TRACE_DEBUG2("bta_ag_co_audio_state: handle %d, state %d", handle, state);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_co_data_open
+**
+** Description This function is executed by AG when a service level connection
+** is opened. The phone can use this function to set
+** up data paths or perform any required initialization or
+** set up particular to the connected service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_co_data_open(UINT16 handle, tBTA_SERVICE_ID service)
+{
+ BTIF_TRACE_DEBUG2("bta_ag_co_data_open handle:%d service:%d", handle, service);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_co_data_close
+**
+** Description This function is called by AG when a service level
+** connection is closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_co_data_close(UINT16 handle)
+{
+ BTIF_TRACE_DEBUG1("bta_ag_co_data_close handle:%d", handle);
+}
+
+
+/*******************************************************************************
+ **
+ ** Function bta_ag_co_tx_write
+ **
+ ** Description This function is called by the AG to send data to the
+ ** phone when the AG is configured for AT command pass-through.
+ ** The implementation of this function must copy the data to
+ ** the phones memory.
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void bta_ag_co_tx_write(UINT16 handle, UINT8 * p_data, UINT16 len)
+{
+ BTIF_TRACE_DEBUG2( "bta_ag_co_tx_write: handle: %d, len: %d", handle, len );
+}
+
diff --git a/btif/co/bta_av_co.c b/btif/co/bta_av_co.c
new file mode 100644
index 0000000..6089532
--- /dev/null
+++ b/btif/co/bta_av_co.c
@@ -0,0 +1,1504 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-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 is the advanced audio/video call-out function implementation for
+ * BTIF.
+ *
+ ******************************************************************************/
+
+#include "string.h"
+#include "a2d_api.h"
+#include "a2d_sbc.h"
+#include "bta_sys.h"
+#include "bta_av_api.h"
+#include "bta_av_co.h"
+#include "bta_av_ci.h"
+#include "bta_av_sbc.h"
+
+#include "btif_media.h"
+#include "sbc_encoder.h"
+#include "btif_av_co.h"
+
+
+/*****************************************************************************
+ ** Constants
+ *****************************************************************************/
+
+#define FUNC_TRACE() APPL_TRACE_DEBUG1("%s", __FUNCTION__);
+
+/* Macro to retrieve the number of elements in a statically allocated array */
+#define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a)/sizeof((__a)[0]))
+
+/* MIN and MAX macros */
+#define BTA_AV_CO_MIN(X,Y) ((X) < (Y) ? (X) : (Y))
+#define BTA_AV_CO_MAX(X,Y) ((X) > (Y) ? (X) : (Y))
+
+/* Macro to convert audio handle to index and vice versa */
+#define BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl) (((hndl) & (~BTA_AV_CHNL_MSK)) - 1)
+#define BTA_AV_CO_AUDIO_INDX_TO_HNDL(indx) (((indx) + 1) | BTA_AV_CHNL_AUDIO)
+
+
+/* Offsets to access codec information in SBC codec */
+#define BTA_AV_CO_SBC_FREQ_CHAN_OFF 3
+#define BTA_AV_CO_SBC_BLOCK_BAND_OFF 4
+#define BTA_AV_CO_SBC_MIN_BITPOOL_OFF 5
+#define BTA_AV_CO_SBC_MAX_BITPOOL_OFF 6
+
+#define BTA_AV_CO_SBC_MAX_BITPOOL 53
+
+/* SCMS-T protect info */
+const UINT8 bta_av_co_cp_scmst[BTA_AV_CP_INFO_LEN] = "\x02\x02\x00";
+
+/* SBC codec capabilities */
+const tA2D_SBC_CIE bta_av_co_sbc_caps =
+{
+ (A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */
+ (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */
+ (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */
+ (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */
+ (A2D_SBC_IE_ALLOC_MD_L | A2D_SBC_IE_ALLOC_MD_S), /* alloc_mthd */
+ BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */
+ A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */
+};
+
+#if !defined(BTIF_AV_SBC_DEFAULT_SAMP_FREQ)
+#define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_44
+#endif
+
+/* Default SBC codec configuration */
+const tA2D_SBC_CIE btif_av_sbc_default_config =
+{
+ BTIF_AV_SBC_DEFAULT_SAMP_FREQ, /* samp_freq */
+ A2D_SBC_IE_CH_MD_JOINT, /* ch_mode */
+ A2D_SBC_IE_BLOCKS_16, /* block_len */
+ A2D_SBC_IE_SUBBAND_8, /* num_subbands */
+ A2D_SBC_IE_ALLOC_MD_L, /* alloc_mthd */
+ BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */
+ A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */
+};
+
+
+/*****************************************************************************
+** Local data
+*****************************************************************************/
+typedef struct
+{
+ UINT8 sep_info_idx; /* local SEP index (in BTA tables) */
+ UINT8 seid; /* peer SEP index (in peer tables) */
+ UINT8 codec_type; /* peer SEP codec type */
+ UINT8 codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */
+ UINT8 num_protect; /* peer SEP number of CP elements */
+ UINT8 protect_info[BTA_AV_CP_INFO_LEN]; /* peer SEP content protection info */
+} tBTA_AV_CO_SINK;
+
+typedef struct
+{
+ BD_ADDR addr; /* address of audio/video peer */
+ tBTA_AV_CO_SINK snks[BTIF_SV_AV_AA_SEP_INDEX]; /* array of supported sinks */
+ UINT8 num_snks; /* total number of sinks at peer */
+ UINT8 num_seps; /* total number of seids at peer */
+ UINT8 num_rx_snks; /* number of received sinks */
+ UINT8 num_sup_snks; /* number of supported sinks in the snks array */
+ tBTA_AV_CO_SINK *p_snk; /* currently selected sink */
+ UINT8 codec_cfg[AVDT_CODEC_SIZE]; /* current codec configuration */
+ BOOLEAN cp_active; /* current CP configuration */
+ BOOLEAN acp; /* acceptor */
+ BOOLEAN recfg_needed; /* reconfiguration is needed */
+ BOOLEAN opened; /* opened */
+ UINT16 mtu; /* maximum transmit unit size */
+} tBTA_AV_CO_PEER;
+
+typedef struct
+{
+ BOOLEAN active;
+ UINT8 flag;
+} tBTA_AV_CO_CP;
+
+typedef struct
+{
+ /* Connected peer information */
+ tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS];
+ /* Current codec configuration - access to this variable must be protected */
+ tBTIF_AV_CODEC_INFO codec_cfg;
+ tBTIF_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */
+
+ tBTA_AV_CO_CP cp;
+} tBTA_AV_CO_CB;
+
+/* Control block instance */
+static tBTA_AV_CO_CB bta_av_co_cb;
+
+static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg);
+static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer);
+static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo);
+static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink);
+static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index);
+static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg);
+
+
+
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_is_active
+ **
+ ** Description Get the current configuration of content protection
+ **
+ ** Returns TRUE if the current streaming has CP, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_cp_is_active(void)
+{
+ FUNC_TRACE();
+ return bta_av_co_cb.cp.active;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_get_flag
+ **
+ ** Description Get content protection flag
+ ** BTA_AV_CP_SCMS_COPY_NEVER
+ ** BTA_AV_CP_SCMS_COPY_ONCE
+ ** BTA_AV_CP_SCMS_COPY_FREE
+ **
+ ** Returns The current flag value
+ **
+ *******************************************************************************/
+UINT8 bta_av_co_cp_get_flag(void)
+{
+ FUNC_TRACE();
+ return bta_av_co_cb.cp.flag;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_set_flag
+ **
+ ** Description Set content protection flag
+ ** BTA_AV_CP_SCMS_COPY_NEVER
+ ** BTA_AV_CP_SCMS_COPY_ONCE
+ ** BTA_AV_CP_SCMS_COPY_FREE
+ **
+ ** Returns TRUE if setting the SCMS flag is supported else FALSE
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag)
+{
+ FUNC_TRACE();
+
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+#else
+ if (cp_flag != BTA_AV_CP_SCMS_COPY_FREE)
+ {
+ return FALSE;
+ }
+#endif
+ bta_av_co_cb.cp.flag = cp_flag;
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_get_peer
+ **
+ ** Description find the peer entry for a given handle
+ **
+ ** Returns the control block
+ **
+ *******************************************************************************/
+static tBTA_AV_CO_PEER *bta_av_co_get_peer(tBTA_AV_HNDL hndl)
+{
+ UINT8 index;
+ FUNC_TRACE();
+
+ index = BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl);
+
+ /* Sanity check */
+ if (index >= BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers))
+ {
+ APPL_TRACE_ERROR1("bta_av_co_get_peer peer index out of bounds:%d", index);
+ return NULL;
+ }
+
+ return &bta_av_co_cb.peers[index];
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_init
+ **
+ ** Description This callout function is executed by AV when it is
+ ** started by calling BTA_AvRegister(). This function can be
+ ** used by the phone to initialize audio paths or for other
+ ** initialization purposes.
+ **
+ **
+ ** Returns Stream codec and content protection capabilities info.
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_num_protect,
+ UINT8 *p_protect_info, UINT8 index)
+{
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG1("bta_av_co_audio_init: %d", index);
+
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ {
+ UINT8 *p = p_protect_info;
+
+ /* Content protection info - support SCMS-T */
+ *p_num_protect = 1;
+ *p++ = BTA_AV_CP_LOSC;
+ UINT16_TO_STREAM(p, BTA_AV_CP_SCMS_T_ID);
+
+ }
+#else
+ /* By default - no content protection info */
+ *p_num_protect = 0;
+ *p_protect_info = 0;
+#endif
+
+ /* reset remote preference through setconfig */
+ bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE;
+
+ switch (index)
+ {
+ case BTIF_SV_AV_AA_SBC_INDEX:
+ /* Set up for SBC codec */
+ *p_codec_type = BTA_AV_CODEC_SBC;
+
+ /* This should not fail because we are using constants for parameters */
+ A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_caps, p_codec_info);
+
+ /* Codec is valid */
+ return TRUE;
+
+
+ default:
+ /* Not valid */
+ return FALSE;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_disc_res
+ **
+ ** Description This callout function is executed by AV to report the
+ ** number of stream end points (SEP) were found during the
+ ** AVDT stream discovery process.
+ **
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+BTA_API void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk,
+ BD_ADDR addr)
+{
+ tBTA_AV_CO_PEER *p_peer;
+
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG3("bta_av_co_audio_disc_res h:x%x num_seps:%d num_snk:%d",
+ hndl, num_seps, num_snk);
+
+ /* Find the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_disc_res could not find peer entry");
+ return;
+ }
+
+ /* Sanity check : this should never happen */
+ if (p_peer->opened)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_disc_res peer already opened");
+ }
+
+ /* Copy the discovery results */
+ bdcpy(p_peer->addr, addr);
+ p_peer->num_snks = num_snk;
+ p_peer->num_seps = num_seps;
+ p_peer->num_rx_snks = 0;
+ p_peer->num_sup_snks = 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_getconfig
+ **
+ ** Description This callout function is executed by AV to retrieve the
+ ** desired codec and content protection configuration for the
+ ** audio stream.
+ **
+ **
+ ** Returns Stream codec and content protection configuration info.
+ **
+ *******************************************************************************/
+BTA_API UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect,
+ UINT8 *p_protect_info)
+
+{
+ UINT8 result = A2D_FAIL;
+ BOOLEAN supported;
+ tBTA_AV_CO_PEER *p_peer;
+ tBTA_AV_CO_SINK *p_sink;
+ UINT8 codec_cfg[AVDT_CODEC_SIZE];
+ UINT8 index;
+
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG3("bta_av_co_audio_getconfig handle:0x%x codec_type:%d seid:%d", hndl, codec_type, seid);
+ APPL_TRACE_DEBUG4("num_protect:0x%02x protect_info:0x%02x%02x%02x",
+ *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_getconfig could not find peer entry");
+ return A2D_FAIL;
+ }
+
+ APPL_TRACE_DEBUG4("bta_av_co_audio_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)",
+ p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks);
+
+ /* Increment the number of received sinks capabilities */
+ p_peer->num_rx_snks++;
+
+ /* Check if this is a supported configuration */
+ supported = FALSE;
+ switch (codec_type)
+ {
+ case BTA_AV_CODEC_SBC:
+ supported = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ if (supported)
+ {
+ /* If there is room for a new one */
+ if (p_peer->num_sup_snks < BTA_AV_CO_NUM_ELEMENTS(p_peer->snks))
+ {
+ p_sink = &p_peer->snks[p_peer->num_sup_snks++];
+
+ APPL_TRACE_DEBUG6("bta_av_co_audio_getconfig saved caps[%x:%x:%x:%x:%x:%x]",
+ p_codec_info[1], p_codec_info[2], p_codec_info[3],
+ p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+
+ memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
+ p_sink->codec_type = codec_type;
+ p_sink->sep_info_idx = *p_sep_info_idx;
+ p_sink->seid = seid;
+ p_sink->num_protect = *p_num_protect;
+ memcpy(p_sink->protect_info, p_protect_info, BTA_AV_CP_INFO_LEN);
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_getconfig no more room for SNK info");
+ }
+ }
+
+ /* If last SNK get capabilities or all supported codec capa retrieved */
+ if ((p_peer->num_rx_snks == p_peer->num_snks) ||
+ (p_peer->num_sup_snks == BTA_AV_CO_NUM_ELEMENTS(p_peer->snks)))
+ {
+ APPL_TRACE_DEBUG0("bta_av_co_audio_getconfig last sink reached");
+
+ /* Protect access to bta_av_co_cb.codec_cfg */
+ GKI_disable();
+
+ /* Find a sink that matches the codec config */
+ if (bta_av_co_audio_peer_supports_codec(p_peer, &index))
+ {
+ /* stop fetching caps once we retrieved a supported codec */
+ if (p_peer->acp)
+ {
+ *p_sep_info_idx = p_peer->num_seps;
+ APPL_TRACE_EVENT0("no need to fetch more SEPs");
+ }
+
+ p_sink = &p_peer->snks[index];
+
+ /* Build the codec configuration for this sink */
+ if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg))
+ {
+ APPL_TRACE_DEBUG6("bta_av_co_audio_getconfig reconfig p_codec_info[%x:%x:%x:%x:%x:%x]",
+ codec_cfg[1], codec_cfg[2], codec_cfg[3],
+ codec_cfg[4], codec_cfg[5], codec_cfg[6]);
+
+ /* Save the new configuration */
+ p_peer->p_snk = p_sink;
+ memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE);
+
+ /* By default, no content protection */
+ *p_num_protect = 0;
+
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* Check if this sink supports SCMS */
+ if (bta_av_co_audio_sink_has_scmst(p_sink))
+ {
+ p_peer->cp_active = TRUE;
+ bta_av_co_cb.cp.active = TRUE;
+ *p_num_protect = BTA_AV_CP_INFO_LEN;
+ memcpy(p_protect_info, bta_av_co_cp_scmst, BTA_AV_CP_INFO_LEN);
+ }
+ else
+ {
+ p_peer->cp_active = FALSE;
+ bta_av_co_cb.cp.active = FALSE;
+ }
+#endif
+
+ /* If acceptor -> reconfig otherwise reply for configuration */
+ if (p_peer->acp)
+ {
+ if (p_peer->recfg_needed)
+ {
+ APPL_TRACE_DEBUG1("bta_av_co_audio_getconfig call BTA_AvReconfig(x%x)", hndl);
+ BTA_AvReconfig(hndl, TRUE, p_sink->sep_info_idx, p_peer->codec_cfg, *p_num_protect, (UINT8 *)bta_av_co_cp_scmst);
+ }
+ }
+ else
+ {
+ *p_sep_info_idx = p_sink->sep_info_idx;
+ memcpy(p_codec_info, p_peer->codec_cfg, AVDT_CODEC_SIZE);
+ }
+ result = A2D_SUCCESS;
+ }
+ }
+ /* Protect access to bta_av_co_cb.codec_cfg */
+ GKI_enable();
+ }
+ return result;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_setconfig
+ **
+ ** Description This callout function is executed by AV to set the codec and
+ ** content protection configuration of the audio stream.
+ **
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+BTA_API void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, UINT8 num_protect, UINT8 *p_protect_info)
+
+{
+ tBTA_AV_CO_PEER *p_peer;
+ UINT8 status = A2D_SUCCESS;
+ UINT8 category = A2D_SUCCESS;
+ BOOLEAN recfg_needed = FALSE;
+
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG6("bta_av_co_audio_setconfig p_codec_info[%x:%x:%x:%x:%x:%x]",
+ p_codec_info[1], p_codec_info[2], p_codec_info[3],
+ p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+ APPL_TRACE_DEBUG4("num_protect:0x%02x protect_info:0x%02x%02x%02x",
+ num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_setconfig could not find peer entry");
+
+ /* Call call-in rejecting the configuration */
+ bta_av_ci_setconfig(hndl, A2D_BUSY, AVDT_ASC_CODEC, 0, NULL, FALSE);
+ return;
+ }
+
+ /* Sanity check: should not be opened at this point */
+ if (p_peer->opened)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_setconfig peer already in use");
+ }
+
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (num_protect != 0)
+ {
+ /* If CP is supported */
+ if ((num_protect != 1) ||
+ (bta_av_co_cp_is_scmst(p_protect_info) == FALSE))
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_setconfig wrong CP configuration");
+ status = A2D_BAD_CP_TYPE;
+ category = AVDT_ASC_PROTECT;
+ }
+ }
+#else
+ /* Do not support content protection for the time being */
+ if (num_protect != 0)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_setconfig wrong CP configuration");
+ status = A2D_BAD_CP_TYPE;
+ category = AVDT_ASC_PROTECT;
+ }
+#endif
+ if (status == A2D_SUCCESS)
+ {
+ /* Check if codec configuration is supported */
+ if (bta_av_co_audio_media_supports_config(codec_type, p_codec_info))
+ {
+ /* Protect access to bta_av_co_cb.codec_cfg */
+ GKI_disable();
+
+ /* Check if the configuration matches the current codec config */
+ switch (bta_av_co_cb.codec_cfg.id)
+ {
+ case BTIF_AV_CODEC_SBC:
+ if ((codec_type != BTA_AV_CODEC_SBC) || memcmp(p_codec_info, bta_av_co_cb.codec_cfg.info, 5))
+ {
+ recfg_needed = TRUE;
+ }
+ else if ((num_protect == 1) && (!bta_av_co_cb.cp.active))
+ {
+ recfg_needed = TRUE;
+ }
+
+ /* if remote side requests a restricted notify sinks preferred bitpool range as all other params are
+ already checked for validify */
+ APPL_TRACE_EVENT2("remote peer setconfig bitpool range [%d:%d]",
+ p_codec_info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
+ p_codec_info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] );
+
+ bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_SBC;
+ memcpy(bta_av_co_cb.codec_cfg_setconfig.info, p_codec_info, AVDT_CODEC_SIZE);
+ break;
+
+
+ default:
+ APPL_TRACE_ERROR1("bta_av_co_audio_setconfig unsupported cid %d", bta_av_co_cb.codec_cfg.id);
+ recfg_needed = TRUE;
+ break;
+ }
+ /* Protect access to bta_av_co_cb.codec_cfg */
+ GKI_enable();
+ }
+ else
+ {
+ category = AVDT_ASC_CODEC;
+ status = A2D_WRONG_CODEC;
+ }
+ }
+
+ if (status != A2D_SUCCESS)
+ {
+ APPL_TRACE_DEBUG2("bta_av_co_audio_setconfig reject s=%d c=%d", status, category);
+
+ /* Call call-in rejecting the configuration */
+ bta_av_ci_setconfig(hndl, status, category, 0, NULL, FALSE);
+ }
+ else
+ {
+ /* Mark that this is an acceptor peer */
+ p_peer->acp = TRUE;
+ p_peer->recfg_needed = recfg_needed;
+
+ APPL_TRACE_DEBUG1("bta_av_co_audio_setconfig accept reconf=%d", recfg_needed);
+
+ /* Call call-in accepting the configuration */
+ bta_av_ci_setconfig(hndl, A2D_SUCCESS, A2D_SUCCESS, 0, NULL, recfg_needed);
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_open
+ **
+ ** Description This function is called by AV when the audio stream connection
+ ** is opened.
+ **
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+BTA_API void bta_av_co_audio_open(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info,
+ UINT16 mtu)
+{
+ tBTA_AV_CO_PEER *p_peer;
+
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG2("bta_av_co_audio_open mtu:%d codec_type:%d", mtu, codec_type);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_setconfig could not find peer entry");
+ }
+ else
+ {
+ p_peer->opened = TRUE;
+ p_peer->mtu = mtu;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_close
+ **
+ ** Description This function is called by AV when the audio stream connection
+ ** is closed.
+ **
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+BTA_API void bta_av_co_audio_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu)
+
+{
+ tBTA_AV_CO_PEER *p_peer;
+
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG0("bta_av_co_audio_close");
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer)
+ {
+ /* Mark the peer closed and clean the peer info */
+ memset(p_peer, 0, sizeof(*p_peer));
+ }
+ else
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_close could not find peer entry");
+ }
+
+ /* reset remote preference through setconfig */
+ bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_start
+ **
+ ** Description This function is called by AV when the audio streaming data
+ ** transfer is started.
+ **
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+BTA_API void bta_av_co_audio_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type,
+ UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr)
+{
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG0("bta_av_co_audio_start");
+
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_stop
+ **
+ ** Description This function is called by AV when the audio streaming data
+ ** transfer is stopped.
+ **
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+BTA_API extern void bta_av_co_audio_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type)
+{
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG0("bta_av_co_audio_stop");
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_src_data_path
+ **
+ ** Description This function is called to manage data transfer from
+ ** the audio codec to AVDTP.
+ **
+ ** Returns Pointer to the GKI buffer to send, NULL if no buffer to send
+ **
+ *******************************************************************************/
+BTA_API void * bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type, UINT32 *p_len,
+ UINT32 *p_timestamp)
+{
+ BT_HDR *p_buf;
+ FUNC_TRACE();
+
+ p_buf = btif_media_aa_readbuf();
+ if (p_buf != NULL)
+ {
+ switch (codec_type)
+ {
+ case BTA_AV_CODEC_SBC:
+ /* In media packet SBC, the following information is available:
+ * p_buf->layer_specific : number of SBC frames in the packet
+ * p_buf->word[0] : timestamp
+ */
+ /* Retrieve the timestamp information from the media packet */
+ *p_timestamp = *((UINT32 *) (p_buf + 1));
+
+ /* Set up packet header */
+ bta_av_sbc_bld_hdr(p_buf, p_buf->layer_specific);
+ break;
+
+
+ default:
+ APPL_TRACE_ERROR1("bta_av_co_audio_src_data_path Unsupported codec type (%d)", codec_type);
+ break;
+ }
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ {
+ UINT8 *p;
+ if (bta_av_co_cp_is_active())
+ {
+ p_buf->len++;
+ p_buf->offset--;
+ p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ *p = bta_av_co_cp_get_flag();
+ }
+ }
+#endif
+ }
+ return p_buf;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_drop
+ **
+ ** Description An Audio packet is dropped. .
+ ** It's very likely that the connected headset with this handle
+ ** is moved far away. The implementation may want to reduce
+ ** the encoder bit rate setting to reduce the packet size.
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_drop(tBTA_AV_HNDL hndl)
+{
+ FUNC_TRACE();
+
+ APPL_TRACE_ERROR1("bta_av_co_audio_drop dropped: x%x", hndl);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_delay
+ **
+ ** Description This function is called by AV when the audio stream connection
+ ** needs to send the initial delay report to the connected SRC.
+ **
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, UINT16 delay)
+{
+ FUNC_TRACE();
+
+ APPL_TRACE_ERROR2("bta_av_co_audio_delay handle: x%x, delay:0x%x", hndl, delay);
+}
+
+
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_codec_build_config
+ **
+ ** Description Build the codec configuration
+ **
+ ** Returns TRUE if the codec was built successfully, FALSE otherwise
+ **
+ *******************************************************************************/
+static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg)
+{
+ FUNC_TRACE();
+
+ memset(p_codec_cfg, 0, AVDT_CODEC_SIZE);
+
+ switch (bta_av_co_cb.codec_cfg.id)
+ {
+ case BTIF_AV_CODEC_SBC:
+ /* only copy the relevant portions for this codec to avoid issues when
+ comparing codec configs covering larger codec sets than SBC (7 bytes) */
+ memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg.info, BTA_AV_CO_SBC_MAX_BITPOOL_OFF+1);
+
+ /* Update the bit pool boundaries with the codec capabilities */
+ p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF];
+ p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF];
+
+ APPL_TRACE_EVENT2("bta_av_co_audio_codec_build_config : bitpool min %d, max %d",
+ p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
+ p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]);
+ break;
+ default:
+ APPL_TRACE_ERROR1("bta_av_co_audio_codec_build_config: unsupported codec id %d", bta_av_co_cb.codec_cfg.id);
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_codec_cfg_matches_caps
+ **
+ ** Description Check if a codec config matches a codec capabilities
+ **
+ ** Returns TRUE if it codec config is supported, FALSE otherwise
+ **
+ *******************************************************************************/
+static BOOLEAN bta_av_co_audio_codec_cfg_matches_caps(UINT8 codec_id, const UINT8 *p_codec_caps, const UINT8 *p_codec_cfg)
+{
+ FUNC_TRACE();
+
+ switch(codec_id)
+ {
+ case BTIF_AV_CODEC_SBC:
+
+ APPL_TRACE_EVENT4("bta_av_co_audio_codec_cfg_matches_caps : min %d/%d max %d/%d",
+ p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
+ p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
+ p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF],
+ p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]);
+
+ /* Must match all items exactly except bitpool boundaries which can be adjusted */
+ if (!((p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF] & p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF]) &&
+ (p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF] & p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF])))
+ {
+ APPL_TRACE_EVENT4("FALSE %x %x %x %x",
+ p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF],
+ p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF],
+ p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF],
+ p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]);
+ return FALSE;
+ }
+ break;
+
+
+ default:
+ APPL_TRACE_ERROR1("bta_av_co_audio_codec_cfg_matches_caps: unsupported codec id %d", codec_id);
+ return FALSE;
+ break;
+ }
+ APPL_TRACE_EVENT0("TRUE");
+
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_codec_match
+ **
+ ** Description Check if a codec capabilities supports the codec config
+ **
+ ** Returns TRUE if the connection supports this codec, FALSE otherwise
+ **
+ *******************************************************************************/
+static BOOLEAN bta_av_co_audio_codec_match(const UINT8 *p_codec_caps)
+{
+ FUNC_TRACE();
+
+ return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg.id, p_codec_caps, bta_av_co_cb.codec_cfg.info);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_peer_reset_config
+ **
+ ** Description Reset the peer codec configuration
+ **
+ ** Returns Nothing
+ **
+ *******************************************************************************/
+static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer)
+{
+ FUNC_TRACE();
+
+ /* Indicate that there is no currently selected sink */
+ p_peer->p_snk = NULL;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_is_scmst
+ **
+ ** Description Check if a content protection service is SCMS-T
+ **
+ ** Returns TRUE if this CP is SCMS-T, FALSE otherwise
+ **
+ *******************************************************************************/
+static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo)
+{
+ UINT16 cp_id;
+ FUNC_TRACE();
+
+ if (*p_protectinfo >= BTA_AV_CP_LOSC)
+ {
+ p_protectinfo++;
+ STREAM_TO_UINT16(cp_id, p_protectinfo);
+ if (cp_id == BTA_AV_CP_SCMS_T_ID)
+ {
+ APPL_TRACE_DEBUG0("bta_av_co_cp_is_scmst: SCMS-T found");
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_sink_has_scmst
+ **
+ ** Description Check if a sink supports SCMS-T
+ **
+ ** Returns TRUE if the sink supports this CP, FALSE otherwise
+ **
+ *******************************************************************************/
+static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink)
+{
+ UINT8 index;
+ const UINT8 *p;
+ FUNC_TRACE();
+
+ /* Check if sink supports SCMS-T */
+ index = p_sink->num_protect;
+ p = &p_sink->protect_info[0];
+
+ while (index)
+ {
+ if (bta_av_co_cp_is_scmst(p))
+ {
+ return TRUE;
+ }
+ /* Move to the next SC */
+ p += *p + 1;
+ /* Decrement the SC counter */
+ index--;
+ }
+ APPL_TRACE_DEBUG0("bta_av_co_audio_sink_has_scmst: SCMS-T not found");
+ return FALSE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_sink_supports_cp
+ **
+ ** Description Check if a sink supports the current content protection
+ **
+ ** Returns TRUE if the sink supports this CP, FALSE otherwise
+ **
+ *******************************************************************************/
+static BOOLEAN bta_av_co_audio_sink_supports_cp(const tBTA_AV_CO_SINK *p_sink)
+{
+ FUNC_TRACE();
+
+ /* Check if content protection is enabled for this stream */
+ if (bta_av_co_cp_get_flag() != BTA_AV_CP_SCMS_COPY_FREE)
+ {
+ return bta_av_co_audio_sink_has_scmst(p_sink);
+ }
+ else
+ {
+ APPL_TRACE_DEBUG0("bta_av_co_audio_sink_supports_cp: not required");
+ return TRUE;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_peer_supports_codec
+ **
+ ** Description Check if a connection supports the codec config
+ **
+ ** Returns TRUE if the connection supports this codec, FALSE otherwise
+ **
+ *******************************************************************************/
+static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index)
+{
+ int index;
+ UINT8 codec_type;
+ FUNC_TRACE();
+
+ /* Configure the codec type to look for */
+ codec_type = bta_av_co_cb.codec_cfg.id;
+
+
+ for (index = 0; index < p_peer->num_sup_snks; index++)
+ {
+ if (p_peer->snks[index].codec_type == codec_type)
+ {
+ switch (bta_av_co_cb.codec_cfg.id)
+ {
+ case BTIF_AV_CODEC_SBC:
+ if (p_snk_index) *p_snk_index = index;
+ return bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps);
+ break;
+
+
+ default:
+ APPL_TRACE_ERROR1("bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg.id);
+ return FALSE;
+ break;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_media_supports_config
+ **
+ ** Description Check if the media source supports a given configuration
+ **
+ ** Returns TRUE if the media source supports this config, FALSE otherwise
+ **
+ *******************************************************************************/
+static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg)
+{
+ FUNC_TRACE();
+
+ switch (codec_type)
+ {
+ case BTA_AV_CODEC_SBC:
+ if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_caps))
+ {
+ return FALSE;
+ }
+ break;
+
+
+ default:
+ APPL_TRACE_ERROR1("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type);
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_codec_supported
+ **
+ ** Description Check if all opened connections are compatible with a codec
+ ** configuration and content protection
+ **
+ ** Returns TRUE if all opened devices support this codec, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_codec_supported(tBTIF_STATUS *p_status)
+{
+ UINT8 index;
+ UINT8 snk_index;
+ tBTA_AV_CO_PEER *p_peer;
+ tBTA_AV_CO_SINK *p_sink;
+ UINT8 codec_cfg[AVDT_CODEC_SIZE];
+ UINT8 num_protect = 0;
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ BOOLEAN cp_active;
+#endif
+
+ FUNC_TRACE();
+
+ APPL_TRACE_DEBUG0("bta_av_co_audio_codec_supported");
+
+ /* Check AV feeding is supported */
+ *p_status = BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED;
+
+ for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++)
+ {
+ p_peer = &bta_av_co_cb.peers[index];
+ if (p_peer->opened)
+ {
+ if (bta_av_co_audio_peer_supports_codec(p_peer, &snk_index))
+ {
+ p_sink = &p_peer->snks[snk_index];
+
+ /* Check that this sink is compatible with the CP */
+ if (!bta_av_co_audio_sink_supports_cp(p_sink))
+ {
+ APPL_TRACE_DEBUG2("bta_av_co_audio_codec_supported sink %d of peer %d doesn't support cp",
+ snk_index, index);
+ *p_status = BTIF_ERROR_SRV_AV_CP_NOT_SUPPORTED;
+ return FALSE;
+ }
+
+ /* Build the codec configuration for this sink */
+ if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg))
+ {
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* Check if this sink supports SCMS */
+ cp_active = bta_av_co_audio_sink_has_scmst(p_sink);
+#endif
+ /* Check if this is a new configuration (new sink or new config) */
+ if ((p_sink != p_peer->p_snk) ||
+ (memcmp(codec_cfg, p_peer->codec_cfg, AVDT_CODEC_SIZE))
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ || (p_peer->cp_active != cp_active)
+#endif
+ )
+ {
+ /* Save the new configuration */
+ p_peer->p_snk = p_sink;
+ memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE);
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ p_peer->cp_active = cp_active;
+ if (p_peer->cp_active)
+ {
+ bta_av_co_cb.cp.active = TRUE;
+ num_protect = BTA_AV_CP_INFO_LEN;
+ }
+ else
+ {
+ bta_av_co_cb.cp.active = FALSE;
+ }
+#endif
+ APPL_TRACE_DEBUG1("bta_av_co_audio_codec_supported call BTA_AvReconfig(x%x)", BTA_AV_CO_AUDIO_INDX_TO_HNDL(index));
+ BTA_AvReconfig(BTA_AV_CO_AUDIO_INDX_TO_HNDL(index), TRUE, p_sink->sep_info_idx,
+ p_peer->codec_cfg, num_protect, (UINT8 *)bta_av_co_cp_scmst);
+ }
+ }
+ }
+ else
+ {
+ APPL_TRACE_DEBUG1("bta_av_co_audio_codec_supported index %d doesn't support codec", index);
+ return FALSE;
+ }
+ }
+ }
+
+ *p_status = BTIF_SUCCESS;
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_codec_reset
+ **
+ ** Description Reset the current codec configuration
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_codec_reset(void)
+{
+ GKI_disable();
+ FUNC_TRACE();
+
+ /* Reset the current configuration to SBC */
+ bta_av_co_cb.codec_cfg.id = BTIF_AV_CODEC_SBC;
+
+ if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btif_av_sbc_default_config, bta_av_co_cb.codec_cfg.info) != A2D_SUCCESS)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed");
+ }
+
+ GKI_enable();
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_set_codec
+ **
+ ** Description Set the current codec configuration from the feeding type.
+ ** This function is starting to modify the configuration, it
+ ** should be protected.
+ **
+ ** Returns TRUE if successful, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_set_codec(const tBTIF_AV_MEDIA_FEEDINGS *p_feeding, tBTIF_STATUS *p_status)
+{
+ tA2D_SBC_CIE sbc_config;
+ tBTIF_AV_CODEC_INFO new_cfg;
+
+ FUNC_TRACE();
+
+ /* Check AV feeding is supported */
+ *p_status = BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED;
+
+ APPL_TRACE_DEBUG1("bta_av_co_audio_set_codec cid=%d", p_feeding->format);
+
+ /* Supported codecs */
+ switch (p_feeding->format)
+ {
+ case BTIF_AV_CODEC_PCM:
+ new_cfg.id = BTIF_AV_CODEC_SBC;
+
+ sbc_config = btif_av_sbc_default_config;
+ if ((p_feeding->cfg.pcm.num_channel != 1) &&
+ (p_feeding->cfg.pcm.num_channel != 2))
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_set_codec PCM channel number unsupported");
+ return FALSE;
+ }
+ if ((p_feeding->cfg.pcm.bit_per_sample != 8) &&
+ (p_feeding->cfg.pcm.bit_per_sample != 16))
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_set_codec PCM sample size unsupported");
+ return FALSE;
+ }
+ switch (p_feeding->cfg.pcm.sampling_freq)
+ {
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_48;
+ break;
+
+ case 11025:
+ case 22050:
+ case 44100:
+ sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_44;
+ break;
+ default:
+ APPL_TRACE_ERROR0("bta_av_co_audio_set_codec PCM sampling frequency unsupported");
+ return FALSE;
+ break;
+ }
+ /* Build the codec config */
+ if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, &sbc_config, new_cfg.info) != A2D_SUCCESS)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_set_codec A2D_BldSbcInfo failed");
+ return FALSE;
+ }
+ break;
+
+
+ default:
+ APPL_TRACE_ERROR0("bta_av_co_audio_set_codec Feeding format unsupported");
+ return FALSE;
+ break;
+ }
+
+ /* The new config was correctly built */
+ bta_av_co_cb.codec_cfg = new_cfg;
+
+
+ /* Check all devices support it */
+ *p_status = BTIF_SUCCESS;
+ return bta_av_co_audio_codec_supported(p_status);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_get_sbc_config
+ **
+ ** Description Retrieves the SBC codec configuration. If the codec in use
+ ** is not SBC, return the default SBC codec configuration.
+ **
+ ** Returns TRUE if codec is SBC, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_get_sbc_config(tA2D_SBC_CIE *p_sbc_config, UINT16 *p_minmtu)
+{
+ BOOLEAN result = FALSE;
+ UINT8 index, jndex;
+ tBTA_AV_CO_PEER *p_peer;
+ tBTA_AV_CO_SINK *p_sink;
+
+ APPL_TRACE_EVENT1("bta_av_co_cb.codec_cfg.id : codec 0x%x", bta_av_co_cb.codec_cfg.id);
+
+ /* Minimum MTU is by default very large */
+ *p_minmtu = 0xFFFF;
+
+ GKI_disable();
+ if (bta_av_co_cb.codec_cfg.id == BTIF_AV_CODEC_SBC)
+ {
+ if (A2D_ParsSbcInfo(p_sbc_config, bta_av_co_cb.codec_cfg.info, FALSE) == A2D_SUCCESS)
+ {
+ for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++)
+ {
+ p_peer = &bta_av_co_cb.peers[index];
+ if (p_peer->opened)
+ {
+ if (p_peer->mtu < *p_minmtu)
+ {
+ *p_minmtu = p_peer->mtu;
+ }
+ for (jndex = 0; jndex < p_peer->num_sup_snks; jndex++)
+ {
+ p_sink = &p_peer->snks[jndex];
+ if (p_sink->codec_type == A2D_MEDIA_CT_SBC)
+ {
+ /* Update the bitpool boundaries of the current config */
+ p_sbc_config->min_bitpool =
+ BTA_AV_CO_MAX(p_sink->codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF],
+ p_sbc_config->min_bitpool);
+ p_sbc_config->max_bitpool =
+ BTA_AV_CO_MIN(p_sink->codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF],
+ p_sbc_config->max_bitpool);
+ APPL_TRACE_EVENT2("bta_av_co_audio_get_sbc_config : sink bitpool min %d, max %d",
+ p_sbc_config->min_bitpool, p_sbc_config->max_bitpool);
+ break;
+ }
+ }
+ }
+ }
+ result = TRUE;
+ }
+ }
+
+ if (!result)
+ {
+ /* Not SBC, still return the default values */
+ *p_sbc_config = btif_av_sbc_default_config;
+ }
+ GKI_enable();
+
+ return result;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_discard_config
+ **
+ ** Description Discard the codec configuration of a connection
+ **
+ ** Returns Nothing
+ **
+ *******************************************************************************/
+void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl)
+{
+ tBTA_AV_CO_PEER *p_peer;
+
+ FUNC_TRACE();
+
+ /* Find the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_audio_discard_config could not find peer entry");
+ return;
+ }
+
+ /* Reset the peer codec configuration */
+ bta_av_co_audio_peer_reset_config(p_peer);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_init
+ **
+ ** Description Initialization
+ **
+ ** Returns Nothing
+ **
+ *******************************************************************************/
+void bta_av_co_init(void)
+{
+ FUNC_TRACE();
+
+ /* Reset the control block */
+ memset(&bta_av_co_cb, 0, sizeof(bta_av_co_cb));
+
+ bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE;
+
+#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE)
+ bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_NEVER);
+#else
+ bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_FREE);
+#endif
+
+ /* Reset the current config */
+ bta_av_co_audio_codec_reset();
+}
+
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_peer_cp_supported
+ **
+ ** Description Checks if the peer supports CP
+ **
+ ** Returns TRUE if the peer supports CP
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl)
+{
+ tBTA_AV_CO_PEER *p_peer;
+ tBTA_AV_CO_SINK *p_sink;
+ UINT8 index;
+
+ FUNC_TRACE();
+
+ /* Find the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL)
+ {
+ APPL_TRACE_ERROR0("bta_av_co_peer_cp_supported could not find peer entry");
+ return FALSE;
+ }
+
+ for (index = 0; index < p_peer->num_sup_snks; index++)
+ {
+ p_sink = &p_peer->snks[index];
+ if (p_sink->codec_type == A2D_MEDIA_CT_SBC)
+ {
+ return bta_av_co_audio_sink_has_scmst(p_sink);
+ }
+ }
+ APPL_TRACE_ERROR0("bta_av_co_peer_cp_supported did not find SBC sink");
+ return FALSE;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_get_remote_bitpool_pref
+ **
+ ** Description Check if remote side did a setconfig within the limits
+ ** of our exported bitpool range. If set we will set the
+ ** remote preference.
+ **
+ ** Returns TRUE if config set, FALSE otherwize
+ **
+ *******************************************************************************/
+
+BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max)
+{
+ /* check if remote peer did a set config */
+ if (bta_av_co_cb.codec_cfg_setconfig.id == BTIF_AV_CODEC_NONE)
+ return FALSE;
+
+ *min = bta_av_co_cb.codec_cfg_setconfig.info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF];
+ *max = bta_av_co_cb.codec_cfg_setconfig.info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF];
+
+ return TRUE;
+}
+
+
diff --git a/btif/co/bta_dm_co.c b/btif/co/bta_dm_co.c
new file mode 100644
index 0000000..611af2d
--- /dev/null
+++ b/btif/co/bta_dm_co.c
@@ -0,0 +1,417 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_dm_co.h"
+#include "bta_dm_ci.h"
+#if (BTM_OOB_INCLUDED == TRUE)
+#include "btif_dm.h"
+#endif
+/*******************************************************************************
+**
+** Function bta_dm_co_get_compress_memory
+**
+** Description This callout function is executed by DM to get memory for compression
+
+** Parameters id - BTA SYS ID
+** memory_p - memory return by callout
+** memory_size - memory size
+**
+** Returns TRUE for success, FALSE for fail.
+**
+*******************************************************************************/
+BOOLEAN bta_dm_co_get_compress_memory(tBTA_SYS_ID id, UINT8 **memory_p, UINT32 *memory_size)
+{
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_io_req
+**
+** Description This callout function is executed by DM to get IO capabilities
+** of the local device for the Simple Pairing process
+**
+** Parameters bd_addr - The peer device
+** *p_io_cap - The local Input/Output capabilities
+** *p_oob_data - TRUE, if OOB data is available for the peer device.
+** *p_auth_req - TRUE, if MITM protection is required.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, tBTA_OOB_DATA *p_oob_data,
+ tBTA_AUTH_REQ *p_auth_req, BOOLEAN is_orig)
+{
+#if (BTM_OOB_INCLUDED == TRUE)
+ btif_dm_set_oob_for_io_req(p_oob_data);
+#endif
+ BTIF_TRACE_DEBUG1("bta_dm_co_io_req *p_oob_data = %d", *p_oob_data);
+ BTIF_TRACE_DEBUG1("bta_dm_co_io_req *p_io_cap = %d", *p_io_cap);
+ BTIF_TRACE_DEBUG1("bta_dm_co_io_req *p_auth_req = %d", *p_auth_req);
+ BTIF_TRACE_DEBUG1("bta_dm_co_io_req is_orig = %d", is_orig);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_io_rsp
+**
+** Description This callout function is executed by DM to report IO capabilities
+** of the peer device for the Simple Pairing process
+**
+** Parameters bd_addr - The peer device
+** io_cap - The remote Input/Output capabilities
+** oob_data - TRUE, if OOB data is available for the peer device.
+** auth_req - TRUE, if MITM protection is required.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req)
+{
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_lk_upgrade
+**
+** Description This callout function is executed by DM to check if the
+** platform wants allow link key upgrade
+**
+** Parameters bd_addr - The peer device
+** *p_upgrade - TRUE, if link key upgrade is desired.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, BOOLEAN *p_upgrade )
+{
+}
+
+#if (BTM_OOB_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_co_loc_oob
+**
+** Description This callout function is executed by DM to report the OOB
+** data of the local device for the Simple Pairing process
+**
+** Parameters valid - TRUE, if the local OOB data is retrieved from LM
+** c - Simple Pairing Hash C
+** r - Simple Pairing Randomnizer R
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r)
+{
+ BTIF_TRACE_DEBUG1("bta_dm_co_loc_oob, valid = %d", valid);
+#ifdef BTIF_DM_OOB_TEST
+ btif_dm_proc_loc_oob(valid, c, r);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_rmt_oob
+**
+** Description This callout function is executed by DM to request the OOB
+** data for the remote device for the Simple Pairing process
+** Need to call bta_dm_ci_rmt_oob() in response
+**
+** Parameters bd_addr - The peer device
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_rmt_oob(BD_ADDR bd_addr)
+{
+ BT_OCTET16 p_c;
+ BT_OCTET16 p_r;
+ BOOLEAN result = FALSE;
+
+#ifdef BTIF_DM_OOB_TEST
+ result = btif_dm_proc_rmt_oob(bd_addr, p_c, p_r);
+#endif
+
+ BTIF_TRACE_DEBUG1("bta_dm_co_rmt_oob: result=%d",result);
+ bta_dm_ci_rmt_oob(result, bd_addr, p_c, p_r);
+}
+
+#endif /* BTM_OOB_INCLUDED */
+
+
+// REMOVE FOR BLUEDROID ?
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)
+
+/*******************************************************************************
+**
+** Function btui_sco_codec_callback
+**
+** Description Callback for btui codec.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void btui_sco_codec_callback(UINT16 event, UINT16 sco_handle)
+{
+ bta_dm_sco_ci_data_ready(event, sco_handle);
+}
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_init
+**
+** Description This function can be used by the phone to initialize audio
+** codec or for other initialization purposes before SCO connection
+** is opened.
+**
+**
+** Returns tBTA_DM_SCO_ROUTE_TYPE: SCO routing configuration type.
+**
+*******************************************************************************/
+tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw,
+ tBTA_CODEC_INFO * p_codec_type, UINT8 app_id)
+{
+ tBTM_SCO_ROUTE_TYPE route = BTA_DM_SCO_ROUTE_PCM;
+
+ BTIF_TRACE_DEBUG0("bta_dm_sco_co_init");
+
+ /* set up SCO routing configuration if SCO over HCI app ID is used and run time
+ configuration is set to SCO over HCI */
+ /* HS invoke this call-out */
+ if (
+#if (BTA_HS_INCLUDED == TRUE ) && (BTA_HS_INCLUDED == TRUE)
+ (app_id == BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.hs_sco_over_hci) ||
+#endif
+ /* AG invoke this call-out */
+ (app_id != BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.ag_sco_over_hci ))
+ {
+ route = btui_cb.sco_hci = BTA_DM_SCO_ROUTE_HCI;
+ }
+ /* no codec is is used for the SCO data */
+ if (p_codec_type->codec_type == BTA_SCO_CODEC_PCM && route == BTA_DM_SCO_ROUTE_HCI)
+ {
+ /* initialize SCO codec */
+ if (!btui_sco_codec_init(rx_bw, tx_bw))
+ {
+ BTIF_TRACE_ERROR0("codec initialization exception!");
+ }
+ }
+
+ return route;
+}
+
+
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_open
+**
+** Description This function is executed when a SCO connection is open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event)
+{
+ tBTUI_SCO_CODEC_CFG cfg;
+
+ if (btui_cb.sco_hci)
+ {
+ BTIF_TRACE_DEBUG2("bta_dm_sco_co_open handle:%d pkt_size:%d", handle, pkt_size);
+ /* use dedicated SCO buffer pool for SCO TX data */
+ cfg.pool_id = HCI_SCO_POOL_ID;
+ cfg.p_cback = btui_sco_codec_callback;
+ cfg.pkt_size = pkt_size;
+ cfg.cb_event = event;
+ /* open and start the codec */
+ btui_sco_codec_open(&cfg);
+ btui_sco_codec_start(handle);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_close
+**
+** Description This function is called when a SCO connection is closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_co_close(void)
+{
+ if (btui_cb.sco_hci)
+ {
+ BTIF_TRACE_DEBUG0("bta_dm_sco_co_close close codec");
+ /* close sco codec */
+ btui_sco_codec_close();
+
+ btui_cb.sco_hci = FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_in_data
+**
+** Description This function is called to send incoming SCO data to application.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_co_in_data(BT_HDR *p_buf)
+{
+ if (btui_cfg.sco_use_mic)
+ btui_sco_codec_inqdata (p_buf);
+ else
+ GKI_freebuf(p_buf);
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_sco_co_out_data
+**
+** Description This function is called to send SCO data over HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_dm_sco_co_out_data(BT_HDR **p_buf)
+{
+ btui_sco_codec_readbuf(p_buf);
+}
+
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)*/
+
+
+#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_dm_co_le_io_key_req
+**
+** Description This callout function is executed by DM to get BLE key information
+** before SMP pairing gets going.
+**
+** Parameters bd_addr - The peer device
+** *p_max_key_size - max key size local device supported.
+** *p_init_key - initiator keys.
+** *p_resp_key - responder keys.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_le_io_key_req(BD_ADDR bd_addr, UINT8 *p_max_key_size,
+ tBTA_LE_KEY_TYPE *p_init_key,
+ tBTA_LE_KEY_TYPE *p_resp_key )
+{
+ BTIF_TRACE_ERROR0("##################################");
+ BTIF_TRACE_ERROR0("bta_dm_co_le_io_key_req: only setting max size to 16");
+ BTIF_TRACE_ERROR0("##################################");
+ *p_max_key_size = 16;
+ *p_init_key = *p_resp_key =
+ (BTA_LE_KEY_PENC|BTA_LE_KEY_PID|BTA_LE_KEY_PCSRK|BTA_LE_KEY_LENC|BTA_LE_KEY_LID|BTA_LE_KEY_LCSRK);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_dm_co_ble_local_key_reload
+**
+** Description This callout function is to load the local BLE keys if available
+** on the device.
+**
+** Parameters none
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er,
+ tBTA_BLE_LOCAL_ID_KEYS *p_id_keys)
+{
+ BTIF_TRACE_ERROR0("##################################");
+ BTIF_TRACE_ERROR0("bta_dm_co_ble_load_local_keys: TBD Load local keys if any are persisted");
+ BTIF_TRACE_ERROR0("##################################");
+}
+
+/*******************************************************************************
+**
+** Function bta_dm_co_ble_io_req
+**
+** Description This callout function is executed by DM to get BLE IO capabilities
+** before SMP pairing gets going.
+**
+** Parameters bd_addr - The peer device
+** *p_io_cap - The local Input/Output capabilities
+** *p_oob_data - TRUE, if OOB data is available for the peer device.
+** *p_auth_req - Auth request setting (Bonding and MITM required or not)
+** *p_max_key_size - max key size local device supported.
+** *p_init_key - initiator keys.
+** *p_resp_key - responder keys.
+**
+** Returns void.
+**
+*******************************************************************************/
+void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap,
+ tBTA_OOB_DATA *p_oob_data,
+ tBTA_LE_AUTH_REQ *p_auth_req,
+ UINT8 *p_max_key_size,
+ tBTA_LE_KEY_TYPE *p_init_key,
+ tBTA_LE_KEY_TYPE *p_resp_key )
+{
+ /* if OOB is not supported, this call-out function does not need to do anything
+ * otherwise, look for the OOB data associated with the address and set *p_oob_data accordingly
+ * If the answer can not be obtained right away,
+ * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the answer is available */
+
+ /* *p_auth_req by default is FALSE for devices with NoInputNoOutput; TRUE for other devices. */
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_auth_req=%d ble_authereq=%d", *p_auth_req, bte_appl_cfg.ble_auth_req);
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_io_cap=%d ble_io_cap=%d", *p_io_cap, bte_appl_cfg.ble_io_cap);
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_init_key=%d ble_init_key=%d", *p_init_key, bte_appl_cfg.ble_init_key);
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_resp_key=%d ble_resp_key=%d", *p_resp_key, bte_appl_cfg.ble_resp_key );
+ BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_max_key_size=%d ble_max_key_size=%d", *p_max_key_size, bte_appl_cfg.ble_max_key_size );
+
+ *p_oob_data = FALSE;
+ if (bte_appl_cfg.ble_auth_req)
+ *p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04);
+
+ if (bte_appl_cfg.ble_io_cap <=4)
+ *p_io_cap = bte_appl_cfg.ble_io_cap;
+
+ if (bte_appl_cfg.ble_init_key<=7)
+ *p_init_key = bte_appl_cfg.ble_init_key;
+
+ if (bte_appl_cfg.ble_resp_key<=7)
+ *p_resp_key = bte_appl_cfg.ble_resp_key;
+
+ if (bte_appl_cfg.ble_max_key_size<=16)
+ *p_max_key_size = bte_appl_cfg.ble_max_key_size;
+
+}
+
+
+#endif
+
diff --git a/btif/co/bta_fs_co.c b/btif/co/bta_fs_co.c
new file mode 100644
index 0000000..ffc146b
--- /dev/null
+++ b/btif/co/bta_fs_co.c
@@ -0,0 +1,1181 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <time.h>
+#include <limits.h>
+#include "gki.h"
+#include "bta_fs_co.h"
+#include "bta_fs_ci.h"
+#include <inttypes.h>
+
+#ifndef AID_SYSTEM
+#define AID_SYSTEM 1000
+#define AID_BLUETOOTH 1002
+#define AID_SDCARD_RW 1015
+#define AID_MISC 9998
+#endif
+
+#define FAT_FS 0x4d44
+const unsigned short BT_UID= AID_BLUETOOTH;
+const unsigned short BT_GID= AID_BLUETOOTH;
+
+/* enable additional debugging traces that should be compiled out by default! */
+#ifndef BTA_FS_DEBUG
+#define BTA_FS_DEBUG TRUE
+#define LOG_TAG "BTA_FS_CO"
+#define LOGI(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__)
+#endif
+
+#if (defined BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+extern const tBTA_PBS_CFG bta_pbs_cfg;
+#endif
+
+
+
+static int del_path (const char *path)
+{
+ DIR *dir;
+ struct dirent *de;
+ int ret = 0;
+ char nameBuffer[PATH_MAX] = {0};
+ struct stat statBuffer;
+ BTIF_TRACE_DEBUG1("in del_path for path:%s", path);
+ dir = opendir(path);
+
+ if (dir == NULL) {
+ BTIF_TRACE_DEBUG1("opendir failed on path:%s", path);
+ return -1;
+ }
+
+ char *filenameOffset;
+
+ strncpy(nameBuffer, path, PATH_MAX - 1);
+ strcat(nameBuffer, "/");
+ int nameLen = strlen(nameBuffer);
+ filenameOffset = nameBuffer + nameLen;
+
+ for (;;) {
+ de = readdir(dir);
+
+ if (de == NULL) {
+ BTIF_TRACE_DEBUG1("readdir failed for path:%s", path);
+ //ret = -1;
+ break;
+ }
+
+ if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, ".."))
+ continue;
+
+ if((int)strlen(de->d_name) > PATH_MAX - nameLen) {
+ BTIF_TRACE_DEBUG1("d_name len:%d is too big", strlen(de->d_name));
+ ret = -1;
+ break;
+ }
+
+ strcpy(filenameOffset, de->d_name);
+
+ ret = lstat (nameBuffer, &statBuffer);
+
+ if (ret != 0) {
+ BTIF_TRACE_DEBUG1("lstat failed for path:%s", nameBuffer);
+ break;
+ }
+
+ if(S_ISDIR(statBuffer.st_mode)) {
+
+ ret = del_path(nameBuffer);
+ if(ret != 0)
+ break;
+ } else {
+ ret = unlink(nameBuffer);
+ if (ret != 0) {
+ BTIF_TRACE_DEBUG1("unlink failed for path:%s", nameBuffer);
+ break;
+ }
+ }
+ }
+
+ closedir(dir);
+ if(ret == 0) {
+ ret = rmdir(path);
+ BTIF_TRACE_DEBUG2("rmdir return:%d for path:%s", ret, path);
+ }
+
+ return ret;
+
+}
+
+inline int getAccess(int accType, struct stat *buffer, char *p_path)
+{
+
+ struct statfs fsbuffer;
+ int idType;
+
+ if(! buffer)
+ return BTA_FS_CO_FAIL;
+
+ //idType= (buffer->st_uid== BT_UID) ? 1 : (buffer->st_uid== BT_GID) ? 2 : 3;
+ if(buffer->st_uid == BT_UID)
+ idType = 1;
+ else if(buffer->st_gid == BT_GID ||
+ buffer->st_gid == AID_SYSTEM ||
+ buffer->st_gid == AID_MISC ||
+ buffer->st_gid == AID_SDCARD_RW)
+ idType = 2;
+ else idType = 3;
+
+ if(statfs(p_path, &fsbuffer)==0)
+ {
+ if(fsbuffer.f_type == FAT_FS)
+ return BTA_FS_CO_OK;
+ }
+ else {
+ return BTA_FS_CO_FAIL;
+ }
+
+ switch(accType) {
+ case 4:
+ if(idType== 1) { //Id is User Id
+ if(buffer-> st_mode & S_IRUSR)
+ return BTA_FS_CO_OK;
+ }
+ else if(idType==2) { //Id is Group Id
+ if(buffer-> st_mode & S_IRGRP)
+ return BTA_FS_CO_OK;
+ }
+ else { //Id is Others
+ if(buffer-> st_mode & S_IROTH)
+ return BTA_FS_CO_OK;
+ }
+ break;
+
+ case 6:
+ if(idType== 1) { //Id is User Id
+ if((buffer-> st_mode & S_IRUSR) && (buffer-> st_mode & S_IWUSR))
+ return BTA_FS_CO_OK;
+ }
+ else if(idType==2) { //Id is Group Id
+ if((buffer-> st_mode & S_IRGRP) && (buffer-> st_mode & S_IWGRP))
+ return BTA_FS_CO_OK;
+ }
+ else { //Id is Others
+ if((buffer-> st_mode & S_IROTH) && (buffer-> st_mode & S_IWOTH))
+ return BTA_FS_CO_OK;
+ }
+ break;
+
+ default:
+ return BTA_FS_CO_OK;
+ }
+ BTIF_TRACE_DEBUG0("*************FTP- Access Failed **********");
+ return BTA_FS_CO_EACCES;
+}
+
+
+/*****************************************************************************
+** Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_fs_convert_oflags
+**
+** Description This function converts the open flags from BTA into MFS.
+**
+** Returns BTA FS status value.
+**
+*******************************************************************************/
+int bta_fs_convert_bta_oflags(int bta_oflags)
+{
+ int oflags = 0; /* Initially read only */
+
+ /* Only one of these can be set: Read Only, Read/Write, or Write Only */
+ if (bta_oflags & BTA_FS_O_RDWR)
+ oflags |= O_RDWR;
+ else if (bta_oflags & BTA_FS_O_WRONLY)
+ oflags |= O_WRONLY;
+
+ /* OR in any other flags that are set by BTA */
+ if (bta_oflags & BTA_FS_O_CREAT)
+ oflags |= O_CREAT;
+
+ if (bta_oflags & BTA_FS_O_EXCL)
+ oflags |= O_EXCL;
+
+ if (bta_oflags & BTA_FS_O_TRUNC)
+ oflags |= O_TRUNC;
+
+ return (oflags);
+}
+
+
+
+/*******************************************************************************
+ **
+ ** Function btapp_fs_check_space
+ **
+ ** Description determines access and if there is enough space for given files size on given path
+ **
+ ** Parameters p_path - Fully qualified path and file name.
+ ** WARNING: file name is stripped off! so it must be present!
+ ** size - size of file to put (0 if unavailable or not applicable)
+ ** app_id - in case application specific treatement is required (e.g opp versus ftp)
+ ** Returns 0 if enough space, otherwise errno failure codes
+ **
+ *******************************************************************************/
+static int btapp_fs_check_space( const char *p_path, const UINT32 size, const UINT8 app_id )
+{
+
+ unsigned long long max_space;
+ struct statfs fs_buffer;
+ int err = 0;
+ char *p_dir;
+ char *p_end;
+
+ if(size==BTA_FS_LEN_UNKNOWN)
+ return 0;
+ /* fail silently in case of no memory. write will catch if not enough space */
+
+ if (NULL != (p_dir = (char *) GKI_getbuf(strlen(p_path) + 1)))
+ {
+ strcpy(p_dir, p_path);
+ if (NULL != (p_end = strrchr(p_dir, '/')))
+ {
+
+ *p_end = '\0';
+ /* get fs info and calculate available space. if not enough, the fs error EFBIG is returned */
+
+ if (0 == statfs(p_dir, &fs_buffer))
+ {
+
+ max_space = fs_buffer.f_bavail * fs_buffer.f_bsize;
+#if (BTA_FS_DEBUG==TRUE)
+ BTIF_TRACE_DEBUG2("btapp_fs_enough_space(file size: %d): (uint)max_size: %u", size, (UINT32)max_space);
+#endif
+ if (max_space < size)
+ err = EFBIG;
+ }
+ else
+ {
+ err = errno;
+ BTIF_TRACE_WARNING1("btapp_fs_enough_space(): statfs() failed with err: %d", err);
+ }
+ }
+ else
+ {
+ err = ENOENT;
+ }
+ GKI_freebuf(p_dir);
+ }
+ else
+ {
+ err = ENOMEM;
+ }
+ return err;
+
+} /* btapp_fs_check_access_space() */
+
+
+/*******************************************************************************
+**
+** Function bta_fs_co_open
+**
+** Description This function is executed by BTA when a file is opened.
+** The phone uses this function to open
+** a file for reading or writing.
+**
+** Parameters p_path - Fully qualified path and file name.
+** oflags - permissions and mode (see constants above)
+** size - size of file to put (0 if unavailable or not applicable)
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, a file descriptor (int),
+** if successful, and an error code (tBTA_FS_CO_STATUS)
+** are returned in the call-in function, bta_fs_ci_open().
+**
+*******************************************************************************/
+
+void bta_fs_co_open(const char *p_path, int oflags, UINT32 size, UINT16 evt,
+ UINT8 app_id)
+{
+
+ tBTA_FS_CO_STATUS status;
+ UINT32 file_size = 0;
+ struct stat file_stat;
+ int fd = -1;
+ int err = 0;
+
+ /* Convert BTA oflags into os specific flags */
+ oflags = bta_fs_convert_bta_oflags(oflags);
+
+ /* check available space in case of write access. oflags are in OS format! */
+ if (oflags & (O_RDWR|O_WRONLY))
+ {
+ err = btapp_fs_check_space(p_path, size, app_id);
+ }
+
+ if ( 0==err )
+ {
+ if ((fd = open(p_path, oflags | O_NONBLOCK, 0666)) >= 0)
+ {
+ if (fstat(fd, &file_stat) == 0)
+ {
+ file_size = file_stat.st_size;
+ if (oflags & O_CREAT)
+ {
+ fchown(fd, BT_UID, BT_GID);
+ BTIF_TRACE_DEBUG0("\n ******CHANGED OWNERSHIP SUCCESSFULLY**********");
+ }
+ }
+ }
+
+ else
+ {
+ err = errno;
+ }
+ }
+
+ BTIF_TRACE_DEBUG4("[CO] bta_fs_co_open: handle:%d err:%d, flags:%x, app id:%d",
+ fd, err, oflags, app_id);
+ BTIF_TRACE_DEBUG1("file=%s", p_path);
+
+ /* convert fs error into bta_fs err. erro is set by first call to enough space to a valid value
+ * and needs only updating in case of error. This reports correct failure to remote obex! */
+
+ switch (err)
+ {
+
+ case 0:
+ status = BTA_FS_CO_OK;
+ break;
+ case EACCES:
+ status = BTA_FS_CO_EACCES;
+ break;
+ case EFBIG: /* file to big for available fs space */
+ status = BTA_FS_CO_ENOSPACE;
+ break;
+ default:
+ status = BTA_FS_CO_FAIL;
+ break;
+ }
+ bta_fs_ci_open(fd, status, file_size, evt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_close
+**
+** Description This function is called by BTA when a connection to a
+** client is closed.
+**
+** Parameters fd - file descriptor of file to close.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful],
+** [BTA_FS_CO_FAIL if failed ]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_close(int fd, UINT8 app_id)
+{
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ int err;
+
+ BTIF_TRACE_DEBUG2("[CO] bta_fs_co_close: handle:%d, app id:%d",
+ fd, app_id);
+ if (close (fd) < 0)
+ {
+ err = errno;
+ status = BTA_FS_CO_FAIL;
+ BTIF_TRACE_WARNING3("[CO] bta_fs_co_close: handle:%d error=%d app_id:%d", fd, err, app_id);
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_read
+**
+** Description This function is called by BTA to read in data from the
+** previously opened file on the phone.
+**
+** Parameters fd - file descriptor of file to read from.
+** p_buf - buffer to read the data into.
+** nbytes - number of bytes to read into the buffer.
+** evt - event that must be passed into the call-in function.
+** ssn - session sequence number. Ignored, if bta_fs_co_open
+** was not called with BTA_FS_CO_RELIABLE.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, bta_fs_ci_read() is
+** called with the buffer of data, along with the number
+** of bytes read into the buffer, and a status. The
+** call-in function should only be called when ALL requested
+** bytes have been read, the end of file has been detected,
+** or an error has occurred.
+**
+*******************************************************************************/
+void bta_fs_co_read(int fd, UINT8 *p_buf, UINT16 nbytes, UINT16 evt, UINT8 ssn, UINT8 app_id)
+{
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ INT32 num_read;
+ int err;
+
+ if ((num_read = read (fd, p_buf, nbytes)) < 0)
+ {
+ err = errno;
+ status = BTA_FS_CO_FAIL;
+ BTIF_TRACE_WARNING3("[CO] bta_fs_co_read: handle:%d error=%d app_id:%d",
+ fd, err, app_id);
+ }
+ else if (num_read < nbytes)
+ status = BTA_FS_CO_EOF;
+
+ bta_fs_ci_read(fd, (UINT16)num_read, status, evt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_write
+**
+** Description This function is called by io to send file data to the
+** phone.
+**
+** Parameters fd - file descriptor of file to write to.
+** p_buf - buffer to read the data from.
+** nbytes - number of bytes to write out to the file.
+** evt - event that must be passed into the call-in function.
+** ssn - session sequence number. Ignored, if bta_fs_co_open
+** was not called with BTA_FS_CO_RELIABLE.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, bta_fs_ci_write() is
+** called with the file descriptor and the status. The
+** call-in function should only be called when ALL requested
+** bytes have been written, or an error has been detected,
+**
+*******************************************************************************/
+void bta_fs_co_write(int fd, const UINT8 *p_buf, UINT16 nbytes, UINT16 evt,
+ UINT8 ssn, UINT8 app_id)
+{
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ INT32 num_written;
+ int err=0;
+
+ if ((num_written = write (fd, p_buf, nbytes)) < 0)
+ {
+ err = errno;
+ status = BTA_FS_CO_FAIL;
+ }
+/* BTIF_TRACE_DEBUG3("[CO] bta_fs_co_write: handle:%d error=%d, num_written:%d", fd, err, num_written);*/
+
+ bta_fs_ci_write(fd, status, evt);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_seek
+**
+** Description This function is called by io to move the file pointer
+** of a previously opened file to the specified location for
+** the next read or write operation.
+**
+** Parameters fd - file descriptor of file.
+** offset - Number of bytes from origin.
+** origin - Initial position.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_seek (int fd, INT32 offset, INT16 origin, UINT8 app_id)
+{
+ lseek(fd, offset, origin);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_access
+**
+** Description This function is called to check the existence of
+** a file or directory, and return whether or not it is a
+** directory or length of the file.
+**
+** Parameters p_path - (input) file or directory to access (fully qualified path).
+** mode - (input) [BTA_FS_ACC_EXIST, BTA_FS_ACC_READ, or BTA_FS_ACC_RDWR]
+** p_is_dir - (output) returns TRUE if p_path specifies a directory.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if it exists]
+** [BTA_FS_CO_EACCES if permissions are wrong]
+** [BTA_FS_CO_FAIL if it does not exist]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_access(const char *p_path, int mode, BOOLEAN *p_is_dir,
+ UINT8 app_id)
+{
+ int err;
+ int os_mode = 0;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ struct stat buffer;
+
+ #if (TRUE==BTA_FS_DEBUG)
+ LOGI("***********CHECKING ACCESS TO = %s", p_path);
+ #endif
+
+ #if (defined BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE)
+
+ if (app_id == UI_PBS_ID)
+ {
+
+ *p_is_dir = TRUE;
+
+ #if (TRUE==BTA_FS_DEBUG)
+ LOGI("***********SUPPORTED REPO = %d", bta_pbs_cfg.supported_repositories);
+ #endif
+ //Check if SIM contact requested, and if so if it's supported.
+ //If not, return error!
+ if (strstr(p_path,"SIM1") && !(bta_pbs_cfg.supported_repositories & 0x2)) {
+ LOGI("***********RETURNING FAIL!");
+ return BTA_FS_CO_FAIL;
+ }
+
+ #if (TRUE==BTA_FS_DEBUG)
+ LOGI("***********RETURNING success!");
+ #endif
+ return (status);
+ }
+ #endif
+
+
+ *p_is_dir = FALSE;
+
+ if (mode == BTA_FS_ACC_RDWR)
+ os_mode = 6;
+ else if (mode == BTA_FS_ACC_READ)
+ os_mode = 4;
+
+ if (stat(p_path, &buffer) == 0)
+ {
+ /* Determine if the object is a file or directory */
+ if (S_ISDIR(buffer.st_mode))
+ *p_is_dir = TRUE;
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("stat() failed! ");
+ return BTA_FS_CO_FAIL;
+ }
+
+ status=getAccess (os_mode, &buffer, (char*)p_path);
+ return (status);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_mkdir
+**
+** Description This function is called to create a directory with
+** the pathname given by path. The pathname is a null terminated
+** string. All components of the path must already exist.
+**
+** Parameters p_path - (input) name of directory to create (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_FAIL if unsuccessful]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_mkdir(const char *p_path, UINT8 app_id)
+{
+ int err;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+
+ if ((mkdir (p_path, 0666)) != 0)
+ {
+ err = errno;
+ status = BTA_FS_CO_FAIL;
+ BTIF_TRACE_WARNING3("[CO] bta_fs_co_mkdir: error=%d, path [%s] app_id:%d",
+ err, p_path, app_id);
+ }
+ return (status);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_rmdir
+**
+** Description This function is called to remove a directory whose
+** name is given by path. The directory must be empty.
+**
+** Parameters p_path - (input) name of directory to remove (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if read-only]
+** [BTA_FS_CO_ENOTEMPTY if directory is not empty]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_rmdir(const char *p_path, UINT8 app_id)
+{
+ int err, path_len;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ struct stat buffer;
+ char *dirName, *tmp = NULL;
+
+ path_len = strlen( p_path )+1;
+ BTIF_TRACE_DEBUG2( "bta_fs_co_rmdir( app_id: %d ): path_len: %d", app_id, path_len );
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_DEBUG1( "bta_fs_co_rmdir():path_len: %d, p_path", app_id );
+ BTIF_TRACE_DEBUG0( p_path );
+#endif
+
+ /* allocate a temp buffer for path with 0 char. make sure not to crash if path is too big! */
+ dirName = (char*) calloc(1, path_len+1);
+ if ( NULL != dirName )
+ {
+ strcpy( dirName, p_path );
+ }
+ else
+ {
+ BTIF_TRACE_WARNING2( "bta_fs_co_rmdir( app_id: %d ) for path_len: %d::out of memory",
+ app_id, path_len );
+ return BTA_FS_CO_FAIL;
+ }
+
+ if (NULL!= (tmp = strrchr(dirName, '/')))
+ {
+ *tmp = '\0';
+ }
+ if (stat(dirName, &buffer) == 0)
+ {
+ status = getAccess(6, &buffer, dirName);
+ }
+ else
+ {
+ free(dirName);
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::stat(dirName) failed" );
+#endif
+ return BTA_FS_CO_FAIL;
+ }
+
+ free(dirName);
+ if (status != BTA_FS_CO_OK)
+ {
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::getAccess(dirName) FAILED");
+#endif
+ return status;
+ }
+
+ if (stat(p_path, &buffer) == 0)
+ {
+ status = getAccess(6, &buffer, (char*)p_path);
+ }
+ else
+ {
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::stat(p_path) FAILED");
+#endif
+ return BTA_FS_CO_FAIL;
+ }
+
+ if (status != BTA_FS_CO_OK)
+ {
+#if (TRUE==BTA_FS_DEBUG)
+ BTIF_TRACE_DEBUG0( "bta_fs_co_rmdir()::getAccess(p_path) FAILED");
+#endif
+ return status;
+ }
+ //if ((rmdir (p_path)) != 0)
+ if (del_path(p_path) != 0)
+ {
+ err = errno;
+ BTIF_TRACE_WARNING1( "bta_fs_co_rmdir():rmdir/del_path FAILED with err: %d", err );
+ if (err == EACCES)
+ status = BTA_FS_CO_EACCES;
+ else if (err == ENOTEMPTY)
+ status = BTA_FS_CO_ENOTEMPTY;
+ else
+ status = BTA_FS_CO_FAIL;
+ }
+ return (status);
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_unlink
+**
+** Description This function is called to remove a file whose name
+** is given by p_path.
+**
+** Parameters p_path - (input) name of file to remove (fully qualified path).
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if read-only]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+tBTA_FS_CO_STATUS bta_fs_co_unlink(const char *p_path, UINT8 app_id)
+{
+ BTIF_TRACE_DEBUG0("bta_fs_co_unlink");
+ int err;
+ tBTA_FS_CO_STATUS status = BTA_FS_CO_OK;
+ char *dirName, *tmp=NULL;
+ struct stat buffer;
+
+ if(! p_path)
+ return BTA_FS_CO_FAIL;
+
+ /* buffer needs to be NULL terminated - so add one more byte to be zero'd out */
+#if 0
+ dirName= (char*) calloc(1, strlen(p_path)); /* <--- this can cause problems */
+#else
+ dirName= (char*) calloc(1, strlen(p_path) + 1);
+#endif
+
+ strncpy(dirName, p_path, strlen(p_path));
+ if((tmp=strrchr(dirName, '/')))
+ {
+ *tmp='\0';
+ }
+ if (stat(dirName, &buffer) == 0)
+ {
+ status=getAccess (6, &buffer, dirName);
+ free(dirName);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("stat() failed! ");
+ free(dirName);
+ return BTA_FS_CO_FAIL;
+ }
+
+ if(status!= BTA_FS_CO_OK)
+ return status;
+
+ if ((unlink (p_path)) != 0)
+ {
+ err = errno;
+ if (err == EACCES)
+ status = BTA_FS_CO_EACCES;
+ else
+ status = BTA_FS_CO_FAIL;
+ }
+ return (status);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_getdirentry
+**
+** Description This function is called to get a directory entry for the
+** specified p_path. The first/next directory should be filled
+** into the location specified by p_entry.
+**
+** Parameters p_path - directory to search (Fully qualified path)
+** first_item - TRUE if first search, FALSE if next search
+** (p_cur contains previous)
+** p_entry (input/output) - Points to last entry data (valid when
+** first_item is FALSE)
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the status is passed
+** in the bta_fs_ci_direntry() call-in function.
+** BTA_FS_CO_OK is returned when p_entry is valid,
+** BTA_FS_CO_EODIR is returned when no more entries [finished]
+** BTA_FS_CO_FAIL is returned if an error occurred
+**
+*******************************************************************************/
+void bta_fs_co_getdirentry(const char *p_path, BOOLEAN first_item,
+ tBTA_FS_DIRENTRY *p_entry, UINT16 evt, UINT8 app_id)
+{
+ tBTA_FS_CO_STATUS co_status = BTA_FS_CO_FAIL;
+ int status = -1; /* '0' - success, '-1' - fail */
+ struct tm *p_tm;
+ DIR *dir;
+ struct dirent *dirent;
+ struct stat buf;
+ char fullname[500];
+
+ BTIF_TRACE_DEBUG0("Entered bta_fs_co_getdirentry");
+
+ /* First item is to be retrieved */
+ if (first_item)
+ {
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: path = %s", p_path);
+
+ dir = opendir(p_path);
+ if(dir == NULL)
+ {
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dir is NULL so error out with errno=%d", errno);
+ co_status = BTA_FS_CO_EODIR;
+ bta_fs_ci_direntry(co_status, evt);
+ return;
+ }
+
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dir = %p", dir);
+ if((dirent = readdir(dir)) != NULL)
+ {
+ p_entry->refdata = (UINT32) dir; /* Save this for future searches */
+ status = 0;
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent);
+ /* Close the search if there are no more items */
+ closedir( (DIR*) p_entry->refdata);
+ co_status = BTA_FS_CO_EODIR;
+ }
+ }
+ else /* Get the next entry based on the p_ref data from previous search */
+ {
+ if ((dirent = readdir((DIR*)p_entry->refdata)) == NULL)
+ {
+ /* Close the search if there are no more items */
+ closedir( (DIR*) p_entry->refdata);
+ co_status = BTA_FS_CO_EODIR;
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent);
+ status = 0;
+ }
+ }
+
+ if (status == 0)
+ {
+ BTIF_TRACE_DEBUG0("bta_fs_co_getdirentry: status = 0");
+
+ sprintf(fullname, "%s/%s", p_path, dirent->d_name);
+
+ /* Load new values into the return structure (refdata is left untouched) */
+ if (stat(fullname, &buf) == 0) {
+ p_entry->filesize = buf.st_size;
+ p_entry->mode = 0; /* Default is normal read/write file access */
+
+ if (S_ISDIR(buf.st_mode))
+ p_entry->mode |= BTA_FS_A_DIR;
+ else
+ p_entry->mode |= BTA_FS_A_RDONLY;
+
+ strcpy(p_entry->p_name, dirent->d_name);
+#if 0
+ fprintf(stderr, "bta_fs_co_getdirentry(): %s %9d %d\n",
+ dirent->d_name,
+ buf.st_size,
+ p_entry->mode);
+#endif
+ p_tm = localtime((const time_t*)&buf.st_mtime);
+ if (p_tm != NULL)
+ {
+ sprintf(p_entry->crtime, "%04d%02d%02dT%02d%02d%02dZ",
+ p_tm->tm_year + 1900, /* Base Year ISO 6201 */
+ p_tm->tm_mon + 1, /* month starts at 0 */
+ p_tm->tm_mday,
+ p_tm->tm_hour,
+ p_tm->tm_min,
+ p_tm->tm_sec);
+ }
+ else
+ p_entry->crtime[0] = '\0'; /* No valid time */
+#if 0
+ fprintf(stderr, "bta_fs_co_getdirentry(): %s %9d %d %s\n",
+ dirent->d_name,
+ p_entry->filesize,
+ p_entry->mode,
+ p_entry->crtime);
+#endif
+ co_status = BTA_FS_CO_OK;
+ } else {
+ BTIF_TRACE_WARNING0("stat() failed! ");
+ co_status = BTA_FS_CO_EACCES;
+ }
+ }
+ BTIF_TRACE_DEBUG0("bta_fs_co_getdirentry: calling bta_fs_ci_getdirentry");
+
+ bta_fs_ci_direntry(co_status, evt);
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_fs_co_setdir
+**
+** Description This function is executed by BTA when the server changes the
+** local path
+**
+** Parameters p_path - the new path.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_setdir(const char *p_path, UINT8 app_id)
+{
+ BTIF_TRACE_DEBUG2("Entered %s. New path: %s", __FUNCTION__, p_path);
+}
+
+/*******************************************************************************
+** OBEX14 Reliable Session not supported. Stub associated callouts.
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function bta_fs_co_resume
+**
+** Description This function is executed by BTA when resuming a session.
+** This is used to retrieve the session ID and related information
+**
+** Parameters evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+** Note: Upon completion of the request, the related session information,
+** if successful, and an error code (tBTA_FS_CO_STATUS)
+** are returned in the call-in function, bta_fs_ci_resume().
+**
+*******************************************************************************/
+void bta_fs_co_resume(UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_resume - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_set_perms
+**
+** Description This function is called to set the permission a file/directory
+** with name as p_src_path.
+**
+** Parameters p_src_path - (input) name of file/directory to set permission (fully qualified path).
+** p_perms - the permission .
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+void bta_fs_co_set_perms(const char *p_src_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_set_perms - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_rename
+**
+** Description This function is called to move a file/directory whose
+** name is given by p_src_path to p_dest_path.
+**
+** Parameters p_src_path - (input) name of file/directory to be moved (fully qualified path).
+** p_dest_path - (input) new name of file/directory(fully qualified path).
+** p_perms - the permission of the new object.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+void bta_fs_co_rename(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_rename - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_copy
+**
+** Description This function is called to copy a file/directory whose
+** name is given by p_src_path to p_dest_path.
+**
+** Parameters p_src_path - (input) name of file/directory to be copied (fully qualified path).
+** p_dest_path - (input) new name of file/directory(fully qualified path).
+** p_perms - the permission of the new object.
+** evt - event that must be passed into the call-in function.
+** app_id - (input) application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns (tBTA_FS_CO_STATUS) status of the call.
+** [BTA_FS_CO_OK if successful]
+** [BTA_FS_CO_EIS_DIR if p_src_path is a folder]
+** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path);
+** or p_src_path is a directory and p_dest_path specifies a different path. ]
+** [BTA_FS_CO_FAIL otherwise]
+**
+*******************************************************************************/
+void bta_fs_co_copy(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_copy - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_resume_op
+**
+** Description This function is executed by BTA when a reliable session is
+** resumed and there was an interrupted operation.
+**
+** Parameters offset - the session ID and related information.
+** evt - event that must be passed into the call-in function.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_resume_op(UINT32 offset, UINT16 evt, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_resume_op - NOT implemented");
+}
+
+
+/*******************************************************************************
+**
+** Function bta_fs_co_session_info
+**
+** Description This function is executed by BTA when a reliable session is
+** established (p_sess_info != NULL) or ended (p_sess_info == NULL).
+**
+** Parameters bd_addr - the peer address
+** p_sess_info - the session ID and related information.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_session_info(BD_ADDR bd_addr, UINT8 *p_sess_info, UINT8 ssn,
+ tBTA_FS_CO_SESS_ST new_st, char *p_path, UINT8 *p_info, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_session_info - NOT implemented");
+}
+
+
+/*******************************************************************************
+**
+** Function bta_fs_co_suspend
+**
+** Description This function is executed by BTA when a reliable session is
+** suspended.
+**
+** Parameters bd_addr - the peer address
+** ssn - the session sequence number.
+** info - the BTA specific information (like last active operation).
+** p_offset- the location to receive object offset of the suspended session
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_suspend(BD_ADDR bd_addr, UINT8 *p_sess_info, UINT8 ssn,
+ UINT32 *p_timeout, UINT32 *p_offset, UINT8 info, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_suspend - NOT implemented");
+}
+
+/*******************************************************************************
+**
+** Function bta_fs_co_sess_ssn
+**
+** Description This function is executed by BTA when resuming a session.
+** This is used to inform call-out module if the ssn/file offset
+** needs to be adjusted.
+**
+** Parameters ssn - the session sequence number of the first request
+** after resume.
+** app_id - application ID specified in the enable functions.
+** It can be used to identify which profile is the caller
+** of the call-out function.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_fs_co_sess_ssn(int fd, UINT8 ssn, UINT8 app_id)
+{
+ BTIF_TRACE_WARNING0("[CO] bta_fs_co_suspend - NOT implemented");
+}
+
diff --git a/btif/co/bta_hh_co.c b/btif/co/bta_hh_co.c
new file mode 100644
index 0000000..81414d2
--- /dev/null
+++ b/btif/co/bta_hh_co.c
@@ -0,0 +1,276 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+//#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <linux/uhid.h>
+#include "btif_hh.h"
+#include "bta_api.h"
+#include "bta_hh_api.h"
+
+
+
+const char *dev_path = "/dev/uhid";
+
+
+/*Internal function to perform UHID write and error checking*/
+static int uhid_write(int fd, const struct uhid_event *ev)
+{
+ ssize_t ret;
+ ret = write(fd, ev, sizeof(*ev));
+ if (ret < 0){
+ int rtn = -errno;
+ APPL_TRACE_ERROR2("%s: Cannot write to uhid:%s",__FUNCTION__,strerror(errno));
+ return rtn;
+ } else if (ret != sizeof(*ev)) {
+ APPL_TRACE_ERROR3("%s: Wrong size written to uhid: %ld != %lu",
+ __FUNCTION__, ret, sizeof(*ev));
+ return -EFAULT;
+ } else {
+ return 0;
+ }
+}
+
+void bta_hh_co_destroy(int fd)
+{
+ struct uhid_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_DESTROY;
+ uhid_write(fd, &ev);
+ close(fd);
+}
+
+int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len)
+{
+ APPL_TRACE_DEBUG0("bta_hh_co_data: UHID write");
+ struct uhid_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_INPUT;
+ ev.u.input.size = len;
+ if(len > sizeof(ev.u.input.data)){
+ APPL_TRACE_WARNING1("%s:report size greater than allowed size",__FUNCTION__);
+ return -1;
+ }
+ memcpy(ev.u.input.data, rpt, len);
+ return uhid_write(fd, &ev);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_co_open
+**
+** Description When connection is opened, this call-out function is executed
+** by HH to do platform specific initialization.
+**
+** Returns void.
+*******************************************************************************/
+void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_mask,
+ UINT8 app_id)
+{
+ UINT32 i;
+ btif_hh_device_t *p_dev = NULL;
+
+ if (dev_handle == BTA_HH_INVALID_HANDLE) {
+ APPL_TRACE_WARNING2("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
+ return;
+ }
+
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ p_dev = &btif_hh_cb.devices[i];
+ if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
+ // We found a device with the same handle. Must be a device reconnected.
+ APPL_TRACE_WARNING2("%s: Found an existing device with the same handle "
+ "dev_status = %d",__FUNCTION__,
+ p_dev->dev_status);
+ APPL_TRACE_WARNING6("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__,
+ p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
+ p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
+ APPL_TRACE_WARNING4("%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
+ __FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
+
+ if(p_dev->fd<0) {
+ p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
+ if (p_dev->fd < 0){
+ APPL_TRACE_ERROR2("%s: Error: failed to open uhid, err:%s",
+ __FUNCTION__,strerror(errno));
+ }else
+ APPL_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
+ }
+
+ break;
+ }
+ p_dev = NULL;
+ }
+
+ if (p_dev == NULL) {
+ // Did not find a device reconnection case. Find an empty slot now.
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
+ p_dev = &btif_hh_cb.devices[i];
+ p_dev->dev_handle = dev_handle;
+ p_dev->attr_mask = attr_mask;
+ p_dev->sub_class = sub_class;
+ p_dev->app_id = app_id;
+
+ btif_hh_cb.device_num++;
+ // This is a new device,open the uhid driver now.
+ p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
+ if (p_dev->fd < 0){
+ APPL_TRACE_ERROR2("%s: Error: failed to open uhid, err:%s",
+ __FUNCTION__,strerror(errno));
+ }else
+ APPL_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
+
+
+ break;
+ }
+ }
+ }
+
+ if (p_dev == NULL) {
+ APPL_TRACE_ERROR1("%s: Error: too many HID devices are connected", __FUNCTION__);
+ return;
+ }
+
+ p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
+ APPL_TRACE_DEBUG2("%s: Return device status %d", __FUNCTION__, p_dev->dev_status);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_co_close
+**
+** Description When connection is closed, this call-out function is executed
+** by HH to do platform specific finalization.
+**
+** Parameters dev_handle - device handle
+** app_id - application id
+**
+** Returns void.
+*******************************************************************************/
+void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id)
+{
+ APPL_TRACE_WARNING3("%s: dev_handle = %d, app_id = %d", __FUNCTION__, dev_handle, app_id);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_co_data
+**
+** Description This function is executed by BTA when HID host receive a data
+** report.
+**
+** Parameters dev_handle - device handle
+** *p_rpt - pointer to the report data
+** len - length of report data
+** mode - Hid host Protocol Mode
+** sub_clas - Device Subclass
+** app_id - application id
+**
+** Returns void
+*******************************************************************************/
+void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MODE mode,
+ UINT8 sub_class, UINT8 ctry_code, BD_ADDR peer_addr, UINT8 app_id)
+{
+ btif_hh_device_t *p_dev;
+
+ APPL_TRACE_DEBUG6("%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
+ "ctry_code = %d, app_id = %d",
+ __FUNCTION__, dev_handle, sub_class, mode, ctry_code, app_id);
+
+ p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
+ if (p_dev == NULL) {
+ APPL_TRACE_WARNING2("%s: Error: unknown HID device handle %d", __FUNCTION__, dev_handle);
+ return;
+ }
+ // Send the HID report to the kernel.
+ if (p_dev->fd >= 0) {
+ bta_hh_co_write(p_dev->fd, p_rpt, len);
+ }else {
+ APPL_TRACE_WARNING3("%s: Error: fd = %d, len = %d", __FUNCTION__, p_dev->fd, len);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hh_co_send_hid_info
+**
+** Description This function is called in btif_hh.c to process DSCP received.
+**
+** Parameters dev_handle - device handle
+** dscp_len - report descriptor length
+** *p_dscp - report descriptor
+**
+** Returns void
+*******************************************************************************/
+void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 vendor_id,
+ UINT16 product_id, UINT16 version, UINT8 ctry_code,
+ int dscp_len, UINT8 *p_dscp)
+{
+ int result;
+ struct uhid_event ev;
+
+ if (p_dev->fd < 0) {
+ APPL_TRACE_WARNING3("%s: Error: fd = %d, dscp_len = %d", __FUNCTION__, p_dev->fd, dscp_len);
+ return;
+ }
+
+ APPL_TRACE_WARNING4("%s: fd = %d, name = [%s], dscp_len = %d", __FUNCTION__,
+ p_dev->fd, dev_name, dscp_len);
+ APPL_TRACE_WARNING5("%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x,"
+ "ctry_code=0x%02x",__FUNCTION__,
+ vendor_id, product_id,
+ version, ctry_code);
+
+//Create and send hid descriptor to kernel
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_CREATE;
+ strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1);
+ ev.u.create.rd_size = dscp_len;
+ ev.u.create.rd_data = p_dscp;
+ ev.u.create.bus = BUS_BLUETOOTH;
+ ev.u.create.vendor = vendor_id;
+ ev.u.create.product = product_id;
+ ev.u.create.version = version;
+ ev.u.create.country = ctry_code;
+ result = uhid_write(p_dev->fd, &ev);
+
+ APPL_TRACE_WARNING4("%s: fd = %d, dscp_len = %d, result = %d", __FUNCTION__,
+ p_dev->fd, dscp_len, result);
+
+ if (result) {
+ APPL_TRACE_WARNING2("%s: Error: failed to send DSCP, result = %d", __FUNCTION__, result);
+
+ /* The HID report descriptor is corrupted. Close the driver. */
+ close(p_dev->fd);
+ p_dev->fd = -1;
+ }
+}
+
+
diff --git a/btif/co/bta_hl_co.c b/btif/co/bta_hl_co.c
new file mode 100644
index 0000000..a7a9061
--- /dev/null
+++ b/btif/co/bta_hl_co.c
@@ -0,0 +1,459 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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 is the implementation file for the HeaLth device profile (HL)
+ * subsystem call-out functions.
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <cutils/sockets.h>
+#include <cutils/log.h>
+#include "bta_api.h"
+#include "btm_api.h"
+#include "bta_sys.h"
+#include "bta_hl_api.h"
+#include "bta_hl_co.h"
+#include "bta_hl_ci.h"
+#include "btif_hl.h"
+
+
+
+/*****************************************************************************
+** Constants and Data Types
+*****************************************************************************/
+/**************************
+** Common Definitions
+***************************/
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_get_num_of_mdep
+**
+** Description This function is called to get the number of MDEPs for this
+** application ID
+**
+** Parameters app_id - application ID
+** p_num_of_mdep (output) - number of MDEP configurations supported
+** by the application
+**
+** Returns Bloolean - TRUE success
+**
+*******************************************************************************/
+BOOLEAN bta_hl_co_get_num_of_mdep(UINT8 app_id, UINT8 *p_num_of_mdep)
+{
+ UINT8 app_idx;
+ BOOLEAN success = FALSE;
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+ *p_num_of_mdep = p_btif_hl_cb->acb[app_idx].sup_feature.num_of_mdeps;
+ success = TRUE;
+ }
+
+
+ BTIF_TRACE_DEBUG3("%s success=%d num_mdeps=%d",
+ __FUNCTION__, success, *p_num_of_mdep );
+ return success;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_co_advrtise_source_sdp
+**
+** Description This function is called to find out whether the SOURCE MDEP
+** configuration information should be advertize in the SDP or nopt
+**
+** Parameters app_id - application ID
+**
+** Returns Bloolean - TRUE advertise the SOURCE MDEP configuration
+** information
+**
+*******************************************************************************/
+BOOLEAN bta_hl_co_advrtise_source_sdp(UINT8 app_id)
+{
+ BOOLEAN advertize_source_sdp=FALSE;
+ UINT8 app_idx;
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+ advertize_source_sdp = p_btif_hl_cb->acb[app_idx].sup_feature.advertize_source_sdp;
+ }
+
+
+ BTIF_TRACE_DEBUG2("%s advertize_flag=%d", __FUNCTION__, advertize_source_sdp );
+
+ return advertize_source_sdp;
+}
+/*******************************************************************************
+**
+** Function bta_hl_co_get_mdep_config
+**
+** Description This function is called to get the supported feature
+** configuration for the specified mdep index and it also assigns
+** the MDEP ID for the specified mdep index
+**
+** Parameters app_id - HDP application ID
+** mdep_idx - the mdep index
+** mdep_id - the assigned MDEP ID for the specified medp_idx
+** p_mdl_cfg (output) - pointer to the MDEP configuration
+**
+**
+** Returns Bloolean - TRUE success
+*******************************************************************************/
+BOOLEAN bta_hl_co_get_mdep_config(UINT8 app_id,
+ UINT8 mdep_idx,
+ tBTA_HL_MDEP_ID mdep_id,
+ tBTA_HL_MDEP_CFG *p_mdep_cfg)
+{
+ UINT8 idx ;
+ UINT8 app_idx;
+ BOOLEAN success = FALSE;
+
+ BTIF_TRACE_DEBUG4("%s app_id=%d mdep_idx=%d mdep_id=%d",
+ __FUNCTION__, app_id,mdep_idx,mdep_id );
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+ idx = mdep_idx -1;
+ p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_id = mdep_id;
+ memcpy(p_mdep_cfg,
+ &p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_cfg,
+ sizeof(tBTA_HL_MDEP_CFG));
+
+ success = TRUE;
+ }
+
+ BTIF_TRACE_DEBUG4("%s success=%d mdep_idx=%d mdep_id=%d",
+ __FUNCTION__, success, mdep_idx, mdep_id );
+
+ return success;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_get_echo_config
+**
+** Description This function is called to get the echo test
+** maximum APDU size configurations
+**
+** Parameters app_id - HDP application ID
+** p_echo_cfg (output) - pointer to the Echo test maximum APDU size
+** configuration
+**
+** Returns Bloolean - TRUE success
+*******************************************************************************/
+BOOLEAN bta_hl_co_get_echo_config(UINT8 app_id,
+ tBTA_HL_ECHO_CFG *p_echo_cfg)
+{
+ UINT8 app_idx;
+ BOOLEAN success = FALSE;
+ btif_hl_app_cb_t *p_acb;
+ tBTA_HL_SUP_FEATURE *p_sup;
+
+ BTIF_TRACE_DEBUG2("%s app_id=%d",__FUNCTION__, app_id );
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_sup = &p_acb->sup_feature;
+ p_echo_cfg->max_rx_apdu_size = p_sup->echo_cfg.max_rx_apdu_size;
+ p_echo_cfg->max_tx_apdu_size = p_sup->echo_cfg.max_tx_apdu_size;
+ success = TRUE;
+ }
+
+ BTIF_TRACE_DEBUG4("%s success=%d max tx_size=%d rx_size=%d",
+ __FUNCTION__, success, p_echo_cfg->max_tx_apdu_size,
+ p_echo_cfg->max_rx_apdu_size );
+
+ return success;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_save_mdl
+**
+** Description This function is called to save a MDL configuration item in persistent
+** storage
+**
+** Parameters app_id - HDP application ID
+** item_idx - the MDL configuration storage index
+** p_mdl_cfg - pointer to the MDL configuration data
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_co_save_mdl(UINT8 app_id, UINT8 item_idx, tBTA_HL_MDL_CFG *p_mdl_cfg )
+{
+
+ BTIF_TRACE_DEBUG6("%s app_id=%d, item_idx=%d active=%d mdl_id=%d time=%d",
+ __FUNCTION__, app_id, item_idx,
+ p_mdl_cfg->active,
+ p_mdl_cfg->mdl_id,
+ p_mdl_cfg->time);
+
+
+ btif_hl_save_mdl_cfg(app_id, item_idx, p_mdl_cfg);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_co_delete_mdl
+**
+** Description This function is called to delete a MDL configuration item in persistent
+** storage
+**
+** Parameters app_id - HDP application ID
+** item_idx - the MDL configuration storage index
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hl_co_delete_mdl(UINT8 app_id, UINT8 item_idx)
+{
+
+
+ BTIF_TRACE_DEBUG3("%s app_id=%d, item_idx=%d", __FUNCTION__, app_id, item_idx);
+
+ btif_hl_delete_mdl_cfg(app_id, item_idx);
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_co_get_mdl_config
+**
+** Description This function is called to get the MDL configuration
+** from the persistent memory. This function shall only be called
+*8 once after the device is powered up
+**
+** Parameters app_id - HDP application ID
+** buffer_size - the unit of the buffer size is sizeof(tBTA_HL_MDL_CFG)
+** p_mdl_buf - Point to the starting location of the buffer
+**
+** Returns BOOLEAN
+**
+**
+*******************************************************************************/
+BOOLEAN bta_hl_co_load_mdl_config (UINT8 app_id, UINT8 buffer_size,
+ tBTA_HL_MDL_CFG *p_mdl_buf )
+{
+ BOOLEAN result = TRUE;
+ UINT8 i;
+ tBTA_HL_MDL_CFG *p;
+
+ BTIF_TRACE_DEBUG3("%s app_id=%d, num_items=%d",
+ __FUNCTION__, app_id, buffer_size);
+
+ if (buffer_size > BTA_HL_NUM_MDL_CFGS)
+ {
+ result = FALSE;
+ return result;
+ }
+ result = btif_hl_load_mdl_config(app_id, buffer_size, p_mdl_buf);
+
+ if (result)
+ {
+ for (i=0, p=p_mdl_buf; i<buffer_size; i++, p++ )
+ {
+ if (p->active)
+ {
+ BTIF_TRACE_DEBUG6("i=%d mdl_id=0x%x dch_mode=%d local mdep_role=%d mdep_id=%d mtu=%d",
+ i, p->mdl_id, p->dch_mode, p->local_mdep_role, p->local_mdep_role, p->mtu);
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG3("%s success=%d num_items=%d", __FUNCTION__, result, buffer_size);
+
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function bta_hl_co_get_tx_data
+**
+** Description Get the data to be sent
+**
+** Parameters app_id - HDP application ID
+** mdl_handle - MDL handle
+** buf_size - the size of the buffer
+** p_buf - the buffer pointer
+** evt - the evt to be passed back to the HL in the
+** bta_hl_ci_get_tx_data call-in function
+**
+** Returns Void
+**
+*******************************************************************************/
+void bta_hl_co_get_tx_data (UINT8 app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT16 buf_size, UINT8 *p_buf, UINT16 evt)
+{
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ btif_hl_mdl_cb_t *p_dcb;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ BTIF_TRACE_DEBUG4("%s app_id=%d mdl_handle=0x%x buf_size=%d",
+ __FUNCTION__, app_id, mdl_handle, buf_size);
+
+ if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (p_dcb->tx_size <= buf_size )
+ {
+ memcpy(p_buf, p_dcb->p_tx_pkt, p_dcb->tx_size);
+ btif_hl_free_buf((void **) &p_dcb->p_tx_pkt);
+ p_dcb->tx_size = 0;
+ status = BTA_HL_STATUS_OK;
+ }
+ }
+
+
+ bta_hl_ci_get_tx_data(mdl_handle, status, evt);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_put_rx_data
+**
+** Description Put the received data
+**
+** Parameters app_id - HDP application ID
+** mdl_handle - MDL handle
+** data_size - the size of the data
+** p_data - the data pointer
+** evt - the evt to be passed back to the HL in the
+** bta_hl_ci_put_rx_data call-in function
+**
+** Returns Void
+**
+*******************************************************************************/
+void bta_hl_co_put_rx_data (UINT8 app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT16 data_size, UINT8 *p_data, UINT16 evt)
+{
+ UINT8 app_idx, mcl_idx, mdl_idx;
+ btif_hl_mdl_cb_t *p_dcb;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+ int r;
+ BTIF_TRACE_DEBUG4("%s app_id=%d mdl_handle=0x%x data_size=%d",
+ __FUNCTION__,app_id, mdl_handle, data_size);
+
+ if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if ((p_dcb->p_rx_pkt = (UINT8 *)btif_hl_get_buf(data_size)) != NULL)
+ {
+ memcpy(p_dcb->p_rx_pkt, p_data, data_size);
+ if (p_dcb->p_scb)
+ {
+ BTIF_TRACE_DEBUG4("app_idx=%d mcl_idx=0x%x mdl_idx=0x%x data_size=%d",
+ app_idx, mcl_idx, mdl_idx, data_size);
+ r = send(p_dcb->p_scb->socket_id[1], p_dcb->p_rx_pkt, data_size, 0);
+
+ if (r == data_size)
+ {
+ BTIF_TRACE_DEBUG1("socket send success data_size=%d", data_size);
+ status = BTA_HL_STATUS_OK;
+ }
+ else
+ {
+ BTIF_TRACE_ERROR2("socket send failed r=%d data_size=%d",r, data_size);
+ }
+
+
+ }
+ btif_hl_free_buf((void **) &p_dcb->p_rx_pkt);
+ }
+ }
+
+ bta_hl_ci_put_rx_data(mdl_handle, status, evt);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_get_tx_data
+**
+** Description Get the Echo data to be sent
+**
+** Parameters app_id - HDP application ID
+** mcl_handle - MCL handle
+** buf_size - the size of the buffer
+** p_buf - the buffer pointer
+** evt - the evt to be passed back to the HL in the
+** bta_hl_ci_get_tx_data call-in function
+**
+** Returns Void
+**
+*******************************************************************************/
+void bta_hl_co_get_echo_data (UINT8 app_id, tBTA_HL_MCL_HANDLE mcl_handle,
+ UINT16 buf_size, UINT8 *p_buf, UINT16 evt)
+{
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ BTIF_TRACE_ERROR1("%s not supported",__FUNCTION__);
+ bta_hl_ci_get_echo_data(mcl_handle, status, evt);
+}
+
+
+/*******************************************************************************
+**
+** Function bta_hl_co_put_echo_data
+**
+** Description Put the received loopback echo data
+**
+** Parameters app_id - HDP application ID
+** mcl_handle - MCL handle
+** data_size - the size of the data
+** p_data - the data pointer
+** evt - the evt to be passed back to the HL in the
+** bta_hl_ci_put_echo_data call-in function
+**
+** Returns Void
+**
+*******************************************************************************/
+void bta_hl_co_put_echo_data (UINT8 app_id, tBTA_HL_MCL_HANDLE mcl_handle,
+ UINT16 data_size, UINT8 *p_data, UINT16 evt)
+{
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ BTIF_TRACE_ERROR1("%s not supported",__FUNCTION__);
+ bta_hl_ci_put_echo_data(mcl_handle, status, evt);
+}
+
diff --git a/btif/co/bta_pan_co.c b/btif/co/bta_pan_co.c
new file mode 100644
index 0000000..e78a5f8
--- /dev/null
+++ b/btif/co/bta_pan_co.c
@@ -0,0 +1,334 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: bta_pan_co.c
+ *
+ * Description: PAN stack callout api
+ *
+ *
+ ***********************************************************************************/
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_ci.h"
+#include "bta_pan_co.h"
+#include "pan_api.h"
+#include "gki.h"
+//#include "btui.h"
+//#include "btui_int.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_pan.h>
+#include "btif_pan_internal.h"
+#include "bd.h"
+
+
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define warn(fmt, ...) ALOGW ("## WARNING : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_pan_co_init
+**
+** Description
+**
+**
+** Returns Data flow mask.
+**
+*******************************************************************************/
+UINT8 bta_pan_co_init(UINT8 *q_level)
+{
+
+ ALOGD("bta_pan_co_init");
+
+ /* set the q_level to 30 buffers */
+ *q_level = 30;
+
+ //return (BTA_PAN_RX_PULL | BTA_PAN_TX_PULL);
+ return (BTA_PAN_RX_PUSH_BUF | BTA_PAN_RX_PUSH | BTA_PAN_TX_PULL);
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function bta_pan_co_open
+**
+** Description
+**
+**
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+
+void bta_pan_co_open(UINT16 handle, UINT8 app_id, tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role, BD_ADDR peer_addr)
+{
+ ALOGD("bta_pan_co_open:app_id:%d, local_role:%d, peer_role:%d, handle:%d",
+ app_id, local_role, peer_role, handle);
+ btpan_conn_t* conn = btpan_find_conn_addr(peer_addr);
+ if(conn == NULL)
+ conn = btpan_new_conn(handle, peer_addr, local_role, peer_role);
+ if(conn)
+ {
+ ALOGD("bta_pan_co_open:tap_fd:%d, open_count:%d, conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d",
+ btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, handle, conn->local_role, conn->remote_role);
+ //refresh the role & bt address
+
+ btpan_cb.open_count++;
+ conn->handle = handle;
+ //bdcpy(conn->peer, peer_addr);
+ if(btpan_cb.tap_fd < 0)
+ {
+ btpan_cb.tap_fd = btpan_tap_open();
+ if(btpan_cb.tap_fd >= 0)
+ create_tap_read_thread(btpan_cb.tap_fd);
+ }
+ if(btpan_cb.tap_fd >= 0)
+ {
+ conn->state = PAN_STATE_OPEN;
+ bta_pan_ci_rx_ready(handle);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_co_close
+**
+** Description This function is called by PAN when a connection to a
+** peer is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_co_close(UINT16 handle, UINT8 app_id)
+{
+ ALOGD("bta_pan_co_close:app_id:%d, handle:%d", app_id, handle);
+ btpan_conn_t* conn = btpan_find_conn_handle(handle);
+ if(conn && conn->state == PAN_STATE_OPEN)
+ {
+ ALOGD("bta_pan_co_close");
+
+ // let bta close event reset this handle as it needs
+ // the handle to find the connection upon CLOSE
+ //conn->handle = -1;
+ conn->state = PAN_STATE_CLOSE;
+ btpan_cb.open_count--;
+
+ if(btpan_cb.open_count == 0)
+ {
+ destroy_tap_read_thread();
+ if(btpan_cb.tap_fd != -1)
+ {
+ btpan_tap_close(btpan_cb.tap_fd);
+ btpan_cb.tap_fd = -1;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_co_tx_path
+**
+** Description This function is called by PAN to transfer data on the
+** TX path; that is, data being sent from BTA to the phone.
+** This function is used when the TX data path is configured
+** to use the pull interface. The implementation of this
+** function will typically call Bluetooth stack functions
+** PORT_Read() or PORT_ReadData() to read data from RFCOMM
+** and then a platform-specific function to send data that
+** data to the phone.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_co_tx_path(UINT16 handle, UINT8 app_id)
+{
+ BT_HDR *p_buf;
+ UINT8 i;
+ BD_ADDR src;
+ BD_ADDR dst;
+ UINT16 protocol;
+ BOOLEAN ext;
+ BOOLEAN forward;
+
+ ALOGD("bta_pan_co_tx_path, handle:%d, app_id:%d", handle, app_id);
+
+ btpan_conn_t* conn = btpan_find_conn_handle(handle);
+ if(conn && conn->state != PAN_STATE_OPEN)
+ {
+ ALOGE("bta_pan_co_tx_path: cannot find pan connction or conn is not opened, conn:%p, conn->state:%d", conn, conn->state);
+ return;
+ }
+ do
+ {
+
+ /* read next data buffer from pan */
+ if ((p_buf = bta_pan_ci_readbuf(handle, src, dst, &protocol,
+ &ext, &forward)))
+ {
+ ALOGD("bta_pan_co_tx_path, calling btapp_tap_send, p_buf->len:%d, offset:%d", p_buf->len, p_buf->offset);
+ if(is_empty_eth_addr(conn->eth_addr) && is_valid_bt_eth_addr(src))
+ {
+ ALOGD("pan bt peer addr: %02x:%02x:%02x:%02x:%02x:%02x, update its ethernet addr: %02x:%02x:%02x:%02x:%02x:%02x",
+ conn->peer[0], conn->peer[1], conn->peer[2], conn->peer[3],conn->peer[4], conn->peer[5],
+ src[0], src[1], src[2], src[3],src[4], src[5]);
+ memcpy(conn->eth_addr, src, sizeof(conn->eth_addr));
+
+ }
+ btpan_tap_send(btpan_cb.tap_fd, src, dst, protocol, (char*)(p_buf + 1) + p_buf->offset, p_buf->len, ext, forward);
+ GKI_freebuf(p_buf);
+ }
+
+ } while (p_buf != NULL);
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_co_rx_path
+**
+** Description
+**
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_co_rx_path(UINT16 handle, UINT8 app_id)
+{
+
+
+ UINT8 i;
+
+ ALOGD("bta_pan_co_rx_path not used");
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_co_tx_write
+**
+** Description This function is called by PAN to send data to the phone
+** when the TX path is configured to use a push interface.
+** The implementation of this function must copy the data to
+** the phone's memory.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_co_tx_write(UINT16 handle, UINT8 app_id, BD_ADDR src, BD_ADDR dst, UINT16 protocol, UINT8 *p_data,
+ UINT16 len, BOOLEAN ext, BOOLEAN forward)
+{
+ ALOGD("bta_pan_co_tx_write not used");
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_co_tx_writebuf
+**
+** Description This function is called by PAN to send data to the phone
+** when the TX path is configured to use a push interface with
+** zero copy. The phone must free the buffer using function
+** GKI_freebuf() when it is through processing the buffer.
+**
+**
+** Returns TRUE if flow enabled
+**
+*******************************************************************************/
+void bta_pan_co_tx_writebuf(UINT16 handle, UINT8 app_id, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf,
+ BOOLEAN ext, BOOLEAN forward)
+{
+
+ ALOGD("bta_pan_co_tx_writebuf not used");
+
+
+}
+
+/*******************************************************************************
+**
+** Function bta_pan_co_rx_flow
+**
+** Description This function is called by PAN to enable or disable
+** data flow on the RX path when it is configured to use
+** a push interface. If data flow is disabled the phone must
+** not call bta_pan_ci_rx_write() or bta_pan_ci_rx_writebuf()
+** until data flow is enabled again.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_co_rx_flow(UINT16 handle, UINT8 app_id, BOOLEAN enable)
+{
+
+ ALOGD("bta_pan_co_rx_flow, enabled:%d, not used", enable);
+
+}
+
+
+/*******************************************************************************
+**
+** Function bta_pan_co_filt_ind
+**
+** Description protocol filter indication from peer device
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_co_pfilt_ind(UINT16 handle, BOOLEAN indication, tBTA_PAN_STATUS result,
+ UINT16 len, UINT8 *p_filters)
+{
+ ALOGD("bta_pan_co_pfilt_ind");
+
+}
+/*******************************************************************************
+**
+** Function bta_pan_co_mfilt_ind
+**
+** Description multicast filter indication from peer device
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_pan_co_mfilt_ind(UINT16 handle, BOOLEAN indication, tBTA_PAN_STATUS result,
+ UINT16 len, UINT8 *p_filters)
+{
+
+ ALOGD("bta_pan_co_mfilt_ind");
+}
+
diff --git a/btif/co/bta_sys_co.c b/btif/co/bta_sys_co.c
new file mode 100644
index 0000000..b7768ad
--- /dev/null
+++ b/btif/co/bta_sys_co.c
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+#include "bta_sys.h"
+#include "bta_sys_ci.h"
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_co_enable
+**
+** Description This function is called by the stack to power up the HW
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_hw_co_enable( tBTA_SYS_HW_MODULE module )
+{
+ /* platform specific implementation to power-up the HW */
+
+
+ /* if no client/server asynchronous system like linux-based OS, directly call the ci here */
+ bta_sys_hw_ci_enabled( module );
+}
+
+
+/*******************************************************************************
+**
+** Function bta_sys_hw_co_disable
+**
+** Description This function is called by the stack to power down the HW
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_sys_hw_co_disable( tBTA_SYS_HW_MODULE module )
+{
+ /* platform specific implementation to power-down the HW */
+
+
+ /* if no client/server asynchronous system like linux-based OS, directly call the ci here */
+ bta_sys_hw_ci_disabled( module );
+
+}
diff --git a/btif/include/btif_api.h b/btif/include/btif_api.h
new file mode 100644
index 0000000..c787bec
--- /dev/null
+++ b/btif/include/btif_api.h
@@ -0,0 +1,328 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_api.h
+ *
+ * Description: Main API header file for all BTIF functions accessed
+ * from main bluetooth HAL. All HAL extensions will not
+ * require headerfiles as they would be accessed through
+ * callout/callins.
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_API_H
+#define BTIF_API_H
+
+#include "btif_common.h"
+#include "btif_dm.h"
+
+/*******************************************************************************
+** BTIF CORE API
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_init_bluetooth
+**
+** Description Creates BTIF task and prepares BT scheduler for startup
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_init_bluetooth(void);
+
+/*******************************************************************************
+**
+** Function btif_enable_bluetooth
+**
+** Description Performs chip power on and kickstarts OS scheduler
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_enable_bluetooth(void);
+
+/*******************************************************************************
+**
+** Function btif_disable_bluetooth
+**
+** Description Inititates shutdown of Bluetooth system.
+** Any active links will be dropped and device entering
+** non connectable/discoverable mode
+**
+** Returns void
+**
+*******************************************************************************/
+bt_status_t btif_disable_bluetooth(void);
+
+/*******************************************************************************
+**
+** Function btif_shutdown_bluetooth
+**
+** Description Finalizes BT scheduler shutdown and terminates BTIF
+** task.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+bt_status_t btif_shutdown_bluetooth(void);
+
+/*******************************************************************************
+**
+** Function btif_get_adapter_properties
+**
+** Description Fetches all local adapter properties
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_adapter_properties(void);
+
+/*******************************************************************************
+**
+** Function btif_get_adapter_property
+**
+** Description Fetches property value from local cache
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_adapter_property( bt_property_type_t type);
+
+/*******************************************************************************
+**
+** Function btif_set_adapter_property
+**
+** Description Updates core stack with property value and stores it in
+** local cache
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_set_adapter_property( const bt_property_t *property);
+
+/*******************************************************************************
+**
+** Function btif_get_remote_device_property
+**
+** Description Fetches the remote device property from the NVRAM
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_device_property( bt_bdaddr_t *remote_addr,
+ bt_property_type_t type);
+
+/*******************************************************************************
+**
+** Function btif_get_remote_device_properties
+**
+** Description Fetches all the remote device properties from NVRAM
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_device_properties( bt_bdaddr_t *remote_addr);
+
+/*******************************************************************************
+**
+** Function btif_set_remote_device_property
+**
+** Description Writes the remote device property to NVRAM.
+** Currently, BT_PROPERTY_REMOTE_FRIENDLY_NAME is the only
+** remote device property that can be set
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_set_remote_device_property( bt_bdaddr_t *remote_addr,
+ const bt_property_t *property);
+
+/*******************************************************************************
+**
+** Function btif_get_remote_service_record
+**
+** Description Looks up the service matching uuid on the remote device
+** and fetches the SCN and service_name if the UUID is found
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_service_record( bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid);
+
+
+/*******************************************************************************
+** BTIF DM API
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_dm_start_discovery
+**
+** Description Start device discovery/inquiry
+**
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_start_discovery(void);
+
+/*******************************************************************************
+**
+** Function btif_dm_cancel_discovery
+**
+** Description Cancels search
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_cancel_discovery(void);
+
+/*******************************************************************************
+**
+** Function btif_dm_create_bond
+**
+** Description Initiate bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr);
+
+/*******************************************************************************
+**
+** Function btif_dm_cancel_bond
+**
+** Description Initiate bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t *bd_addr);
+
+/*******************************************************************************
+**
+** Function btif_dm_remove_bond
+**
+** Description Removes bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_remove_bond(const bt_bdaddr_t *bd_addr);
+
+/*******************************************************************************
+**
+** Function btif_dm_pin_reply
+**
+** Description BT legacy pairing - PIN code reply
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_pin_reply( const bt_bdaddr_t *bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t *pin_code);
+
+/*******************************************************************************
+**
+** Function btif_dm_passkey_reply
+**
+** Description BT SSP passkey reply
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_passkey_reply( const bt_bdaddr_t *bd_addr,
+ uint8_t accept, uint32_t passkey);
+
+/*******************************************************************************
+**
+** Function btif_dm_ssp_reply
+**
+** Description BT SSP Reply - Just Works, Numeric Comparison & Passkey Entry
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_ssp_reply( const bt_bdaddr_t *bd_addr,
+ bt_ssp_variant_t variant, uint8_t accept,
+ uint32_t passkey);
+
+/*******************************************************************************
+**
+** Function btif_dm_get_adapter_property
+**
+** Description Queries the BTA for the adapter property
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_get_adapter_property(bt_property_t *prop);
+
+/*******************************************************************************
+**
+** Function btif_dm_get_remote_services
+**
+** Description Start SDP to get remote services
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_get_remote_service_record(bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid);
+
+
+/*******************************************************************************
+**
+** Function btif_dm_get_remote_services
+**
+** Description Start SDP to get remote services
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_get_remote_services(bt_bdaddr_t *remote_addr);
+
+/*******************************************************************************
+**
+** Function btif_dut_mode_configure
+**
+** Description Configure Test Mode - 'enable' to 1 puts the device in test mode and 0 exits
+** test mode
+**
+** Returns BT_STATUS_SUCCESS on success
+**
+*******************************************************************************/
+bt_status_t btif_dut_mode_configure(uint8_t enable);
+
+/*******************************************************************************
+**
+** Function btif_dut_mode_send
+**
+** Description Sends a HCI Vendor specific command to the controller
+**
+** Returns BT_STATUS_SUCCESS on success
+**
+*******************************************************************************/
+bt_status_t btif_dut_mode_send(uint16_t opcode, uint8_t *buf, uint8_t len);
+
+#endif /* BTIF_API_H */
diff --git a/btif/include/btif_av.h b/btif/include/btif_av.h
new file mode 100644
index 0000000..c6bd20a
--- /dev/null
+++ b/btif/include/btif_av.h
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_av.h
+ *
+ * Description: Main API header file for all BTIF AV functions accessed
+ * from internal stack.
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_AV_H
+#define BTIF_AV_H
+
+#include "btif_common.h"
+#include "btif_sm.h"
+#include "bta_av_api.h"
+
+
+/*******************************************************************************
+** Type definitions for callback functions
+********************************************************************************/
+
+typedef enum {
+ /* Reuse BTA_AV_XXX_EVT - No need to redefine them here */
+ BTIF_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT,
+ BTIF_AV_DISCONNECT_REQ_EVT,
+ BTIF_AV_START_STREAM_REQ_EVT,
+ BTIF_AV_STOP_STREAM_REQ_EVT,
+ BTIF_AV_SUSPEND_STREAM_REQ_EVT,
+ BTIF_AV_RECONFIGURE_REQ_EVT,
+} btif_av_sm_event_t;
+
+
+/*******************************************************************************
+** BTIF AV API
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_av_get_sm_handle
+**
+** Description Fetches current av SM handle
+**
+** Returns None
+**
+*******************************************************************************/
+
+btif_sm_handle_t btif_av_get_sm_handle(void);
+
+/*******************************************************************************
+**
+** Function btif_av_stream_ready
+**
+** Description Checks whether AV is ready for starting a stream
+**
+** Returns None
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_stream_ready(void);
+
+/*******************************************************************************
+**
+** Function btif_av_stream_started_ready
+**
+** Description Checks whether AV ready for media start in streaming state
+**
+** Returns None
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_stream_started_ready(void);
+
+/*******************************************************************************
+**
+** Function btif_dispatch_sm_event
+**
+** Description Send event to AV statemachine
+**
+** Returns None
+**
+*******************************************************************************/
+
+/* used to pass events to AV statemachine from other tasks */
+void btif_dispatch_sm_event(btif_av_sm_event_t event, void *p_data, int len);
+
+/*******************************************************************************
+**
+** Function btif_av_init
+**
+** Description Initializes btif AV if not already done
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_av_init(void);
+
+#endif /* BTIF_AV_H */
diff --git a/btif/include/btif_av_api.h b/btif/include/btif_av_api.h
new file mode 100644
index 0000000..86cd40b
--- /dev/null
+++ b/btif/include/btif_av_api.h
@@ -0,0 +1,210 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ **
+ ** Name: btif_av_api.h
+ **
+ ** Description: This is the public interface file for the advanced
+ ** audio/video streaming (AV) subsystem of BTIF, Broadcom's
+ ** Bluetooth application layer for mobile phones.
+ **
+ *****************************************************************************/
+
+#ifndef BTIF_AV_API_H
+#define BTIF_AV_API_H
+
+#include "bt_target.h"
+#include "bta_av_api.h"
+#include "uipc.h"
+
+#include "btif_media.h"
+#include "a2d_api.h"
+#include "a2d_sbc.h"
+
+
+/*****************************************************************************
+ ** Constants and data types
+ *****************************************************************************/
+
+/* Codec type */
+#define BTIF_AV_CODEC_NONE 0xFF
+#define BTIF_AV_CODEC_SBC A2D_MEDIA_CT_SBC /* SBC media codec type */
+
+#define BTIF_AV_CODEC_PCM 0x5 /* Raw PCM */
+
+typedef UINT8 tBTIF_AV_CODEC_ID;
+
+/* AV features masks */
+#define BTIF_AV_FEAT_RCTG BTA_AV_FEAT_RCTG /* remote control target */
+#define BTIF_AV_FEAT_RCCT BTA_AV_FEAT_RCCT /* remote control controller */
+#define BTIF_AV_FEAT_METADATA BTA_AV_FEAT_METADATA /* remote control Metadata Transfer command/response */
+
+typedef UINT16 tBTIF_AV_FEAT;
+
+/* AV channel values */
+#define BTIF_AV_CHNL_MSK BTA_AV_CHNL_MSK
+#define BTIF_AV_CHNL_AUDIO BTA_AV_CHNL_AUDIO /* audio channel */
+#define BTIF_AV_CHNL_VIDEO BTA_AV_CHNL_VIDEO /* video channel */
+typedef UINT8 tBTIF_AV_CHNL;
+
+typedef UINT8 tBTIF_AV_HNDL;
+
+/* Operation id list for BTIF_AvRemoteCmd */
+#define BTIF_AV_ID_SELECT 0x00 /* select */
+#define BTIF_AV_ID_UP 0x01 /* up */
+#define BTIF_AV_ID_DOWN 0x02 /* down */
+#define BTIF_AV_ID_LEFT 0x03 /* left */
+#define BTIF_AV_ID_RIGHT 0x04 /* right */
+#define BTIF_AV_ID_RIGHT_UP 0x05 /* right-up */
+#define BTIF_AV_ID_RIGHT_DOWN 0x06 /* right-down */
+#define BTIF_AV_ID_LEFT_UP 0x07 /* left-up */
+#define BTIF_AV_ID_LEFT_DOWN 0x08 /* left-down */
+#define BTIF_AV_ID_ROOT_MENU 0x09 /* root menu */
+#define BTIF_AV_ID_SETUP_MENU 0x0A /* setup menu */
+#define BTIF_AV_ID_CONT_MENU 0x0B /* contents menu */
+#define BTIF_AV_ID_FAV_MENU 0x0C /* favorite menu */
+#define BTIF_AV_ID_EXIT 0x0D /* exit */
+#define BTIF_AV_ID_0 0x20 /* 0 */
+#define BTIF_AV_ID_1 0x21 /* 1 */
+#define BTIF_AV_ID_2 0x22 /* 2 */
+#define BTIF_AV_ID_3 0x23 /* 3 */
+#define BTIF_AV_ID_4 0x24 /* 4 */
+#define BTIF_AV_ID_5 0x25 /* 5 */
+#define BTIF_AV_ID_6 0x26 /* 6 */
+#define BTIF_AV_ID_7 0x27 /* 7 */
+#define BTIF_AV_ID_8 0x28 /* 8 */
+#define BTIF_AV_ID_9 0x29 /* 9 */
+#define BTIF_AV_ID_DOT 0x2A /* dot */
+#define BTIF_AV_ID_ENTER 0x2B /* enter */
+#define BTIF_AV_ID_CLEAR 0x2C /* clear */
+#define BTIF_AV_ID_CHAN_UP 0x30 /* channel up */
+#define BTIF_AV_ID_CHAN_DOWN 0x31 /* channel down */
+#define BTIF_AV_ID_PREV_CHAN 0x32 /* previous channel */
+#define BTIF_AV_ID_SOUND_SEL 0x33 /* sound select */
+#define BTIF_AV_ID_INPUT_SEL 0x34 /* input select */
+#define BTIF_AV_ID_DISP_INFO 0x35 /* display information */
+#define BTIF_AV_ID_HELP 0x36 /* help */
+#define BTIF_AV_ID_PAGE_UP 0x37 /* page up */
+#define BTIF_AV_ID_PAGE_DOWN 0x38 /* page down */
+#define BTIF_AV_ID_POWER 0x40 /* power */
+#define BTIF_AV_ID_VOL_UP 0x41 /* volume up */
+#define BTIF_AV_ID_VOL_DOWN 0x42 /* volume down */
+#define BTIF_AV_ID_MUTE 0x43 /* mute */
+#define BTIF_AV_ID_PLAY 0x44 /* play */
+#define BTIF_AV_ID_STOP 0x45 /* stop */
+#define BTIF_AV_ID_PAUSE 0x46 /* pause */
+#define BTIF_AV_ID_RECORD 0x47 /* record */
+#define BTIF_AV_ID_REWIND 0x48 /* rewind */
+#define BTIF_AV_ID_FAST_FOR 0x49 /* fast forward */
+#define BTIF_AV_ID_EJECT 0x4A /* eject */
+#define BTIF_AV_ID_FORWARD 0x4B /* forward */
+#define BTIF_AV_ID_BACKWARD 0x4C /* backward */
+#define BTIF_AV_ID_ANGLE 0x50 /* angle */
+#define BTIF_AV_ID_SUBPICT 0x51 /* subpicture */
+#define BTIF_AV_ID_F1 0x71 /* F1 */
+#define BTIF_AV_ID_F2 0x72 /* F2 */
+#define BTIF_AV_ID_F3 0x73 /* F3 */
+#define BTIF_AV_ID_F4 0x74 /* F4 */
+#define BTIF_AV_ID_F5 0x75 /* F5 */
+#define BTIF_AV_ID_VENDOR 0x7E /* vendor unique */
+#define BTIF_AV_KEYPRESSED_RELEASE 0x80
+
+typedef UINT8 tBTIF_AV_RC;
+
+/* State flag for pass through command */
+#define BTIF_AV_STATE_PRESS 0 /* key pressed */
+#define BTIF_AV_STATE_RELEASE 1 /* key released */
+
+typedef UINT8 tBTIF_AV_STATE;
+
+typedef UINT8 tBTIF_AV_RC_HNDL;
+
+/* Command codes for BTIF_AvVendorCmd */
+#define BTIF_AV_CMD_CTRL 0
+#define BTIF_AV_CMD_STATUS 1
+#define BTIF_AV_CMD_SPEC_INQ 2
+#define BTIF_AV_CMD_NOTIF 3
+#define BTIF_AV_CMD_GEN_INQ 4
+
+typedef UINT8 tBTIF_AV_CMD;
+
+/* AV callback events */
+#define BTIF_AV_OPEN_EVT 0 /* connection opened */
+#define BTIF_AV_CLOSE_EVT 1 /* connection closed */
+#define BTIF_AV_START_EVT 2 /* stream data transfer started */
+#define BTIF_AV_STOP_EVT 3 /* stream data transfer stopped */
+#define BTIF_AV_RC_OPEN_EVT 4 /* remote control channel open */
+#define BTIF_AV_RC_CLOSE_EVT 5 /* remote control channel closed */
+#define BTIF_AV_REMOTE_CMD_EVT 6 /* remote control command */
+#define BTIF_AV_REMOTE_RSP_EVT 7 /* remote control response */
+#define BTIF_AV_META_MSG_EVT 8 /* metadata messages */
+
+typedef UINT8 tBTIF_AV_EVT;
+
+#define BTIF_AV_FEEDING_ASYNCHRONOUS 0 /* asynchronous feeding, use tx av timer */
+#define BTIF_AV_FEEDING_SYNCHRONOUS 1 /* synchronous feeding, no av tx timer */
+
+#define BTIF_AV_MAX_SYNCHRONOUS_LATENCY 80 /* max latency in ms for BTIF_AV_FEEDING_SYNCHRONOUS */
+#define BTIF_AV_MIN_SYNCHRONOUS_LATENCY 4 /* min latency in ms for BTIF_AV_FEEDING_SYNCHRONOUS */
+
+typedef UINT8 tBTIF_AV_FEEDING_MODE;
+
+#define BTIF_AV_CHANNEL_MODE_MONO A2D_SBC_IE_CH_MD_MONO
+#define BTIF_AV_CHANNEL_MODE_STEREO A2D_SBC_IE_CH_MD_STEREO
+#define BTIF_AV_CHANNEL_MODE_JOINT A2D_SBC_IE_CH_MD_JOINT
+#define BTIF_AV_CHANNEL_MODE_DUAL A2D_SBC_IE_CH_MD_DUAL
+
+typedef UINT8 tBTIF_AV_CHANNEL_MODE;
+
+/**
+ * Structure used to configure the AV codec capabilities/config
+ */
+typedef struct
+{
+ tBTIF_AV_CODEC_ID id; /* Codec ID (in terms of BTIF) */
+ UINT8 info[AVDT_CODEC_SIZE]; /* Codec info (can be config or capabilities) */
+} tBTIF_AV_CODEC_INFO;
+
+/**
+ * Structure used to configure the AV media feeding
+ */
+typedef struct
+{
+ UINT16 sampling_freq; /* 44100, 48000 etc */
+ UINT16 num_channel; /* 1 for mono or 2 stereo */
+ UINT8 bit_per_sample; /* Number of bits per sample (8, 16) */
+} tBTIF_AV_MEDIA_FEED_CFG_PCM;
+
+typedef union
+{
+ tBTIF_AV_MEDIA_FEED_CFG_PCM pcm; /* Raw PCM feeding format */
+}tBTIF_AV_MEDIA_FEED_CFG;
+
+typedef struct
+{
+ tBTIF_AV_CODEC_ID format; /* Media codec identifier */
+ tBTIF_AV_MEDIA_FEED_CFG cfg; /* Media codec configuration */
+} tBTIF_AV_MEDIA_FEEDINGS;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTIF_AV_API_H */
diff --git a/btif/include/btif_av_co.h b/btif/include/btif_av_co.h
new file mode 100644
index 0000000..20e9a1e
--- /dev/null
+++ b/btif/include/btif_av_co.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_AV_CO_H
+#define BTIF_AV_CO_H
+
+#include "btif_media.h"
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+enum
+{
+ BTIF_SV_AV_AA_SBC_INDEX = 0,
+ BTIF_SV_AV_AA_SEP_INDEX /* Last index */
+};
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_is_active
+ **
+ ** Description Get the current configuration of content protection
+ **
+ ** Returns TRUE if the current streaming has CP, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_cp_is_active(void);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_get_flag
+ **
+ ** Description Get content protection flag
+ ** BTA_AV_CP_SCMS_COPY_NEVER
+ ** BTA_AV_CP_SCMS_COPY_ONCE
+ ** BTA_AV_CP_SCMS_COPY_FREE
+ **
+ ** Returns The current flag value
+ **
+ *******************************************************************************/
+UINT8 bta_av_co_cp_get_flag(void);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_set_flag
+ **
+ ** Description Set content protection flag
+ ** BTA_AV_CP_SCMS_COPY_NEVER
+ ** BTA_AV_CP_SCMS_COPY_ONCE
+ ** BTA_AV_CP_SCMS_COPY_FREE
+ **
+ ** Returns TRUE if setting the SCMS flag is supported else FALSE
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_codec_reset
+ **
+ ** Description Reset the current codec configuration
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void bta_av_co_audio_codec_reset(void);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_codec_supported
+ **
+ ** Description Check if all opened connections are compatible with a codec
+ ** configuration
+ **
+ ** Returns TRUE if all opened devices support this codec, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_codec_supported(tBTIF_STATUS *p_status);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_set_codec
+ **
+ ** Description Set the current codec configuration from the feeding type.
+ ** This function is starting to modify the configuration, it
+ ** should be protected.
+ **
+ ** Returns TRUE if successful, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_set_codec(const tBTIF_AV_MEDIA_FEEDINGS *p_feeding, tBTIF_STATUS *p_status);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_get_sbc_config
+ **
+ ** Description Retrieves the SBC codec configuration. If the codec in use
+ ** is not SBC, return the default SBC codec configuration.
+ **
+ ** Returns TRUE if codec is SBC, FALSE otherwise
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_audio_get_sbc_config(tA2D_SBC_CIE *p_sbc_config, UINT16 *p_minmtu);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_discard_config
+ **
+ ** Description Discard the codec configuration of a connection
+ **
+ ** Returns Nothing
+ **
+ *******************************************************************************/
+void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_init
+ **
+ ** Description Initialization
+ **
+ ** Returns Nothing
+ **
+ *******************************************************************************/
+void bta_av_co_init(void);
+
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_peer_cp_supported
+ **
+ ** Description Checks if the peer supports CP
+ **
+ ** Returns TRUE if the peer supports CP
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_get_remote_bitpool_pref
+ **
+ ** Description Check if remote side did a setconfig within the limits
+ ** of our exported bitpool range. If set we will set the
+ ** remote preference.
+ **
+ ** Returns TRUE if config set, FALSE otherwize
+ **
+ *******************************************************************************/
+BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max);
+
+#endif
diff --git a/btif/include/btif_common.h b/btif/include/btif_common.h
new file mode 100644
index 0000000..7f3b039
--- /dev/null
+++ b/btif/include/btif_common.h
@@ -0,0 +1,183 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_COMMON_H
+#define BTIF_COMMON_H
+
+#include "data_types.h"
+#include "bt_types.h"
+#include "bta_api.h"
+
+#ifndef LOG_TAG
+#error "LOG_TAG not defined, please add in .c file prior to including bt_common.h"
+#endif
+
+#include <utils/Log.h>
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define ASSERTC(cond, msg, val) if (!(cond)) { ALOGE( \
+ "### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
+
+/* Calculate start of event enumeration; id is top 8 bits of event */
+#define BTIF_SIG_START(id) ((id) << 8)
+
+/* For upstream the MSB bit is always SET */
+#define BTIF_SIG_CB_BIT (0x8000)
+#define BTIF_SIG_CB_START(id) (((id) << 8) | BTIF_SIG_CB_BIT)
+
+/* BTIF sub-systems */
+#define BTIF_CORE 0
+#define BTIF_DM 1
+#define BTIF_HFP 2
+#define BTIF_AV 3
+#define BTIF_PAN 4
+
+extern bt_callbacks_t *bt_hal_cbacks;
+
+#define HAL_CBACK(P_CB, P_CBACK, ...)\
+ if (P_CB && P_CB->P_CBACK) { \
+ ALOGD("HAL %s->%s", #P_CB, #P_CBACK); \
+ P_CB->P_CBACK(__VA_ARGS__); \
+ } \
+ else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ }
+
+/**
+ * BTIF events for requests that require context switch to btif task
+ * on downstreams path
+ */
+enum
+{
+ BTIF_CORE_API_START = BTIF_SIG_START(BTIF_CORE),
+ BTIF_CORE_STORAGE_NO_ACTION,
+ BTIF_CORE_STORAGE_ADAPTER_WRITE,
+ BTIF_CORE_STORAGE_ADAPTER_READ,
+ BTIF_CORE_STORAGE_ADAPTER_READ_ALL,
+ BTIF_CORE_STORAGE_REMOTE_WRITE,
+ BTIF_CORE_STORAGE_REMOTE_READ,
+ BTIF_CORE_STORAGE_REMOTE_READ_ALL,
+ BTIF_CORE_STORAGE_READ_ALL,
+ BTIF_CORE_STORAGE_NOTIFY_STATUS,
+ /* add here */
+
+ BTIF_DM_API_START = BTIF_SIG_START(BTIF_DM),
+ BTIF_DM_ENABLE_SERVICE,
+ BTIF_DM_DISABLE_SERVICE,
+ /* add here */
+
+ BTIF_HFP_API_START = BTIF_SIG_START(BTIF_HFP),
+ /* add here */
+
+ BTIF_AV_API_START = BTIF_SIG_START(BTIF_AV),
+ /* add here */
+};
+
+/**
+ * BTIF events for callbacks that require context switch to btif task
+ * on upstream path - Typically these would be non-BTA events
+ * that are generated by the BTIF layer.
+ */
+enum
+{
+ BTIF_CORE_CB_START = BTIF_SIG_CB_START(BTIF_CORE),
+ /* add here */
+
+ BTIF_DM_CB_START = BTIF_SIG_CB_START(BTIF_DM),
+ BTIF_DM_CB_DISCOVERY_STARTED, /* Discovery has started */
+ BTIF_DM_CB_CREATE_BOND, /* Create bond */
+ BTIF_DM_CB_REMOVE_BOND, /*Remove bond */
+ BTIF_DM_CB_HID_REMOTE_NAME, /* Remote name callback for HID device */
+ BTIF_DM_CB_BOND_STATE_BONDING,
+
+ BTIF_HFP_CB_START = BTIF_SIG_CB_START(BTIF_HFP),
+ BTIF_HFP_CB_AUDIO_CONNECTING, /* HF AUDIO connect has been sent to BTA successfully */
+
+ BTIF_PAN_CB_START = BTIF_SIG_CB_START(BTIF_PAN),
+ BTIF_PAN_CB_DISCONNECTING, /* PAN Disconnect has been sent to BTA successfully */
+};
+
+/* Macro definitions for BD ADDR persistence */
+
+/**
+ * PROPERTY_BT_BDADDR_PATH
+ * The property key stores the storage location of Bluetooth Device Address
+ */
+#ifndef PROPERTY_BT_BDADDR_PATH
+#define PROPERTY_BT_BDADDR_PATH "ro.bt.bdaddr_path"
+#endif
+
+/**
+ * PERSIST_BDADDR_PROPERTY
+ * If there is no valid bdaddr available from PROPERTY_BT_BDADDR_PATH,
+ * generating a random BDADDR and keeping it in the PERSIST_BDADDR_DROP.
+ */
+#ifndef PERSIST_BDADDR_PROPERTY
+#define PERSIST_BDADDR_PROPERTY "persist.service.bdroid.bdaddr"
+#endif
+
+#define FACTORY_BT_BDADDR_STORAGE_LEN 17
+
+
+/*******************************************************************************
+** Type definitions for callback functions
+********************************************************************************/
+
+typedef void (tBTIF_CBACK) (UINT16 event, char *p_param);
+typedef void (tBTIF_COPY_CBACK) (UINT16 event, char *p_dest, char *p_src);
+
+
+/*******************************************************************************
+** Type definitions and return values
+********************************************************************************/
+
+/* this type handles all btif context switches between BTU and HAL */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTIF_CBACK* p_cb; /* context switch callback */
+
+ /* parameters passed to callback */
+ UINT16 event; /* message event id */
+ char p_param[0]; /* parameter area needs to be last */
+} tBTIF_CONTEXT_SWITCH_CBACK;
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, UINT16 event, char* p_params,
+ int param_len, tBTIF_COPY_CBACK *p_copy_cback);
+tBTA_SERVICE_MASK btif_get_enabled_services_mask(void);
+bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id);
+bt_status_t btif_disable_service(tBTA_SERVICE_ID service_id);
+int btif_is_enabled(void);
+
+/**
+ * BTIF_Events
+ */
+void btif_enable_bluetooth_evt(tBTA_STATUS status, BD_ADDR local_bd);
+void btif_disable_bluetooth_evt(void);
+void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props, bt_property_t *p_props);
+void btif_remote_properties_evt(bt_status_t status, bt_bdaddr_t *remote_addr,
+ uint32_t num_props, bt_property_t *p_props);
+#endif /* BTIF_COMMON_H */
diff --git a/btif/include/btif_config.h b/btif/include/btif_config.h
new file mode 100644
index 0000000..8fc9eb2
--- /dev/null
+++ b/btif/include/btif_config.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_config.h
+ *
+ * Description: Bluetooth configuration Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_CONFIG_H
+#define BTIF_CONFIG_H
+
+#ifdef __cplusplus
+#include <stdint.h>
+extern "C" {
+#endif
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define BTIF_CFG_TYPE_INVALID 0
+#define BTIF_CFG_TYPE_STR 1
+#define BTIF_CFG_TYPE_INT (1 << 1)
+#define BTIF_CFG_TYPE_BIN (1 << 2)
+#define BTIF_CFG_TYPE_VOLATILE (1 << 15)
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+int btif_config_init();
+
+int btif_config_exist(const char* section, const char* key, const char* name);
+int btif_config_get_int(const char* section, const char* key, const char* name, int* value);
+int btif_config_set_int(const char* section, const char* key, const char* name, int value);
+int btif_config_get_str(const char* section, const char* key, const char* name, char* value, int* bytes);
+int btif_config_set_str(const char* section, const char* key, const char* name, const char* value);
+
+int btif_config_get(const char* section, const char* key, const char* name, char* value, int* bytes, int* type);
+int btif_config_set(const char* section, const char* key, const char* name, const char* value, int bytes, int type);
+
+int btif_config_remove(const char* section, const char* key, const char* name);
+
+short btif_config_next_key(short current_key_pos, const char* section, char * key_name, int* key_name_bytes);
+short btif_config_next_value(short pos, const char* section, const char* key, char* value_name, int* value_name_bytes);
+
+typedef void (*btif_config_enum_callback)(void* user_data, const char* section, const char* key, const char* name,
+ const char* value, int bytes, int type);
+int btif_config_enum(btif_config_enum_callback cb, void* user_data);
+
+int btif_config_save();
+void btif_config_flush();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/btif/include/btif_config_util.h b/btif/include/btif_config_util.h
new file mode 100644
index 0000000..3a2f53e
--- /dev/null
+++ b/btif/include/btif_config_util.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_config_util.h
+ *
+ * Description: Bluetooth configuration utility api
+ *
+ ***********************************************************************************/
+
+#ifndef BTIF_CONFIG_UTIL_H
+#define BTIF_CONFIG_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define BLUEZ_PATH "/data/misc/bluetoothd/"
+#define BLUEZ_PATH_BAK "/data/misc/bluetoothd_bak"
+#define BLUEZ_LINKKEY "linkkeys"
+#define BLUEZ_NAMES "names"
+#define BLUEZ_PROFILES "profiles"
+#define BLUEZ_CLASSES "classes"
+#define BLUEZ_TYPES "types"
+#define BLUEZ_CONFIG "config"
+#define BLUEZ_ALIASES "aliases"
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+int btif_config_save_file(const char* file_name);
+int btif_config_load_file(const char* file_name);
+int load_bluez_adapter_info(char* adapter_path, int size);
+int load_bluez_linkkeys(const char* adapter_path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h
new file mode 100644
index 0000000..2d73c45
--- /dev/null
+++ b/btif/include/btif_dm.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_DM_H
+#define BTIF_DM_H
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+/**
+ * BTIF callback to switch context from bte to btif
+ */
+void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data);
+
+/**
+ * Notify BT disable being initiated. DM may chose to abort
+ * pending commands, like pairing
+ */
+void btif_dm_on_disable(void);
+
+/**
+ * Out-of-band functions
+ */
+#if (BTM_OOB_INCLUDED == TRUE)
+void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA *p_oob_data);
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void);
+void btif_dm_proc_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r);
+BOOLEAN btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r);
+#endif /* BTIF_DM_OOB_TEST */
+#endif /* BTM_OOB_INCLUDED */
+
+#endif
diff --git a/btif/include/btif_hh.h b/btif/include/btif_hh.h
new file mode 100644
index 0000000..4f31002
--- /dev/null
+++ b/btif/include/btif_hh.h
@@ -0,0 +1,102 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HH_H
+#define BTIF_HH_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hh.h>
+#include <stdint.h>
+#include "bta_hh_api.h"
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define BTIF_HH_MAX_HID 8
+#define BTIF_HH_MAX_ADDED_DEV 32
+
+#define BTIF_HH_MAX_KEYSTATES 3
+#define BTIF_HH_KEYSTATE_MASK_NUMLOCK 0x01
+#define BTIF_HH_KEYSTATE_MASK_CAPSLOCK 0x02
+#define BTIF_HH_KEYSTATE_MASK_SCROLLLOCK 0x04
+
+
+/*******************************************************************************
+** Type definitions and return values
+********************************************************************************/
+
+typedef enum
+{
+ BTIF_HH_DISABLED = 0,
+ BTIF_HH_ENABLED,
+ BTIF_HH_DISABLING,
+ BTIF_HH_DEV_UNKNOWN,
+ BTIF_HH_DEV_CONNECTING,
+ BTIF_HH_DEV_CONNECTED,
+ BTIF_HH_DEV_DISCONNECTED
+} BTIF_HH_STATUS;
+
+typedef struct
+{
+ bthh_connection_state_t dev_status;
+ UINT8 dev_handle;
+ bt_bdaddr_t bd_addr;
+ tBTA_HH_ATTR_MASK attr_mask;
+ UINT8 sub_class;
+ UINT8 app_id;
+ int fd;
+ BT_HDR *p_buf;
+} btif_hh_device_t;
+
+/* Control block to maintain properties of devices */
+typedef struct
+{
+ UINT8 dev_handle;
+ bt_bdaddr_t bd_addr;
+ tBTA_HH_ATTR_MASK attr_mask;
+} btif_hh_added_device_t;
+
+/**
+ * BTIF-HH control block to maintain added devices and currently
+ * connected hid devices
+ */
+typedef struct
+{
+ BTIF_HH_STATUS status;
+ btif_hh_device_t devices[BTIF_HH_MAX_HID];
+ UINT32 device_num;
+ btif_hh_added_device_t added_devices[BTIF_HH_MAX_ADDED_DEV];
+ btif_hh_device_t *p_curr_dev;
+} btif_hh_cb_t;
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+extern btif_hh_cb_t btif_hh_cb;
+
+extern btif_hh_device_t *btif_hh_find_connected_dev_by_handle(UINT8 handle);
+extern void btif_hh_remove_device(bt_bdaddr_t bd_addr);
+extern bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t *bd_addr);
+extern void btif_hh_disconnect(bt_bdaddr_t *bd_addr);
+
+BOOLEAN btif_hh_add_added_dev(bt_bdaddr_t bd_addr, tBTA_HH_ATTR_MASK attr_mask);
+
+#endif
diff --git a/btif/include/btif_hl.h b/btif/include/btif_hl.h
new file mode 100644
index 0000000..0573082
--- /dev/null
+++ b/btif/include/btif_hl.h
@@ -0,0 +1,366 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HL_H
+#define BTIF_HL_H
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define BTIF_HL_DATA_TYPE_NONE 0x0000
+#define BTIF_HL_DATA_TYPE_PULSE_OXIMETER 0x1004 /* from BT assigned number */
+#define BTIF_HL_DATA_TYPE_BLOOD_PRESSURE_MON 0x1007
+#define BTIF_HL_DATA_TYPE_BODY_THERMOMETER 0x1008
+#define BTIF_HL_DATA_TYPE_BODY_WEIGHT_SCALE 0x100F
+#define BTIF_HL_DATA_TYPE_GLUCOSE_METER 0x1011
+#define BTIF_HL_DATA_TYPE_STEP_COUNTER 0x1068
+
+#define BTIF_HL_CCH_NUM_FILTER_ELEMS 3
+#define BTIF_HL_APPLICATION_NAME_LEN 512
+
+#define BTIF_HL_NV_MAX_APPS 16
+
+
+/*******************************************************************************
+** Type definitions and return values
+********************************************************************************/
+
+typedef enum
+{
+ BTIF_HL_SOC_STATE_IDLE,
+ BTIF_HL_SOC_STATE_W4_ADD,
+ BTIF_HL_SOC_STATE_W4_CONN,
+ BTIF_HL_SOC_STATE_W4_READ,
+ BTIF_HL_SOC_STATE_W4_REL
+} btif_hl_soc_state_t;
+
+typedef enum
+{
+ BTIF_HL_STATE_DISABLED,
+ BTIF_HL_STATE_DISABLING,
+ BTIF_HL_STATE_ENABLED,
+ BTIF_HL_STATE_ENABLING,
+} btif_hl_state_t;
+
+typedef enum
+{
+ BTIF_HL_CCH_OP_NONE,
+ BTIF_HL_CCH_OP_MDEP_FILTERING,
+ BTIF_HL_CCH_OP_MATCHED_CTRL_PSM,
+ BTIF_HL_CCH_OP_DCH_OPEN,
+ BTIF_HL_CCH_OP_DCH_RECONNECT,
+ BTIF_HL_CCH_OP_DCH_ECHO_TEST
+} btif_hl_cch_op_t;
+
+typedef enum
+{
+ BTIF_HL_PEND_DCH_OP_NONE,
+ BTIF_HL_PEND_DCH_OP_DELETE_MDL,
+ BTIF_HL_PEND_DCH_OP_OPEN,
+ BTIF_HL_PEND_DCH_OP_RECONNECT
+} btif_hl_pend_dch_op_t;
+
+typedef enum
+{
+ BTIF_HL_DCH_OP_NONE,
+ BTIF_HL_DCH_OP_DISC
+} btif_hl_dch_op_t;
+
+typedef enum
+{
+ BTIF_HL_CHAN_CB_STATE_NONE,
+ BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING,
+ BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING,
+
+ BTIF_HL_CHAN_CB_STATE_DISCONNECTING_PENDING,
+ BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING,
+ BTIF_HL_CHAN_CB_STATE_DESTROYED_PENDING,
+} btif_hl_chan_cb_state_t;
+
+enum
+{
+ BTIF_HL_SEND_CONNECTED_CB,
+ BTIF_HL_SEND_DISCONNECTED_CB,
+ BTIF_HL_REG_APP,
+ BTIF_HL_UNREG_APP,
+ BTIF_HL_UPDATE_MDL,
+};
+
+typedef struct
+{
+ UINT8 mdep_cfg_idx;
+ int data_type;
+ tBTA_HL_MDEP_ID peer_mdep_id;
+} btif_hl_extra_mdl_cfg_t;
+
+typedef struct
+{
+ tBTA_HL_MDL_CFG base;
+ btif_hl_extra_mdl_cfg_t extra;
+} btif_hl_mdl_cfg_t;
+
+typedef struct
+{
+ btif_hl_mdl_cfg_t mdl_cfg[BTA_HL_NUM_MDL_CFGS];
+} btif_hl_nv_mdl_data_t;
+
+typedef struct
+{
+ tBTA_HL_SUP_FEATURE sup_feature;
+ tBTA_HL_DCH_CFG channel_type[BTA_HL_NUM_MDEPS];
+ char srv_name[BTA_SERVICE_NAME_LEN +1];
+ char srv_desp[BTA_SERVICE_DESP_LEN +1];
+ char provider_name[BTA_PROVIDER_NAME_LEN +1];
+ char application_name[BTIF_HL_APPLICATION_NAME_LEN +1];
+} btif_hl_nv_app_data_t;
+
+typedef struct
+{
+ BOOLEAN in_use;
+ UINT16 use_freq;
+} btif_hl_nv_app_t;
+
+typedef struct
+{
+ btif_hl_nv_app_t app[BTIF_HL_NV_MAX_APPS];
+} btif_hl_nv_app_cb_t;
+
+typedef struct
+{
+ UINT8 app_nv_idx;
+ BOOLEAN active;
+ UINT8 app_idx;
+ btif_hl_nv_app_data_t app_data;
+} btif_hl_app_data_t;
+
+typedef struct
+{
+ BOOLEAN is_app_read;
+ btif_hl_nv_app_cb_t app_cb;
+ BUFFER_Q app_queue;
+} btif_hl_nv_cb_t;
+
+typedef struct
+{
+ int channel_id;
+ BD_ADDR bd_addr;
+ UINT8 mdep_cfg_idx;
+ int max_s;
+ int socket_id[2];
+ UINT8 app_idx;
+ UINT8 mcl_idx;
+ UINT8 mdl_idx;
+ btif_hl_soc_state_t state;
+}btif_hl_soc_cb_t;
+
+typedef struct
+{
+ UINT16 data_type;
+ UINT16 max_tx_apdu_size;
+ UINT16 max_rx_apdu_size;
+} btif_hl_data_type_cfg_t;
+
+typedef struct
+{
+ UINT16 data_type;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+} btif_hl_filter_elem_t;
+
+typedef struct
+{
+ UINT8 num_elems;
+ btif_hl_filter_elem_t elem[BTIF_HL_CCH_NUM_FILTER_ELEMS];
+} btif_hl_cch_filter_t;
+
+typedef struct
+{
+ BOOLEAN in_use;
+ UINT16 mdl_id;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ btif_hl_dch_op_t dch_oper;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ UINT8 local_mdep_cfg_idx;
+ tBTA_HL_DCH_CFG local_cfg;
+ tBTA_HL_MDEP_ID peer_mdep_id;
+ UINT16 peer_data_type;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+ tBTA_HL_DCH_MODE dch_mode;
+ tBTA_SEC sec_mask;
+ BOOLEAN is_the_first_reliable;
+ BOOLEAN delete_mdl;
+ UINT16 mtu;
+ tMCA_CHNL_CFG chnl_cfg;
+ UINT16 tx_size;
+ UINT8 *p_tx_pkt;
+ UINT8 *p_rx_pkt;
+ BOOLEAN cong;
+ btif_hl_soc_cb_t *p_scb;
+ int channel_id;
+} btif_hl_mdl_cb_t;
+
+typedef struct
+{
+ int channel_id;
+ int mdep_cfg_idx;
+ BOOLEAN in_use;
+ btif_hl_chan_cb_state_t cb_state;
+ btif_hl_pend_dch_op_t op;
+ BD_ADDR bd_addr;
+ BOOLEAN abort_pending;
+} btif_hl_pending_chan_cb_t;
+
+typedef struct
+{
+ btif_hl_mdl_cb_t mdl[BTA_HL_NUM_MDLS_PER_MCL];
+ BOOLEAN in_use;
+ BOOLEAN is_connected;
+ UINT16 req_ctrl_psm;
+ UINT16 ctrl_psm;
+ UINT16 data_psm;
+ BD_ADDR bd_addr;
+ UINT16 cch_mtu;
+ tBTA_SEC sec_mask;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ btif_hl_pending_chan_cb_t pcb;
+ BOOLEAN valid_sdp_idx;
+ UINT8 sdp_idx;
+ tBTA_HL_SDP sdp;
+ btif_hl_cch_op_t cch_oper;
+ BOOLEAN cch_timer_active;
+ TIMER_LIST_ENT cch_timer;
+} btif_hl_mcl_cb_t;
+
+typedef struct
+{
+ BOOLEAN active;
+ UINT16 mdl_id;
+ UINT8 mdep_cfg_idx;
+ BD_ADDR bd_addr;
+ int channel_id;
+} btif_hl_delete_mdl_t;
+
+typedef struct
+{
+ btif_hl_mcl_cb_t mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */
+ BOOLEAN in_use; /* this CB is in use*/
+ BOOLEAN reg_pending;
+ BOOLEAN is_new_app;
+ UINT8 app_nv_idx;
+ UINT8 app_id;
+
+ tBTA_HL_SUP_FEATURE sup_feature;
+ tBTA_HL_DCH_CFG channel_type[BTA_HL_NUM_MDEPS];
+ tBTA_HL_SDP_INFO_IND sdp_info_ind;
+ btif_hl_cch_filter_t filter;
+
+ btif_hl_mdl_cfg_t mdl_cfg[BTA_HL_NUM_MDL_CFGS];
+ int mdl_cfg_channel_id[BTA_HL_NUM_MDL_CFGS];
+
+ btif_hl_delete_mdl_t delete_mdl;
+ tBTA_HL_DEVICE_TYPE dev_type;
+ tBTA_HL_APP_HANDLE app_handle;
+ UINT16 sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+ char srv_name[BTA_SERVICE_NAME_LEN +1]; /* service name to be used in the SDP; null terminated*/
+ char srv_desp[BTA_SERVICE_DESP_LEN +1]; /* service description to be used in the SDP; null terminated */
+ char provider_name[BTA_PROVIDER_NAME_LEN +1]; /* provide name to be used in the SDP; null terminated */
+ char application_name[BTIF_HL_APPLICATION_NAME_LEN +1]; /* applicaiton name */
+} btif_hl_app_cb_t;
+
+typedef struct
+{
+ BOOLEAN in_use;
+ UINT8 app_idx;
+} btif_hl_pending_reg_cb_t;
+
+/* BTIF-HL control block */
+typedef struct
+{
+ btif_hl_app_cb_t acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */
+ tBTA_HL_CTRL_CBACK *p_ctrl_cback; /* pointer to control callback function */
+ UINT8 next_app_id;
+ UINT16 next_channel_id;
+ btif_hl_state_t state;
+ btif_hl_nv_cb_t ncb;
+} btif_hl_cb_t;
+
+typedef UINT8 btif_hl_evt_t;
+
+typedef struct
+{
+ int app_id;
+ BD_ADDR bd_addr;
+ int mdep_cfg_index;
+ int channel_id;
+ btif_hl_chan_cb_state_t cb_state;
+ int fd;
+} btif_hl_send_chan_state_cb_t;
+
+
+typedef struct
+{
+ UINT8 app_idx;
+} btif_hl_reg_t;
+
+typedef btif_hl_reg_t btif_hl_unreg_t;
+typedef btif_hl_reg_t btif_hl_update_mdl_t;
+
+typedef union
+{
+ btif_hl_send_chan_state_cb_t chan_cb;
+ btif_hl_reg_t reg;
+ btif_hl_unreg_t unreg;
+ btif_hl_update_mdl_t update_mdl;
+} btif_hl_evt_cb_t;
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+#define BTIF_HL_GET_CB_PTR() &(btif_hl_cb)
+#define BTIF_HL_GET_APP_CB_PTR(app_idx) &(btif_hl_cb.acb[(app_idx)])
+#define BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) &(btif_hl_cb.acb[(app_idx)].mcb[(mcl_idx)])
+#define BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) &(btif_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[mdl_idx])
+#define BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx) &(btif_hl_cb.acb[app_idx].mcb[mcl_idx].pcb)
+#define BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx) &(btif_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)])
+#define BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, item_idx) &(btif_hl_cb.acb[(app_idx)].mdl_cfg_channel_id[(item_idx)])
+
+extern btif_hl_cb_t btif_hl_cb;
+extern btif_hl_cb_t *p_btif_hl_cb;
+extern btif_hl_nv_cb_t *p_ncb;
+
+extern BOOLEAN btif_hl_find_mcl_idx(UINT8 app_idx, BD_ADDR p_bd_addr, UINT8 *p_mcl_idx);
+extern BOOLEAN btif_hl_find_app_idx(UINT8 app_id, UINT8 *p_app_idx);
+extern BOOLEAN btif_hl_find_avail_mcl_idx(UINT8 app_idx, UINT8 *p_mcl_idx);
+extern BOOLEAN btif_hl_find_avail_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_idx);
+extern BOOLEAN btif_hl_find_mcl_idx_using_handle( tBTA_HL_MCL_HANDLE mcl_handle,
+ UINT8 *p_app_idx, UINT8 *p_mcl_idx);
+extern BOOLEAN btif_hl_save_mdl_cfg(UINT8 app_id, UINT8 item_idx, tBTA_HL_MDL_CFG *p_mdl_cfg);
+extern BOOLEAN btif_hl_delete_mdl_cfg(UINT8 app_id, UINT8 item_idx);
+extern void * btif_hl_get_buf(UINT16 size);
+extern void btif_hl_free_buf(void **p);
+extern BOOLEAN btif_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT8 *p_app_idx,UINT8 *p_mcl_idx,
+ UINT8 *p_mdl_idx);
+extern void btif_hl_abort_pending_chan_setup(UINT8 app_idx, UINT8 mcl_idx);
+extern BOOLEAN btif_hl_proc_pending_op(UINT8 app_idx, UINT8 mcl_idx);
+extern BOOLEAN btif_hl_load_mdl_config (UINT8 app_id, UINT8 buffer_size,
+ tBTA_HL_MDL_CFG *p_mdl_buf );
+#endif
diff --git a/btif/include/btif_media.h b/btif/include/btif_media.h
new file mode 100644
index 0000000..b3b72e7
--- /dev/null
+++ b/btif/include/btif_media.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_media.h
+ *
+ * Description: This is the audio module for the BTIF system.
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_MEDIA_H
+#define BTIF_MEDIA_H
+
+#include "bta_api.h"
+#include "bd.h"
+#include "gki.h"
+#include "btif_av_api.h"
+#include "audio_a2dp_hw.h"
+
+/*******************************************************************************
+ ** Constants
+ *******************************************************************************/
+
+/* Generic part */
+#define BTIF_SUCCESS 0
+
+/**
+ * AV (Audio Video source) Errors
+ */
+#define BTIF_ERROR_SRV_AV_NOT_ENABLED 700 /* AV is not enabled */
+#define BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED 701 /* Requested Feeding not supported */
+#define BTIF_ERROR_SRV_AV_BUSY 702 /* Another operation ongoing */
+#define BTIF_ERROR_SRV_AV_NOT_OPENED 703 /* No AV link opened */
+#define BTIF_ERROR_SRV_AV_NOT_STARTED 704 /* AV is not started */
+#define BTIF_ERROR_SRV_AV_CP_NOT_SUPPORTED 705 /* Content protection is not supported by all headsets */
+
+/* Transcoding definition for TxTranscoding and RxTranscoding */
+#define BTIF_MEDIA_TRSCD_OFF 0
+#define BTIF_MEDIA_TRSCD_PCM_2_SBC 1 /* Tx */
+
+
+/*******************************************************************************
+ ** Data types
+ *******************************************************************************/
+
+typedef int tBTIF_STATUS;
+
+/* tBTIF_MEDIA_INIT_AUDIO msg structure */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 SamplingFreq; /* 16k, 32k, 44.1k or 48k*/
+ UINT8 ChannelMode; /* mono, dual, stereo or joint stereo*/
+ UINT8 NumOfSubBands; /* 4 or 8 */
+ UINT8 NumOfBlocks; /* 4, 8, 12 or 16*/
+ UINT8 AllocationMethod; /* loudness or SNR*/
+ UINT16 MtuSize; /* peer mtu size */
+} tBTIF_MEDIA_INIT_AUDIO;
+
+#if (BTA_AV_INCLUDED == TRUE)
+/* tBTIF_MEDIA_UPDATE_AUDIO msg structure */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 MinMtuSize; /* Minimum peer mtu size */
+ UINT8 MaxBitPool; /* Maximum peer bitpool */
+ UINT8 MinBitPool; /* Minimum peer bitpool */
+} tBTIF_MEDIA_UPDATE_AUDIO;
+
+/* tBTIF_MEDIA_INIT_AUDIO_FEEDING msg structure */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTIF_AV_FEEDING_MODE feeding_mode;
+ tBTIF_AV_MEDIA_FEEDINGS feeding;
+} tBTIF_MEDIA_INIT_AUDIO_FEEDING;
+#endif
+
+
+/*******************************************************************************
+ ** Public functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ **
+ ** Function btif_av_task
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+extern int btif_media_task(void *p);
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_enc_init_req
+ **
+ ** Description Request to initialize the media task encoder
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+extern BOOLEAN btif_media_task_enc_init_req(tBTIF_MEDIA_INIT_AUDIO * p_msg);
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_enc_update_req
+ **
+ ** Description Request to update the media task encoder
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+#if (BTA_AV_INCLUDED == TRUE)
+extern BOOLEAN btif_media_task_enc_update_req(tBTIF_MEDIA_UPDATE_AUDIO * p_msg);
+#endif
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_start_aa_req
+ **
+ ** Description Request to start audio encoding task
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+extern BOOLEAN btif_media_task_start_aa_req(void);
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_stop_aa_req
+ **
+ ** Description Request to stop audio encoding task
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+extern BOOLEAN btif_media_task_stop_aa_req(void);
+
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_aa_tx_flush_req
+ **
+ ** Description Request to flush audio encoding pipe
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+extern BOOLEAN btif_media_task_aa_tx_flush_req(void);
+
+/*******************************************************************************
+ **
+ ** Function btif_media_aa_readbuf
+ **
+ ** Description Read an audio GKI buffer from the BTIF media TX queue
+ **
+ ** Returns pointer on a GKI aa buffer ready to send
+ **
+ *******************************************************************************/
+extern BT_HDR *btif_media_aa_readbuf(void);
+
+/*******************************************************************************
+ **
+ ** Function btif_media_aa_writebuf
+ **
+ ** Description Enqueue a Advance Audio media GKI buffer to be processed by btif media task.
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+extern void btif_media_aa_writebuf(BT_HDR *pBuf, UINT32 timestamp, UINT16 seq_num);
+
+/*******************************************************************************
+ **
+ ** Function btif_media_av_writebuf
+ **
+ ** Description Enqueue a video media GKI buffer to be processed by btif media task.
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+extern BOOLEAN btif_media_av_writebuf(UINT8 *p_media, UINT32 media_len,
+ UINT32 timestamp, UINT16 seq_num);
+
+#if (BTA_AV_INCLUDED == TRUE)
+/*******************************************************************************
+ **
+ ** Function btif_media_task_audio_feeding_init_req
+ **
+ ** Description Request to initialize audio feeding
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+
+extern BOOLEAN btif_media_task_audio_feeding_init_req(tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_msg);
+#endif
+
+/*******************************************************************************
+ **
+ ** Function dump_codec_info
+ **
+ ** Description Decode and display codec_info (for debug)
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+extern void dump_codec_info(unsigned char *p_codec);
+
+/**
+ * Local adaptation helper functions between btif and media task
+ */
+
+int btif_a2dp_start_media_task(void);
+void btif_a2dp_stop_media_task(void);
+
+void btif_a2dp_on_init(void);
+void btif_a2dp_setup_codec(void);
+void btif_a2dp_on_idle(void);
+void btif_a2dp_on_open(void);
+void btif_a2dp_on_started(tBTA_AV_START *p_av);
+void btif_a2dp_on_stop_req(void);
+void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av);
+void btif_a2dp_on_suspend(void);
+void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av);
+void btif_a2dp_set_tx_flush(BOOLEAN enable);
+
+void btif_media_check_iop_exceptions(UINT8 *peer_bda);
+
+#endif
diff --git a/btif/include/btif_pan.h b/btif/include/btif_pan.h
new file mode 100644
index 0000000..d9ecb2e
--- /dev/null
+++ b/btif/include/btif_pan.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_pan.h
+ *
+ * Description: Bluetooth pan Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_PAN_H
+#define BTIF_PAN_H
+
+#include <hardware/bt_pan.h>
+
+btpan_interface_t *btif_pan_interface();
+void btif_pan_init();
+void btif_pan_cleanup();
+
+#endif
diff --git a/btif/include/btif_pan_internal.h b/btif/include/btif_pan_internal.h
new file mode 100644
index 0000000..d697ac8
--- /dev/null
+++ b/btif/include/btif_pan_internal.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_pan_internal.h
+ *
+ * Description: Bluetooth pan internal
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_PAN_INTERNAL_H
+#define BTIF_PAN_INTERNAL_H
+
+#include "btif_pan.h"
+#include "bt_types.h"
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define PAN_NAP_SERVICE_NAME "Android Network Access Point"
+#define PANU_SERVICE_NAME "Android Network User"
+#define TAP_IF_NAME "bt-pan"
+#define ETH_ADDR_LEN 6
+#ifndef PAN_SECURITY
+#define PAN_SECURITY (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT)
+#endif
+
+#define PAN_STATE_UNKNOWN 0
+#define PAN_STATE_OPEN 1
+#define PAN_STATE_CLOSE 2
+#ifndef PAN_ROLE_INACTIVE
+#define PAN_ROLE_INACTIVE 0
+#endif
+
+
+/*******************************************************************************
+** Type definitions and return values
+********************************************************************************/
+
+typedef struct eth_hdr
+{
+ unsigned char h_dest[ETH_ADDR_LEN];
+ unsigned char h_src[ETH_ADDR_LEN];
+ short h_proto;
+} tETH_HDR;
+
+typedef struct
+{
+ int handle;
+ int state;
+ UINT16 protocol;
+ BD_ADDR peer;
+ int local_role;
+ int remote_role;
+ unsigned char eth_addr[ETH_ADDR_LEN];
+} btpan_conn_t;
+
+typedef struct
+{
+ int btl_if_handle;
+ int btl_if_handle_panu;
+ int tap_fd;
+ int enabled;
+ int open_count;
+ btpan_conn_t conns[MAX_PAN_CONNS];
+} btpan_cb_t;
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+extern btpan_cb_t btpan_cb;
+btpan_conn_t *btpan_new_conn(int handle, const BD_ADDR addr, int local_role, int peer_role);
+btpan_conn_t *btpan_find_conn_addr(const BD_ADDR addr);
+btpan_conn_t *btpan_find_conn_handle(UINT16 handle);
+int btpan_get_connected_count(void);
+int btpan_tap_open(void);
+void create_tap_read_thread(int tap_fd);
+void destroy_tap_read_thread(void);
+int btpan_tap_close(int tap_fd);
+int btpan_tap_send(int tap_fd, const BD_ADDR src, const BD_ADDR dst, UINT16 protocol,
+ const char* buff, UINT16 size, BOOLEAN ext, BOOLEAN forward);
+
+static inline int is_empty_eth_addr(const BD_ADDR addr)
+{
+ int i;
+ for(i = 0; i < BD_ADDR_LEN; i++)
+ if(addr[i] != 0)
+ return 0;
+ return 1;
+}
+
+static inline int is_valid_bt_eth_addr(const BD_ADDR addr)
+{
+ if(is_empty_eth_addr(addr))
+ return 0;
+ return addr[0] & 1 ? 0 : 1; /* Cannot be multicasting address */
+}
+
+#endif
diff --git a/btif/include/btif_profile_queue.h b/btif/include/btif_profile_queue.h
new file mode 100644
index 0000000..931f457
--- /dev/null
+++ b/btif/include/btif_profile_queue.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_profile_queue.h
+ *
+ * Description: Bluetooth remote device connection queuing
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_PROFILE_QUEUE_H
+#define BTIF_PROFILE_QUEUE_H
+
+typedef bt_status_t (btif_connect_cb_t) (bt_bdaddr_t *bda);
+
+bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda,
+ btif_connect_cb_t *connect_cb);
+void btif_queue_advance();
+void btif_queue_release();
+
+#endif
diff --git a/btif/include/btif_sm.h b/btif/include/btif_sm.h
new file mode 100644
index 0000000..baad0d9
--- /dev/null
+++ b/btif/include/btif_sm.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: btif_sm.h
+ *
+ * Description: Generic BTIF state machine API
+ *
+ *****************************************************************************/
+
+#ifndef BTIF_SM_H
+#define BTIF_SM_H
+
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+/* Generic Enter/Exit state machine events */
+#define BTIF_SM_ENTER_EVT 0xFFFF
+#define BTIF_SM_EXIT_EVT 0xFFFE
+
+
+/*****************************************************************************
+** Type definitions and return values
+******************************************************************************/
+typedef UINT32 btif_sm_state_t;
+typedef UINT32 btif_sm_event_t;
+typedef void* btif_sm_handle_t;
+typedef BOOLEAN(*btif_sm_handler_t)(btif_sm_event_t event, void *data);
+
+
+/*****************************************************************************
+** Functions
+**
+** NOTE: THESE APIs SHOULD BE INVOKED ONLY IN THE BTIF CONTEXT
+**
+******************************************************************************/
+
+/*****************************************************************************
+**
+** Function btif_sm_init
+**
+** Description Initializes the state machine with the state handlers
+** The caller should ensure that the table and the corresponding
+** states match. The location that 'p_handlers' points to shall
+** be available until the btif_sm_shutdown API is invoked.
+**
+** Returns Returns a pointer to the initialized state machine handle.
+**
+******************************************************************************/
+btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers,
+ btif_sm_state_t initial_state);
+
+/*****************************************************************************
+**
+** Function btif_sm_shutdown
+**
+** Description Tears down the state machine
+**
+** Returns None
+**
+******************************************************************************/
+void btif_sm_shutdown(btif_sm_handle_t handle);
+
+/*****************************************************************************
+**
+** Function btif_sm_get_state
+**
+** Description Fetches the current state of the state machine
+**
+** Returns Current state
+**
+******************************************************************************/
+btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle);
+
+/*****************************************************************************
+**
+** Function btif_sm_dispatch
+**
+** Description Dispatches the 'event' along with 'data' to the current state handler
+**
+** Returns Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise
+**
+******************************************************************************/
+bt_status_t btif_sm_dispatch(btif_sm_handle_t handle, btif_sm_event_t event,
+ void *data);
+
+/*****************************************************************************
+**
+** Function btif_sm_change_state
+**
+** Description Make a transition to the new 'state'. The 'BTIF_SM_EXIT_EVT'
+** shall be invoked before exiting the current state. The
+** 'BTIF_SM_ENTER_EVT' shall be invoked before entering the new state
+**
+**
+** Returns Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise
+**
+******************************************************************************/
+bt_status_t btif_sm_change_state(btif_sm_handle_t handle, btif_sm_state_t state);
+
+#endif /* BTIF_SM_H */
diff --git a/btif/include/btif_sock.h b/btif/include/btif_sock.h
new file mode 100644
index 0000000..ad2c71d
--- /dev/null
+++ b/btif/include/btif_sock.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sock.h
+ *
+ * Description: Bluetooth socket Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_SOCK_H
+#define BTIF_SOCK_H
+
+#include <hardware/bt_sock.h>
+
+bt_status_t btif_sock_init();
+btsock_interface_t *btif_sock_get_interface();
+void btif_sock_cleanup();
+
+#endif
diff --git a/btif/include/btif_sock_rfc.h b/btif/include/btif_sock_rfc.h
new file mode 100644
index 0000000..b36ec1f
--- /dev/null
+++ b/btif/include/btif_sock_rfc.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sock.h
+ *
+ * Description: Bluetooth socket Interface
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_SOCK_RFC_H
+#define BTIF_SOCK_RFC_H
+
+bt_status_t btsock_rfc_init(int handle);
+bt_status_t btsock_rfc_cleanup();
+bt_status_t btsock_rfc_listen(const char* name, const uint8_t* uuid, int channel,
+ int* sock_fd, int flags);
+bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, const uint8_t* uuid,
+ int channel, int* sock_fd, int flags);
+void btsock_rfc_signaled(int fd, int flags, uint32_t user_id);
+
+#endif
diff --git a/btif/include/btif_sock_sdp.h b/btif/include/btif_sock_sdp.h
new file mode 100644
index 0000000..9fe4768
--- /dev/null
+++ b/btif/include/btif_sock_sdp.h
@@ -0,0 +1,39 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_SDP_H
+#define BTIF_SOCK_SDP_H
+static const UINT8 UUID_OBEX_OBJECT_PUSH[] = {0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const UINT8 UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const UINT8 UUID_SPP[] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+
+static inline BOOLEAN is_uuid_empty(const uint8_t* uuid)
+{
+ static uint8_t empty_uuid[16];
+ return uuid == NULL || memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0;
+}
+
+int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, int scn);
+void del_rfc_sdp_rec(int handle);
+BOOLEAN is_reserved_rfc_channel(int channel);
+int get_reserved_rfc_channel(const uint8_t* uuid);
+
+#endif
diff --git a/btif/include/btif_sock_thread.h b/btif/include/btif_sock_thread.h
new file mode 100644
index 0000000..9b12f56
--- /dev/null
+++ b/btif/include/btif_sock_thread.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_THREAD_H
+#define BTIF_SOCK_THREAD_H
+
+#include <hardware/bt_sock.h>
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define SOCK_THREAD_FD_RD 1 /* BT socket read signal */
+#define SOCK_THREAD_FD_WR (1 << 1) /* BT socket write signal */
+#define SOCK_THREAD_FD_EXCEPTION (1 << 2) /* BT socket exception singal */
+#define SOCK_THREAD_ADD_FD_SYNC (1 << 3) /* Add BT socket fd in current socket
+ poll thread context immediately */
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+typedef void (*btsock_signaled_cb)(int fd, int type, int flags, uint32_t user_id);
+typedef void (*btsock_cmd_cb)(int cmd_fd, int type, int size, uint32_t user_id);
+
+int btsock_thread_init();
+int btsock_thread_add_fd(int handle, int fd, int type, int flags, uint32_t user_id);
+int btsock_thread_wakeup(int handle);
+int btsock_thread_post_cmd(int handle, int cmd_type, const unsigned char* cmd_data,
+ int data_size, uint32_t user_id);
+int btsock_thread_create(btsock_signaled_cb callback, btsock_cmd_cb cmd_callback);
+int btsock_thread_exit(int handle);
+
+#endif
diff --git a/btif/include/btif_sock_util.h b/btif/include/btif_sock_util.h
new file mode 100644
index 0000000..e0f7066
--- /dev/null
+++ b/btif/include/btif_sock_util.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sock_util.h
+ *
+ * Description: Bluetooth socket Interface Helper functions
+ *
+ *******************************************************************************/
+
+#ifndef BTIF_SOCK_UTIL_H
+#define BTIF_SOCK_UTIL_H
+
+#include <pthread.h>
+#include <cutils/log.h>
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+static inline void init_slot_lock( pthread_mutex_t* mutex)
+{
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+ pthread_mutex_init(mutex, &attr);
+}
+
+static inline void lock_slot(pthread_mutex_t* mutex)
+{
+ if(mutex->value)
+ pthread_mutex_lock(mutex);
+ else ALOGE("mutex: %p is not initialized", mutex);
+}
+
+static inline void unlock_slot(pthread_mutex_t* mutex)
+{
+ if(mutex->value)
+ pthread_mutex_unlock(mutex);
+ else ALOGE("mutex: %p is not initialized", mutex);
+}
+
+void dump_bin(const char* title, const char* data, int size);
+
+int sock_send_fd(int sock_fd, const uint8_t* buffer, int len, int send_fd);
+int sock_send_all(int sock_fd, const uint8_t* buf, int len);
+int sock_recv_all(int sock_fd, uint8_t* buf, int len);
+
+#endif
diff --git a/btif/include/btif_storage.h b/btif/include/btif_storage.h
new file mode 100644
index 0000000..87dec3b
--- /dev/null
+++ b/btif/include/btif_storage.h
@@ -0,0 +1,313 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_STORAGE_H
+#define BTIF_STORAGE_H
+
+#include "data_types.h"
+#include "bt_types.h"
+
+#include <utils/Log.h>
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+#define BTIF_STORAGE_FILL_PROPERTY(p_prop, t, l, p_v) \
+ (p_prop)->type = t;(p_prop)->len = l; (p_prop)->val = (p_v);
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_storage_get_adapter_property
+**
+** Description BTIF storage API - Fetches the adapter property->type
+** from NVRAM and fills property->val.
+** Caller should provide memory for property->val and
+** set the property->val
+**
+** Returns BT_STATUS_SUCCESS if the fetch was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_get_adapter_property(bt_property_t *property);
+
+/*******************************************************************************
+**
+** Function btif_storage_set_adapter_property
+**
+** Description BTIF storage API - Stores the adapter property
+** to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_set_adapter_property(bt_property_t *property);
+
+/*******************************************************************************
+**
+** Function btif_storage_get_remote_device_property
+**
+** Description BTIF storage API - Fetches the remote device property->type
+** from NVRAM and fills property->val.
+** Caller should provide memory for property->val and
+** set the property->val
+**
+** Returns BT_STATUS_SUCCESS if the fetch was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_get_remote_device_property(bt_bdaddr_t *remote_bd_addr,
+ bt_property_t *property);
+
+/*******************************************************************************
+**
+** Function btif_storage_set_remote_device_property
+**
+** Description BTIF storage API - Stores the remote device property
+** to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t *remote_bd_addr,
+ bt_property_t *property);
+
+/*******************************************************************************
+**
+** Function btif_storage_add_remote_device
+**
+** Description BTIF storage API - Adds a newly discovered device to NVRAM
+** along with the timestamp. Also, stores the various
+** properties - RSSI, BDADDR, NAME (if found in EIR)
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bdaddr,
+ uint32_t num_properties,
+ bt_property_t *properties);
+
+/*******************************************************************************
+**
+** Function btif_storage_add_bonded_device
+**
+** Description BTIF storage API - Adds the newly bonded device to NVRAM
+** along with the link-key, Key type and Pin key length
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr,
+ LINK_KEY link_key,
+ uint8_t key_type,
+ uint8_t pin_length);
+
+/*******************************************************************************
+**
+** Function btif_storage_remove_bonded_device
+**
+** Description BTIF storage API - Deletes the bonded device from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the deletion was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t *remote_bd_addr);
+
+/*******************************************************************************
+**
+** Function btif_storage_remove_bonded_device
+**
+** Description BTIF storage API - Deletes the bonded device from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the deletion was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_load_bonded_devices(void);
+
+/*******************************************************************************
+**
+** Function btif_storage_read_hl_apps_cb
+**
+** Description BTIF storage API - Read HL application control block from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_read_hl_apps_cb(char *value, int value_size);
+
+/*******************************************************************************
+**
+** Function btif_storage_write_hl_apps_cb
+**
+** Description BTIF storage API - Write HL application control block to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_write_hl_apps_cb(char *value, int value_size);
+
+/*******************************************************************************
+**
+** Function btif_storage_read_hl_apps_cb
+**
+** Description BTIF storage API - Read HL application configuration from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_read_hl_app_data(UINT8 app_idx, char *value, int value_size);
+
+/*******************************************************************************
+**
+** Function btif_storage_write_hl_app_data
+**
+** Description BTIF storage API - Write HL application configuration to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_write_hl_app_data(UINT8 app_idx, char *value, int value_size);
+
+/*******************************************************************************
+**
+** Function btif_storage_read_hl_mdl_data
+**
+** Description BTIF storage API - Read HL application MDL configuration from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_read_hl_mdl_data(UINT8 app_idx, char *value, int value_size);
+
+/*******************************************************************************
+**
+** Function btif_storage_write_hl_mdl_data
+**
+** Description BTIF storage API - Write HL application MDL configuration from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_write_hl_mdl_data(UINT8 app_idx, char *value, int value_size);
+
+/*******************************************************************************
+**
+** Function btif_storage_add_hid_device_info
+**
+** Description BTIF storage API - Adds the hid information of bonded hid devices-to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_hid_device_info(bt_bdaddr_t *remote_bd_addr,
+ UINT16 attr_mask, UINT8 sub_class,
+ UINT8 app_id, UINT16 vendor_id,
+ UINT16 product_id, UINT16 version,
+ UINT8 ctry_code, UINT16 dl_len,
+ UINT8 *dsc_list);
+
+/*******************************************************************************
+**
+** Function btif_storage_load_bonded_hid_info
+**
+** Description BTIF storage API - Loads hid info for all the bonded devices
+** from NVRAM and adds those devices to the BTA_HH.
+**
+** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_load_bonded_hid_info(void);
+
+/*******************************************************************************
+**
+** Function btif_storage_remove_hid_info
+**
+** Description BTIF storage API - Deletes the bonded hid device info from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the deletion was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_remove_hid_info(bt_bdaddr_t *remote_bd_addr);
+
+/*******************************************************************************
+**
+** Function btif_storage_load_autopair_device_list
+**
+** Description BTIF storage API - Populates auto pair device list
+**
+** Returns BT_STATUS_SUCCESS if the auto pair blacklist is successfully populated
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_load_autopair_device_list();
+
+/*******************************************************************************
+**
+** Function btif_storage_is_device_autopair_blacklisted
+**
+** Description BTIF storage API Checks if the given device is blacklisted for auto pairing
+**
+** Returns TRUE if the device is found in the auto pair blacklist
+** FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_dev_addr);
+
+/*******************************************************************************
+**
+** Function btif_storage_add_device_to_autopair_blacklist
+**
+** Description BTIF storage API - Add a remote device to the auto pairing blacklist
+**
+** Returns BT_STATUS_SUCCESS if the device is successfully added to the auto pair blacklist
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_device_to_autopair_blacklist(bt_bdaddr_t *remote_dev_addr);
+
+/*******************************************************************************
+**
+** Function btif_storage_is_fixed_pin_zeros_keyboard
+**
+** Description BTIF storage API - checks if this device has fixed PIN key device list
+**
+** Returns TRUE if the device is found in the fixed pin keyboard device list
+** FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btif_storage_is_fixed_pin_zeros_keyboard(bt_bdaddr_t *remote_dev_addr);
+
+#endif /* BTIF_STORAGE_H */
diff --git a/btif/include/btif_util.h b/btif/include/btif_util.h
new file mode 100644
index 0000000..09dae6e
--- /dev/null
+++ b/btif/include/btif_util.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_UTIL_H
+#define BTIF_UTIL_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <utils/Log.h>
+
+#include "data_types.h"
+#include "bt_types.h"
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+
+/*******************************************************************************
+** Type definitions for callback functions
+********************************************************************************/
+
+typedef char bdstr_t[18];
+
+
+/*******************************************************************************
+** Functions
+********************************************************************************/
+
+const char* dump_bt_status(bt_status_t status);
+const char* dump_dm_search_event(UINT16 event);
+const char* dump_dm_event(UINT16 event);
+const char* dump_hf_event(UINT16 event);
+const char* dump_hh_event(UINT16 event);
+const char* dump_hf_conn_state(UINT16 event);
+const char* dump_hf_call_state(bthf_call_state_t call_state);
+const char* dump_property_type(bt_property_type_t type);
+const char* dump_hf_audio_state(UINT16 event);
+const char* dump_adapter_scan_mode(bt_scan_mode_t mode);
+const char* dump_thread_evt(bt_cb_thread_evt evt);
+
+const char* dump_av_conn_state(UINT16 event);
+const char* dump_av_audio_state(UINT16 event);
+
+int str2bd(char *str, bt_bdaddr_t *addr);
+char *bd2str(bt_bdaddr_t *addr, bdstr_t *bdstr);
+
+UINT32 devclass2uint(DEV_CLASS dev_class);
+void uint2devclass(UINT32 dev, DEV_CLASS dev_class);
+void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128);
+
+void uuid_to_string(bt_uuid_t *p_uuid, char *str);
+void string_to_uuid(char *str, bt_uuid_t *p_uuid);
+int ascii_2_hex (char *p_ascii, int len, UINT8 *p_hex);
+
+#endif /* BTIF_UTIL_H */
diff --git a/btif/include/uinput.h b/btif/include/uinput.h
new file mode 100644
index 0000000..5925703
--- /dev/null
+++ b/btif/include/uinput.h
@@ -0,0 +1,590 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#ifndef __UINPUT_H
+#define __UINPUT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+/*******************************************************************************
+** Constants & Macros
+********************************************************************************/
+
+/* Events */
+
+#define EV_SYN 0x00
+#define EV_KEY 0x01
+#define EV_REL 0x02
+#define EV_ABS 0x03
+#define EV_MSC 0x04
+#define EV_LED 0x11
+#define EV_SND 0x12
+#define EV_REP 0x14
+#define EV_FF 0x15
+#define EV_PWR 0x16
+#define EV_FF_STATUS 0x17
+#define EV_MAX 0x1f
+
+/* Synchronization events */
+
+#define SYN_REPORT 0
+#define SYN_CONFIG 1
+
+/* Keys and buttons */
+
+#define KEY_RESERVED 0
+#define KEY_ESC 1
+#define KEY_1 2
+#define KEY_2 3
+#define KEY_3 4
+#define KEY_4 5
+#define KEY_5 6
+#define KEY_6 7
+#define KEY_7 8
+#define KEY_8 9
+#define KEY_9 10
+#define KEY_0 11
+#define KEY_MINUS 12
+#define KEY_EQUAL 13
+#define KEY_BACKSPACE 14
+#define KEY_TAB 15
+#define KEY_Q 16
+#define KEY_W 17
+#define KEY_E 18
+#define KEY_R 19
+#define KEY_T 20
+#define KEY_Y 21
+#define KEY_U 22
+#define KEY_I 23
+#define KEY_O 24
+#define KEY_P 25
+#define KEY_LEFTBRACE 26
+#define KEY_RIGHTBRACE 27
+#define KEY_ENTER 28
+#define KEY_LEFTCTRL 29
+#define KEY_A 30
+#define KEY_S 31
+#define KEY_D 32
+#define KEY_F 33
+#define KEY_G 34
+#define KEY_H 35
+#define KEY_J 36
+#define KEY_K 37
+#define KEY_L 38
+#define KEY_SEMICOLON 39
+#define KEY_APOSTROPHE 40
+#define KEY_GRAVE 41
+#define KEY_LEFTSHIFT 42
+#define KEY_BACKSLASH 43
+#define KEY_Z 44
+#define KEY_X 45
+#define KEY_C 46
+#define KEY_V 47
+#define KEY_B 48
+#define KEY_N 49
+#define KEY_M 50
+#define KEY_COMMA 51
+#define KEY_DOT 52
+#define KEY_SLASH 53
+#define KEY_RIGHTSHIFT 54
+#define KEY_KPASTERISK 55
+#define KEY_LEFTALT 56
+#define KEY_SPACE 57
+#define KEY_CAPSLOCK 58
+#define KEY_F1 59
+#define KEY_F2 60
+#define KEY_F3 61
+#define KEY_F4 62
+#define KEY_F5 63
+#define KEY_F6 64
+#define KEY_F7 65
+#define KEY_F8 66
+#define KEY_F9 67
+#define KEY_F10 68
+#define KEY_NUMLOCK 69
+#define KEY_SCROLLLOCK 70
+#define KEY_KP7 71
+#define KEY_KP8 72
+#define KEY_KP9 73
+#define KEY_KPMINUS 74
+#define KEY_KP4 75
+#define KEY_KP5 76
+#define KEY_KP6 77
+#define KEY_KPPLUS 78
+#define KEY_KP1 79
+#define KEY_KP2 80
+#define KEY_KP3 81
+#define KEY_KP0 82
+#define KEY_KPDOT 83
+#define KEY_103RD 84
+#define KEY_F13 85
+#define KEY_102ND 86
+#define KEY_F11 87
+#define KEY_F12 88
+#define KEY_F14 89
+#define KEY_F15 90
+#define KEY_F16 91
+#define KEY_F17 92
+#define KEY_F18 93
+#define KEY_F19 94
+#define KEY_F20 95
+#define KEY_KPENTER 96
+#define KEY_RIGHTCTRL 97
+#define KEY_KPSLASH 98
+#define KEY_SYSRQ 99
+#define KEY_RIGHTALT 100
+#define KEY_LINEFEED 101
+#define KEY_HOME 102
+#define KEY_UP 103
+#define KEY_PAGEUP 104
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_END 107
+#define KEY_DOWN 108
+#define KEY_PAGEDOWN 109
+#define KEY_INSERT 110
+#define KEY_DELETE 111
+#define KEY_MACRO 112
+#define KEY_MUTE 113
+#define KEY_VOLUMEDOWN 114
+#define KEY_VOLUMEUP 115
+#define KEY_POWER 116
+#define KEY_KPEQUAL 117
+#define KEY_KPPLUSMINUS 118
+#define KEY_PAUSE 119
+#define KEY_F21 120
+#define KEY_F22 121
+#define KEY_F23 122
+#define KEY_F24 123
+#define KEY_KPCOMMA 124
+#define KEY_LEFTMETA 125
+#define KEY_RIGHTMETA 126
+#define KEY_COMPOSE 127
+
+#define KEY_STOP 128
+#define KEY_AGAIN 129
+#define KEY_PROPS 130
+#define KEY_UNDO 131
+#define KEY_FRONT 132
+#define KEY_COPY 133
+#define KEY_OPEN 134
+#define KEY_PASTE 135
+#define KEY_FIND 136
+#define KEY_CUT 137
+#define KEY_HELP 138
+#define KEY_MENU 139
+#define KEY_CALC 140
+#define KEY_SETUP 141
+#define KEY_SLEEP 142
+#define KEY_WAKEUP 143
+#define KEY_FILE 144
+#define KEY_SENDFILE 145
+#define KEY_DELETEFILE 146
+#define KEY_XFER 147
+#define KEY_PROG1 148
+#define KEY_PROG2 149
+#define KEY_WWW 150
+#define KEY_MSDOS 151
+#define KEY_COFFEE 152
+#define KEY_DIRECTION 153
+#define KEY_CYCLEWINDOWS 154
+#define KEY_MAIL 155
+#define KEY_BOOKMARKS 156
+#define KEY_COMPUTER 157
+#define KEY_BACK 158
+#define KEY_FORWARD 159
+#define KEY_CLOSECD 160
+#define KEY_EJECTCD 161
+#define KEY_EJECTCLOSECD 162
+#define KEY_NEXTSONG 163
+#define KEY_PLAYPAUSE 164
+#define KEY_PREVIOUSSONG 165
+#define KEY_STOPCD 166
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_PHONE 169
+#define KEY_ISO 170
+#define KEY_CONFIG 171
+#define KEY_HOMEPAGE 172
+#define KEY_REFRESH 173
+#define KEY_EXIT 174
+#define KEY_MOVE 175
+#define KEY_EDIT 176
+#define KEY_SCROLLUP 177
+#define KEY_SCROLLDOWN 178
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+
+#define KEY_INTL1 181
+#define KEY_INTL2 182
+#define KEY_INTL3 183
+#define KEY_INTL4 184
+#define KEY_INTL5 185
+#define KEY_INTL6 186
+#define KEY_INTL7 187
+#define KEY_INTL8 188
+#define KEY_INTL9 189
+#define KEY_LANG1 190
+#define KEY_LANG2 191
+#define KEY_LANG3 192
+#define KEY_LANG4 193
+#define KEY_LANG5 194
+#define KEY_LANG6 195
+#define KEY_LANG7 196
+#define KEY_LANG8 197
+#define KEY_LANG9 198
+
+#define KEY_PLAYCD 200
+#define KEY_PAUSECD 201
+#define KEY_PROG3 202
+#define KEY_PROG4 203
+#define KEY_SUSPEND 205
+#define KEY_CLOSE 206
+#define KEY_PLAY 207
+
+#define KEY_UNKNOWN 220
+
+#define KEY_BRIGHTNESSDOWN 224
+#define KEY_BRIGHTNESSUP 225
+
+#define BTN_MISC 0x100
+#define BTN_0 0x100
+#define BTN_1 0x101
+#define BTN_2 0x102
+#define BTN_3 0x103
+#define BTN_4 0x104
+#define BTN_5 0x105
+#define BTN_6 0x106
+#define BTN_7 0x107
+#define BTN_8 0x108
+#define BTN_9 0x109
+
+#define BTN_MOUSE 0x110
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+#define BTN_TASK 0x117
+
+#define BTN_JOYSTICK 0x120
+#define BTN_TRIGGER 0x120
+#define BTN_THUMB 0x121
+#define BTN_THUMB2 0x122
+#define BTN_TOP 0x123
+#define BTN_TOP2 0x124
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
+#define BTN_BASE6 0x12b
+#define BTN_DEAD 0x12f
+
+#define BTN_GAMEPAD 0x130
+#define BTN_A 0x130
+#define BTN_B 0x131
+#define BTN_C 0x132
+#define BTN_X 0x133
+#define BTN_Y 0x134
+#define BTN_Z 0x135
+#define BTN_TL 0x136
+#define BTN_TR 0x137
+#define BTN_TL2 0x138
+#define BTN_TR2 0x139
+#define BTN_SELECT 0x13a
+#define BTN_START 0x13b
+#define BTN_MODE 0x13c
+#define BTN_THUMBL 0x13d
+#define BTN_THUMBR 0x13e
+
+#define BTN_DIGI 0x140
+#define BTN_TOOL_PEN 0x140
+#define BTN_TOOL_RUBBER 0x141
+#define BTN_TOOL_BRUSH 0x142
+#define BTN_TOOL_PENCIL 0x143
+#define BTN_TOOL_AIRBRUSH 0x144
+#define BTN_TOOL_FINGER 0x145
+#define BTN_TOOL_MOUSE 0x146
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
+#define BTN_TOOL_DOUBLETAP 0x14d
+#define BTN_TOOL_TRIPLETAP 0x14e
+
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
+#define KEY_OK 0x160
+#define KEY_SELECT 0x161
+#define KEY_GOTO 0x162
+#define KEY_CLEAR 0x163
+#define KEY_POWER2 0x164
+#define KEY_OPTION 0x165
+#define KEY_INFO 0x166
+#define KEY_TIME 0x167
+#define KEY_VENDOR 0x168
+#define KEY_ARCHIVE 0x169
+#define KEY_PROGRAM 0x16a
+#define KEY_CHANNEL 0x16b
+#define KEY_FAVORITES 0x16c
+#define KEY_EPG 0x16d
+#define KEY_PVR 0x16e
+#define KEY_MHP 0x16f
+#define KEY_LANGUAGE 0x170
+#define KEY_TITLE 0x171
+#define KEY_SUBTITLE 0x172
+#define KEY_ANGLE 0x173
+#define KEY_ZOOM 0x174
+#define KEY_MODE 0x175
+#define KEY_KEYBOARD 0x176
+#define KEY_SCREEN 0x177
+#define KEY_PC 0x178
+#define KEY_TV 0x179
+#define KEY_TV2 0x17a
+#define KEY_VCR 0x17b
+#define KEY_VCR2 0x17c
+#define KEY_SAT 0x17d
+#define KEY_SAT2 0x17e
+#define KEY_CD 0x17f
+#define KEY_TAPE 0x180
+#define KEY_RADIO 0x181
+#define KEY_TUNER 0x182
+#define KEY_PLAYER 0x183
+#define KEY_TEXT 0x184
+#define KEY_DVD 0x185
+#define KEY_AUX 0x186
+#define KEY_MP3 0x187
+#define KEY_AUDIO 0x188
+#define KEY_VIDEO 0x189
+#define KEY_DIRECTORY 0x18a
+#define KEY_LIST 0x18b
+#define KEY_MEMO 0x18c
+#define KEY_CALENDAR 0x18d
+#define KEY_RED 0x18e
+#define KEY_GREEN 0x18f
+#define KEY_YELLOW 0x190
+#define KEY_BLUE 0x191
+#define KEY_CHANNELUP 0x192
+#define KEY_CHANNELDOWN 0x193
+#define KEY_FIRST 0x194
+#define KEY_LAST 0x195
+#define KEY_AB 0x196
+#define KEY_NEXT 0x197
+#define KEY_RESTART 0x198
+#define KEY_SLOW 0x199
+#define KEY_SHUFFLE 0x19a
+#define KEY_BREAK 0x19b
+#define KEY_PREVIOUS 0x19c
+#define KEY_DIGITS 0x19d
+#define KEY_TEEN 0x19e
+#define KEY_TWEN 0x19f
+
+#define KEY_FRAMEBACK 0x1b2
+#define KEY_FRAMEFORWARD 0x1b3
+#define KEY_CONTEXT_MENU 0x1fb
+
+#define KEY_MAX 0x1ff
+
+/* Relative axes */
+
+#define REL_X 0x00
+#define REL_Y 0x01
+#define REL_Z 0x02
+#define REL_RX 0x03
+#define REL_RY 0x04
+#define REL_RZ 0x05
+#define REL_HWHEEL 0x06
+#define REL_DIAL 0x07
+#define REL_WHEEL 0x08
+#define REL_MISC 0x09
+#define REL_MAX 0x0f
+
+/* Absolute axes */
+
+#define ABS_X 0x00
+#define ABS_Y 0x01
+#define ABS_Z 0x02
+#define ABS_RX 0x03
+#define ABS_RY 0x04
+#define ABS_RZ 0x05
+#define ABS_THROTTLE 0x06
+#define ABS_RUDDER 0x07
+#define ABS_WHEEL 0x08
+#define ABS_GAS 0x09
+#define ABS_BRAKE 0x0a
+#define ABS_HAT0X 0x10
+#define ABS_HAT0Y 0x11
+#define ABS_HAT1X 0x12
+#define ABS_HAT1Y 0x13
+#define ABS_HAT2X 0x14
+#define ABS_HAT2Y 0x15
+#define ABS_HAT3X 0x16
+#define ABS_HAT3Y 0x17
+#define ABS_PRESSURE 0x18
+#define ABS_DISTANCE 0x19
+#define ABS_TILT_X 0x1a
+#define ABS_TILT_Y 0x1b
+#define ABS_TOOL_WIDTH 0x1c
+#define ABS_VOLUME 0x20
+#define ABS_MISC 0x28
+#define ABS_MAX 0x3f
+
+/* Switch events */
+
+#define SW_0 0x00
+#define SW_1 0x01
+#define SW_2 0x02
+#define SW_3 0x03
+#define SW_4 0x04
+#define SW_5 0x05
+#define SW_6 0x06
+#define SW_7 0x07
+#define SW_MAX 0x0f
+
+/* Misc events */
+
+#define MSC_SERIAL 0x00
+#define MSC_PULSELED 0x01
+#define MSC_GESTURE 0x02
+#define MSC_RAW 0x03
+#define MSC_SCAN 0x04
+#define MSC_MAX 0x07
+
+/* LEDs */
+
+#define LED_NUML 0x00
+#define LED_CAPSL 0x01
+#define LED_SCROLLL 0x02
+#define LED_COMPOSE 0x03
+#define LED_KANA 0x04
+#define LED_SLEEP 0x05
+#define LED_SUSPEND 0x06
+#define LED_MUTE 0x07
+#define LED_MISC 0x08
+#define LED_MAIL 0x09
+#define LED_CHARGING 0x0a
+#define LED_MAX 0x0f
+
+/* Autorepeat values */
+
+#define REP_DELAY 0x00
+#define REP_PERIOD 0x01
+#define REP_MAX 0x01
+
+/* Sounds */
+
+#define SND_CLICK 0x00
+#define SND_BELL 0x01
+#define SND_TONE 0x02
+#define SND_MAX 0x07
+
+/* Identifiers */
+
+#define ID_BUS 0
+#define ID_VENDOR 1
+#define ID_PRODUCT 2
+#define ID_VERSION 3
+
+#define BUS_PCI 0x01
+#define BUS_ISAPNP 0x02
+#define BUS_USB 0x03
+#define BUS_HIL 0x04
+#define BUS_BLUETOOTH 0x05
+
+#define BUS_ISA 0x10
+#define BUS_I8042 0x11
+#define BUS_XTKBD 0x12
+#define BUS_RS232 0x13
+#define BUS_GAMEPORT 0x14
+#define BUS_PARPORT 0x15
+#define BUS_AMIGA 0x16
+#define BUS_ADB 0x17
+#define BUS_I2C 0x18
+#define BUS_HOST 0x19
+#define BUS_GSC 0x1A
+
+/* User input interface */
+
+#define UINPUT_IOCTL_BASE 'U'
+
+#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
+#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
+
+#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
+#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
+#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
+#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
+#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
+#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
+#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
+#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
+#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
+#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
+
+#ifndef NBITS
+#define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1)
+#endif
+
+#define UINPUT_MAX_NAME_SIZE 80
+
+
+/*******************************************************************************
+** Type definitions and return values
+********************************************************************************/
+
+struct uinput_id {
+ uint16_t bustype;
+ uint16_t vendor;
+ uint16_t product;
+ uint16_t version;
+};
+
+struct uinput_dev {
+ char name[UINPUT_MAX_NAME_SIZE];
+ struct uinput_id id;
+ int ff_effects_max;
+ int absmax[ABS_MAX + 1];
+ int absmin[ABS_MAX + 1];
+ int absfuzz[ABS_MAX + 1];
+ int absflat[ABS_MAX + 1];
+};
+
+struct uinput_event {
+ struct timeval time;
+ uint16_t type;
+ uint16_t code;
+ int32_t value;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UINPUT_H */
diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c
new file mode 100644
index 0000000..20d6a07
--- /dev/null
+++ b/btif/src/bluetooth.c
@@ -0,0 +1,413 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: bluetooth.c
+ *
+ * Description: Bluetooth HAL implementation
+ *
+ ***********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_sock.h>
+#include <hardware/bt_hh.h>
+#include <hardware/bt_hl.h>
+#include <hardware/bt_pan.h>
+
+#define LOG_NDDEBUG 0
+#define LOG_TAG "bluedroid"
+
+#include "btif_api.h"
+#include "bt_utils.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define is_profile(profile, str) ((strlen(str) == strlen(profile)) && strncmp((const char *)profile, str, strlen(str)) == 0)
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+bt_callbacks_t *bt_hal_cbacks = NULL;
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/* list all extended interfaces here */
+
+/* handsfree profile */
+extern bthf_interface_t *btif_hf_get_interface();
+/* advanced audio profile */
+extern btav_interface_t *btif_av_get_interface();
+/*rfc l2cap*/
+extern btsock_interface_t *btif_sock_get_interface();
+/* hid host profile */
+extern bthh_interface_t *btif_hh_get_interface();
+/* health device profile */
+extern bthl_interface_t *btif_hl_get_interface();
+/*pan*/
+extern btpan_interface_t *btif_pan_get_interface();
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+static uint8_t interface_ready(void)
+{
+ /* add checks here that would prevent API calls other than init to be executed */
+ if (bt_hal_cbacks == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** BLUETOOTH HAL INTERFACE FUNCTIONS
+**
+*****************************************************************************/
+
+static int init(bt_callbacks_t* callbacks )
+{
+ ALOGI("init");
+
+ /* sanity check */
+ if (interface_ready() == TRUE)
+ return BT_STATUS_DONE;
+
+ /* store reference to user callbacks */
+ bt_hal_cbacks = callbacks;
+
+ /* add checks for individual callbacks ? */
+
+ bt_utils_init();
+
+ /* init btif */
+ btif_init_bluetooth();
+
+ return BT_STATUS_SUCCESS;
+}
+
+static int enable( void )
+{
+ ALOGI("enable");
+
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_enable_bluetooth();
+}
+
+static int disable(void)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_disable_bluetooth();
+}
+
+static void cleanup( void )
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return;
+
+ btif_shutdown_bluetooth();
+ bt_utils_cleanup();
+
+ /* hal callbacks reset upon shutdown complete callback */
+
+ return;
+}
+
+static int get_adapter_properties(void)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_adapter_properties();
+}
+
+static int get_adapter_property(bt_property_type_t type)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_adapter_property(type);
+}
+
+static int set_adapter_property(const bt_property_t *property)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_set_adapter_property(property);
+}
+
+int get_remote_device_properties(bt_bdaddr_t *remote_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_device_properties(remote_addr);
+}
+
+int get_remote_device_property(bt_bdaddr_t *remote_addr, bt_property_type_t type)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_device_property(remote_addr, type);
+}
+
+int set_remote_device_property(bt_bdaddr_t *remote_addr, const bt_property_t *property)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_set_remote_device_property(remote_addr, property);
+}
+
+int get_remote_service_record(bt_bdaddr_t *remote_addr, bt_uuid_t *uuid)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_service_record(remote_addr, uuid);
+}
+
+int get_remote_services(bt_bdaddr_t *remote_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_get_remote_services(remote_addr);
+}
+
+static int start_discovery(void)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_start_discovery();
+}
+
+static int cancel_discovery(void)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_cancel_discovery();
+}
+
+static int create_bond(const bt_bdaddr_t *bd_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_create_bond(bd_addr);
+}
+
+static int cancel_bond(const bt_bdaddr_t *bd_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_cancel_bond(bd_addr);
+}
+
+static int remove_bond(const bt_bdaddr_t *bd_addr)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_remove_bond(bd_addr);
+}
+
+static int pin_reply(const bt_bdaddr_t *bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t *pin_code)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_pin_reply(bd_addr, accept, pin_len, pin_code);
+}
+
+static int ssp_reply(const bt_bdaddr_t *bd_addr, bt_ssp_variant_t variant,
+ uint8_t accept, uint32_t passkey)
+{
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_ssp_reply(bd_addr, variant, accept, passkey);
+}
+
+static const void* get_profile_interface (const char *profile_id)
+{
+ ALOGI("get_profile_interface %s", profile_id);
+
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return NULL;
+
+ /* check for supported profile interfaces */
+ if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
+ return btif_hf_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID))
+ return btif_sock_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_PAN_ID))
+ return btif_pan_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
+ return btif_av_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
+ return btif_hh_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_HEALTH_ID))
+ return btif_hl_get_interface();
+ return NULL;
+}
+
+int dut_mode_configure(uint8_t enable)
+{
+ ALOGI("dut_mode_configure");
+
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dut_mode_configure(enable);
+}
+
+int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len)
+{
+ ALOGI("dut_mode_send");
+
+ /* sanity check */
+ if (interface_ready() == FALSE)
+ return BT_STATUS_NOT_READY;
+
+ return btif_dut_mode_send(opcode, buf, len);
+}
+static const bt_interface_t bluetoothInterface = {
+ sizeof(bt_interface_t),
+ init,
+ enable,
+ disable,
+ cleanup,
+ get_adapter_properties,
+ get_adapter_property,
+ set_adapter_property,
+ get_remote_device_properties,
+ get_remote_device_property,
+ set_remote_device_property,
+ get_remote_service_record,
+ get_remote_services,
+ start_discovery,
+ cancel_discovery,
+ create_bond,
+ remove_bond,
+ cancel_bond,
+ pin_reply,
+ ssp_reply,
+ get_profile_interface,
+ dut_mode_configure,
+ dut_mode_send
+};
+
+const bt_interface_t* bluetooth__get_bluetooth_interface ()
+{
+ /* fixme -- add property to disable bt interface ? */
+
+ return &bluetoothInterface;
+}
+
+static int close_bluetooth_stack(struct hw_device_t* device)
+{
+ cleanup();
+ return 0;
+}
+
+static int open_bluetooth_stack (const struct hw_module_t* module, char const* name,
+struct hw_device_t** abstraction)
+{
+ bluetooth_device_t *stack = malloc(sizeof(bluetooth_device_t) );
+ memset(stack, 0, sizeof(bluetooth_device_t) );
+ stack->common.tag = HARDWARE_DEVICE_TAG;
+ stack->common.version = 0;
+ stack->common.module = (struct hw_module_t*)module;
+ stack->common.close = close_bluetooth_stack;
+ stack->get_bluetooth_interface = bluetooth__get_bluetooth_interface;
+ *abstraction = (struct hw_device_t*)stack;
+ return 0;
+}
+
+
+static struct hw_module_methods_t bt_stack_module_methods = {
+ .open = open_bluetooth_stack,
+};
+
+struct hw_module_t HAL_MODULE_INFO_SYM = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = BT_HARDWARE_MODULE_ID,
+ .name = "Bluetooth Stack",
+ .author = "The Android Open Source Project",
+ .methods = &bt_stack_module_methods
+};
+
diff --git a/btif/src/btif_av.c b/btif/src/btif_av.c
new file mode 100755
index 0000000..4419c22
--- /dev/null
+++ b/btif/src/btif_av.c
@@ -0,0 +1,970 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Filename: btif_av.c
+ *
+ * Description: Bluedroid AV implementation
+ *
+ *****************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include "hardware/bt_av.h"
+
+#define LOG_TAG "BTIF_AV"
+
+#include "btif_av.h"
+#include "btif_util.h"
+#include "btif_profile_queue.h"
+#include "bta_api.h"
+#include "btif_media.h"
+#include "bta_av_api.h"
+#include "gki.h"
+#include "bd.h"
+#include "btu.h"
+
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+#define BTIF_AV_SERVICE_NAME "Advanced Audio"
+
+#define BTIF_TIMEOUT_AV_OPEN_ON_RC_SECS 2
+
+typedef enum {
+ BTIF_AV_STATE_IDLE = 0x0,
+ BTIF_AV_STATE_OPENING,
+ BTIF_AV_STATE_OPENED,
+ BTIF_AV_STATE_STARTED,
+ BTIF_AV_STATE_CLOSING
+} btif_av_state_t;
+
+/* Should not need dedicated suspend state as actual actions are no
+ different than open state. Suspend flags are needed however to prevent
+ media task from trying to restart stream during remote suspend or while
+ we are in the process of a local suspend */
+
+#define BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING 0x1
+#define BTIF_AV_FLAG_REMOTE_SUSPEND 0x2
+
+/*****************************************************************************
+** Local type definitions
+******************************************************************************/
+
+typedef struct
+{
+ tBTA_AV_HNDL bta_handle;
+ bt_bdaddr_t peer_bda;
+ btif_sm_handle_t sm_handle;
+ UINT8 flags;
+} btif_av_cb_t;
+
+/*****************************************************************************
+** Static variables
+******************************************************************************/
+static btav_callbacks_t *bt_av_callbacks = NULL;
+static btif_av_cb_t btif_av_cb;
+static TIMER_LIST_ENT tle_av_open_on_rc;
+
+/* both interface and media task needs to be ready to alloc incoming request */
+#define CHECK_BTAV_INIT() if ((bt_av_callbacks == NULL) || (btif_av_cb.sm_handle == NULL))\
+{\
+ BTIF_TRACE_WARNING1("%s: BTAV not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+}\
+else\
+{\
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);\
+}
+
+/* Helper macro to avoid code duplication in the state machine handlers */
+#define CHECK_RC_EVENT(e, d) \
+ case BTA_AV_RC_OPEN_EVT: \
+ case BTA_AV_RC_CLOSE_EVT: \
+ case BTA_AV_REMOTE_CMD_EVT: \
+ case BTA_AV_VENDOR_CMD_EVT: \
+ case BTA_AV_META_MSG_EVT: \
+ case BTA_AV_RC_FEAT_EVT: \
+ { \
+ btif_rc_handler(e, d);\
+ }break; \
+
+static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *data);
+static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *data);
+static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *data);
+static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *data);
+static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *data);
+
+static const btif_sm_handler_t btif_av_state_handlers[] =
+{
+ btif_av_state_idle_handler,
+ btif_av_state_opening_handler,
+ btif_av_state_opened_handler,
+ btif_av_state_started_handler,
+ btif_av_state_closing_handler
+};
+
+/*************************************************************************
+** Extern functions
+*************************************************************************/
+extern void btif_rc_init(void);
+extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data);
+extern BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr);
+extern void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp);
+
+/*****************************************************************************
+** Local helper functions
+******************************************************************************/
+
+const char *dump_av_sm_state_name(btif_av_state_t state)
+{
+ switch (state)
+ {
+ CASE_RETURN_STR(BTIF_AV_STATE_IDLE)
+ CASE_RETURN_STR(BTIF_AV_STATE_OPENING)
+ CASE_RETURN_STR(BTIF_AV_STATE_OPENED)
+ CASE_RETURN_STR(BTIF_AV_STATE_STARTED)
+ CASE_RETURN_STR(BTIF_AV_STATE_CLOSING)
+ default: return "UNKNOWN_STATE";
+ }
+}
+
+const char *dump_av_sm_event_name(btif_av_sm_event_t event)
+{
+ switch((int)event)
+ {
+ CASE_RETURN_STR(BTA_AV_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_AV_REGISTER_EVT)
+ CASE_RETURN_STR(BTA_AV_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AV_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AV_START_EVT)
+ CASE_RETURN_STR(BTA_AV_STOP_EVT)
+ CASE_RETURN_STR(BTA_AV_PROTECT_REQ_EVT)
+ CASE_RETURN_STR(BTA_AV_PROTECT_RSP_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT)
+ CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT)
+ CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
+ CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
+ CASE_RETURN_STR(BTA_AV_RECONFIG_EVT)
+ CASE_RETURN_STR(BTA_AV_SUSPEND_EVT)
+ CASE_RETURN_STR(BTA_AV_PENDING_EVT)
+ CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
+ CASE_RETURN_STR(BTA_AV_REJECT_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
+ CASE_RETURN_STR(BTIF_SM_ENTER_EVT)
+ CASE_RETURN_STR(BTIF_SM_EXIT_EVT)
+ CASE_RETURN_STR(BTIF_AV_CONNECT_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_DISCONNECT_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_START_STREAM_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_STOP_STREAM_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_RECONFIGURE_REQ_EVT)
+
+ default: return "UNKNOWN_EVENT";
+ }
+}
+
+/****************************************************************************
+** Local helper functions
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function btif_initiate_av_open_tmr_hdlr
+**
+** Description Timer to trigger AV open if the remote headset establishes
+** RC connection w/o AV connection. The timer is needed to IOP
+** with headsets that do establish AV after RC connection.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_initiate_av_open_tmr_hdlr(TIMER_LIST_ENT *tle)
+{
+ BD_ADDR peer_addr;
+
+ /* is there at least one RC connection - There should be */
+ if (btif_rc_get_connected_peer(peer_addr)) {
+ BTIF_TRACE_DEBUG1("%s Issuing connect to the remote RC peer", __FUNCTION__);
+ btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (void*)&peer_addr);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR1("%s No connected RC peers", __FUNCTION__);
+ }
+}
+
+/*****************************************************************************
+** Static functions
+******************************************************************************/
+
+/*****************************************************************************
+**
+** Function btif_av_state_idle_handler
+**
+** Description State managing disconnected AV link
+**
+** Returns TRUE if event was processed, FALSE otherwise
+**
+*******************************************************************************/
+
+static BOOLEAN btif_av_state_idle_handler(btif_sm_event_t event, void *p_data)
+{
+ BTIF_TRACE_DEBUG3("%s event:%s flags %x", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb.flags);
+
+ switch (event)
+ {
+ case BTIF_SM_ENTER_EVT:
+ /* clear the peer_bda */
+ memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t));
+ btif_av_cb.flags = 0;
+ btif_a2dp_on_idle();
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ case BTA_AV_ENABLE_EVT:
+ break;
+
+ case BTA_AV_REGISTER_EVT:
+ btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
+ break;
+
+ case BTA_AV_PENDING_EVT:
+ case BTIF_AV_CONNECT_REQ_EVT:
+ {
+ if (event == BTIF_AV_CONNECT_REQ_EVT)
+ {
+ memcpy(&btif_av_cb.peer_bda, (bt_bdaddr_t*)p_data, sizeof(bt_bdaddr_t));
+ }
+ else if (event == BTA_AV_PENDING_EVT)
+ {
+ bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
+ }
+ BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle,
+ TRUE, BTA_SEC_NONE);
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
+ } break;
+
+ case BTA_AV_RC_OPEN_EVT:
+ /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So
+ * as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore,
+ * we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state.
+ * We initiate the AV connection after a small 3s timeout to avoid any collisions from the
+ * headsets, as some headsets initiate the AVRC connection first and then
+ * immediately initiate the AV connection
+ *
+ * TODO: We may need to do this only on an AVRCP Play. FixMe
+ */
+
+ BTIF_TRACE_DEBUG0("BTA_AV_RC_OPEN_EVT received w/o AV");
+ memset(&tle_av_open_on_rc, 0, sizeof(tle_av_open_on_rc));
+ tle_av_open_on_rc.param = (UINT32)btif_initiate_av_open_tmr_hdlr;
+ btu_start_timer(&tle_av_open_on_rc, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_AV_OPEN_ON_RC_SECS);
+ btif_rc_handler(event, p_data);
+ break;
+
+ case BTA_AV_REMOTE_CMD_EVT:
+ case BTA_AV_VENDOR_CMD_EVT:
+ case BTA_AV_META_MSG_EVT:
+ case BTA_AV_RC_FEAT_EVT:
+ btif_rc_handler(event, (tBTA_AV*)p_data);
+ break;
+
+ case BTA_AV_RC_CLOSE_EVT:
+ if (tle_av_open_on_rc.in_use) {
+ BTIF_TRACE_DEBUG0("BTA_AV_RC_CLOSE_EVT: Stopping AV timer.");
+ btu_stop_timer(&tle_av_open_on_rc);
+ }
+ btif_rc_handler(event, p_data);
+ break;
+
+ default:
+ BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__,
+ dump_av_sm_event_name(event));
+ return FALSE;
+
+ }
+ return TRUE;
+}
+/*****************************************************************************
+**
+** Function btif_av_state_opening_handler
+**
+** Description Intermediate state managing events during establishment
+** of avdtp channel
+**
+** Returns TRUE if event was processed, FALSE otherwise
+**
+*******************************************************************************/
+
+static BOOLEAN btif_av_state_opening_handler(btif_sm_event_t event, void *p_data)
+{
+ BTIF_TRACE_DEBUG3("%s event:%s flags %x", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb.flags);
+
+ switch (event)
+ {
+ case BTIF_SM_ENTER_EVT:
+ /* inform the application that we are entering connecting state */
+ HAL_CBACK(bt_av_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_CONNECTING, &(btif_av_cb.peer_bda));
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ case BTA_AV_OPEN_EVT:
+ {
+ tBTA_AV *p_bta_data = (tBTA_AV*)p_data;
+ btav_connection_state_t state;
+ btif_sm_state_t av_state;
+ BTIF_TRACE_DEBUG1("status:%d", p_bta_data->open.status);
+
+ if (p_bta_data->open.status == BTA_AV_SUCCESS)
+ {
+ state = BTAV_CONNECTION_STATE_CONNECTED;
+ av_state = BTIF_AV_STATE_OPENED;
+ }
+ else
+ {
+ BTIF_TRACE_WARNING1("BTA_AV_OPEN_EVT::FAILED status: %d",
+ p_bta_data->open.status );
+ state = BTAV_CONNECTION_STATE_DISCONNECTED;
+ av_state = BTIF_AV_STATE_IDLE;
+ }
+
+ /* inform the application of the event */
+ HAL_CBACK(bt_av_callbacks, connection_state_cb,
+ state, &(btif_av_cb.peer_bda));
+ /* change state to open/idle based on the status */
+ btif_sm_change_state(btif_av_cb.sm_handle, av_state);
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
+ (p_bta_data->open.status == BTA_AV_SUCCESS));
+ btif_queue_advance();
+ } break;
+
+ CHECK_RC_EVENT(event, p_data);
+
+ default:
+ BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__,
+ dump_av_sm_event_name(event));
+ return FALSE;
+
+ }
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Function btif_av_state_closing_handler
+**
+** Description Intermediate state managing events during closing
+** of avdtp channel
+**
+** Returns TRUE if event was processed, FALSE otherwise
+**
+*******************************************************************************/
+
+static BOOLEAN btif_av_state_closing_handler(btif_sm_event_t event, void *p_data)
+{
+ BTIF_TRACE_DEBUG3("%s event:%s flags %x", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb.flags);
+
+ switch (event)
+ {
+ case BTIF_SM_ENTER_EVT:
+
+ /* immediately stop transmission of frames */
+ btif_a2dp_set_tx_flush(TRUE);
+ /* wait for audioflinger to stop a2dp */
+ break;
+
+ case BTIF_AV_STOP_STREAM_REQ_EVT:
+ /* immediately flush any pending tx frames while suspend is pending */
+ btif_a2dp_set_tx_flush(TRUE);
+
+ btif_a2dp_on_stopped(NULL);
+
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ case BTA_AV_CLOSE_EVT:
+
+ /* inform the application that we are disconnecting */
+ HAL_CBACK(bt_av_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ /* Handle the RC_CLOSE event for the cleanup */
+ case BTA_AV_RC_CLOSE_EVT:
+ btif_rc_handler(event, (tBTA_AV*)p_data);
+ break;
+
+ default:
+ BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__,
+ dump_av_sm_event_name(event));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Function btif_av_state_opened_handler
+**
+** Description Handles AV events while AVDTP is in OPEN state
+**
+** Returns TRUE if event was processed, FALSE otherwise
+**
+*******************************************************************************/
+
+static BOOLEAN btif_av_state_opened_handler(btif_sm_event_t event, void *p_data)
+{
+ tBTA_AV *p_av = (tBTA_AV*)p_data;
+
+ BTIF_TRACE_DEBUG3("%s event:%s flags %x", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb.flags);
+
+ if ( (event == BTA_AV_REMOTE_CMD_EVT) && (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND) &&
+ (p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY) )
+ {
+ BTIF_TRACE_EVENT1("%s: Resetting remote suspend flag on RC PLAY", __FUNCTION__);
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ }
+
+ switch (event)
+ {
+ case BTIF_SM_ENTER_EVT:
+ btif_media_check_iop_exceptions(btif_av_cb.peer_bda.address);
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ case BTIF_AV_START_STREAM_REQ_EVT:
+ btif_a2dp_setup_codec();
+ BTA_AvStart();
+ break;
+
+ case BTA_AV_START_EVT:
+ {
+ BTIF_TRACE_EVENT3("BTA_AV_START_EVT status %d, suspending %d, init %d",
+ p_av->start.status, p_av->start.suspending, p_av->start.initiator);
+
+ if ((p_av->start.status == BTA_SUCCESS) && (p_av->start.suspending == TRUE))
+ return TRUE;
+
+ btif_a2dp_on_started(&p_av->start);
+
+ /* remain in open state if status failed */
+ if (p_av->start.status != BTA_AV_SUCCESS)
+ return FALSE;
+
+ /* change state to started */
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED);
+
+ } break;
+
+ case BTIF_AV_DISCONNECT_REQ_EVT:
+ BTA_AvClose(btif_av_cb.bta_handle);
+
+ /* inform the application that we are disconnecting */
+ HAL_CBACK(bt_av_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
+ break;
+
+ case BTA_AV_CLOSE_EVT:
+
+ /* inform the application that we are disconnected */
+ HAL_CBACK(bt_av_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ CHECK_RC_EVENT(event, p_data);
+
+ default:
+ BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__,
+ dump_av_sm_event_name(event));
+ return FALSE;
+
+ }
+ return TRUE;
+}
+
+/*****************************************************************************
+**
+** Function btif_av_state_started_handler
+**
+** Description Handles AV events while A2DP stream is started
+**
+** Returns TRUE if event was processed, FALSE otherwise
+**
+*******************************************************************************/
+
+static BOOLEAN btif_av_state_started_handler(btif_sm_event_t event, void *p_data)
+{
+ tBTA_AV *p_av = (tBTA_AV*)p_data;
+
+ BTIF_TRACE_DEBUG3("%s event:%s flags %x", __FUNCTION__,
+ dump_av_sm_event_name(event), btif_av_cb.flags);
+
+ switch (event)
+ {
+ case BTIF_SM_ENTER_EVT:
+
+ /* we are again in started state, clear any remote suspend flags */
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+
+ HAL_CBACK(bt_av_callbacks, audio_state_cb,
+ BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda));
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ /* fixme -- use suspend = true always to work around issue with BTA AV */
+ case BTIF_AV_STOP_STREAM_REQ_EVT:
+ case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+
+ /* set pending flag to ensure btif task is not trying to restart
+ stream while suspend is in progress */
+ btif_av_cb.flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+
+ /* if we were remotely suspended but suspend locally, local suspend
+ always overrides */
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+
+ /* immediately stop transmission of frames while suspend is pending */
+ btif_a2dp_set_tx_flush(TRUE);
+
+ BTA_AvStop(TRUE);
+ break;
+
+ case BTIF_AV_DISCONNECT_REQ_EVT:
+
+ /* request avdtp to close */
+ BTA_AvClose(btif_av_cb.bta_handle);
+
+ /* inform the application that we are disconnecting */
+ HAL_CBACK(bt_av_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_DISCONNECTING, &(btif_av_cb.peer_bda));
+
+ /* wait in closing state until fully closed */
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_CLOSING);
+ break;
+
+ case BTA_AV_SUSPEND_EVT:
+
+ BTIF_TRACE_EVENT2("BTA_AV_SUSPEND_EVT status %d, init %d",
+ p_av->suspend.status, p_av->suspend.initiator);
+
+ /* a2dp suspended, stop media task until resumed */
+ btif_a2dp_on_suspended(&p_av->suspend);
+
+ /* if not successful, remain in current state */
+ if (p_av->suspend.status != BTA_AV_SUCCESS)
+ {
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+
+ /* suspend failed, reset back tx flush state */
+ btif_a2dp_set_tx_flush(FALSE);
+ return FALSE;
+ }
+
+ if (p_av->suspend.initiator != TRUE)
+ {
+ /* remote suspend, notify HAL and await audioflinger to
+ suspend/stop stream */
+
+ /* set remote suspend flag to block media task from restarting
+ stream only if we did not already initiate a local suspend */
+ if ((btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0)
+ btif_av_cb.flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
+
+ HAL_CBACK(bt_av_callbacks, audio_state_cb,
+ BTAV_AUDIO_STATE_REMOTE_SUSPEND, &(btif_av_cb.peer_bda));
+ }
+ else
+ {
+ HAL_CBACK(bt_av_callbacks, audio_state_cb,
+ BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
+ }
+
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+
+ /* suspend completed and state changed, clear pending status */
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ break;
+
+ case BTA_AV_STOP_EVT:
+
+ btif_a2dp_on_stopped(&p_av->suspend);
+
+ HAL_CBACK(bt_av_callbacks, audio_state_cb,
+ BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
+
+ /* if stop was successful, change state to open */
+ if (p_av->suspend.status == BTA_AV_SUCCESS)
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+
+ break;
+
+ case BTA_AV_CLOSE_EVT:
+
+ /* avdtp link is closed */
+
+ btif_a2dp_on_stopped(NULL);
+
+ /* inform the application that we are disconnected */
+ HAL_CBACK(bt_av_callbacks, connection_state_cb,
+ BTAV_CONNECTION_STATE_DISCONNECTED, &(btif_av_cb.peer_bda));
+
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ CHECK_RC_EVENT(event, p_data);
+
+ default:
+ BTIF_TRACE_WARNING2("%s : unhandled event:%s", __FUNCTION__,
+ dump_av_sm_event_name(event));
+ return FALSE;
+
+ }
+ return TRUE;
+}
+
+/*****************************************************************************
+** Local event handlers
+******************************************************************************/
+
+static void btif_av_handle_event(UINT16 event, char* p_param)
+{
+ btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
+}
+
+static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data)
+{
+ /* Switch to BTIF context */
+ btif_transfer_context(btif_av_handle_event, event,
+ (char*)p_data, sizeof(tBTA_AV), NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_av_init
+**
+** Description Initializes btif AV if not already done
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_av_init(void)
+{
+ if (btif_av_cb.sm_handle == NULL)
+ {
+ if (btif_a2dp_start_media_task() != GKI_SUCCESS)
+ return BT_STATUS_FAIL;
+
+ btif_enable_service(BTA_A2DP_SERVICE_ID);
+
+ /* Initialize the AVRC CB */
+ btif_rc_init();
+
+ /* Also initialize the AV state machine */
+ btif_av_cb.sm_handle = btif_sm_init((const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
+
+ btif_a2dp_on_init();
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_DONE;
+}
+
+/*******************************************************************************
+**
+** Function init
+**
+** Description Initializes the AV interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+static bt_status_t init(btav_callbacks_t* callbacks )
+{
+ int status;
+
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ if (bt_av_callbacks)
+ return BT_STATUS_DONE;
+
+ bt_av_callbacks = callbacks;
+ btif_av_cb.sm_handle = NULL;
+
+ return btif_av_init();
+}
+
+/*******************************************************************************
+**
+** Function connect
+**
+** Description Establishes the AV signalling channel with the remote headset
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+static bt_status_t connect_int(bt_bdaddr_t *bd_addr)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT, (char*)bd_addr);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t connect(bt_bdaddr_t *bd_addr)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ CHECK_BTAV_INIT();
+
+ return btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+**
+** Function disconnect
+**
+** Description Tears down the AV signalling channel with the remote headset
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ CHECK_BTAV_INIT();
+
+ /* Switch to BTIF context */
+ return btif_transfer_context(btif_av_handle_event, BTIF_AV_DISCONNECT_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+}
+
+/*******************************************************************************
+**
+** Function cleanup
+**
+** Description Shuts down the AV interface and does the cleanup
+**
+** Returns None
+**
+*******************************************************************************/
+static void cleanup(void)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ if (bt_av_callbacks)
+ {
+ btif_a2dp_stop_media_task();
+
+ btif_disable_service(BTA_A2DP_SERVICE_ID);
+ bt_av_callbacks = NULL;
+
+ /* Also shut down the AV state machine */
+ btif_sm_shutdown(btif_av_cb.sm_handle);
+ btif_av_cb.sm_handle = NULL;
+ }
+ return;
+}
+
+static const btav_interface_t bt_av_interface = {
+ sizeof(btav_interface_t),
+ init,
+ connect,
+ disconnect,
+ cleanup,
+};
+
+/*******************************************************************************
+**
+** Function btif_av_get_sm_handle
+**
+** Description Fetches current av SM handle
+**
+** Returns None
+**
+*******************************************************************************/
+
+btif_sm_handle_t btif_av_get_sm_handle(void)
+{
+ return btif_av_cb.sm_handle;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_stream_ready
+**
+** Description Checks whether AV is ready for starting a stream
+**
+** Returns None
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_stream_ready(void)
+{
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+
+ BTIF_TRACE_DEBUG3("btif_av_stream_ready : sm hdl %d, state %d, flags %x",
+ btif_av_cb.sm_handle, state, btif_av_cb.flags);
+
+ /* also make sure main adapter is enabled */
+ if (btif_is_enabled() == 0)
+ {
+ BTIF_TRACE_EVENT0("main adapter not enabled");
+ return FALSE;
+ }
+
+ /* check if we are remotely suspended */
+ if (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND)
+ return FALSE;
+
+ return (state == BTIF_AV_STATE_OPENED);
+}
+
+/*******************************************************************************
+**
+** Function btif_av_stream_started_ready
+**
+** Description Checks whether AV ready for media start in streaming state
+**
+** Returns None
+**
+*******************************************************************************/
+
+BOOLEAN btif_av_stream_started_ready(void)
+{
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+
+ BTIF_TRACE_DEBUG3("btif_av_stream_started : sm hdl %d, state %d, flags %x",
+ btif_av_cb.sm_handle, state, btif_av_cb.flags);
+
+ /* don't allow media task to start if we are suspending or
+ remotely suspended (not yet changed state) */
+ if (btif_av_cb.flags & (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING | BTIF_AV_FLAG_REMOTE_SUSPEND))
+ return FALSE;
+
+ return (state == BTIF_AV_STATE_STARTED);
+}
+
+/*******************************************************************************
+**
+** Function btif_dispatch_sm_event
+**
+** Description Send event to AV statemachine
+**
+** Returns None
+**
+*******************************************************************************/
+
+/* used to pass events to AV statemachine from other tasks */
+void btif_dispatch_sm_event(btif_av_sm_event_t event, void *p_data, int len)
+{
+ /* Switch to BTIF context */
+ btif_transfer_context(btif_av_handle_event, event,
+ (char*)p_data, len, NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_av_execute_service
+**
+** Description Initializes/Shuts down the service
+**
+** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_av_execute_service(BOOLEAN b_enable)
+{
+ if (b_enable)
+ {
+ /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
+ * handle this request in order to allow incoming connections to succeed.
+ * We need to put this back once support for this is added */
+
+ /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+ * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+ * be initiated by the app/audioflinger layers */
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD),
+ bte_av_callback);
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0);
+ }
+ else {
+ BTA_AvDeregister(btif_av_cb.bta_handle);
+ BTA_AvDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_get_interface
+**
+** Description Get the AV callback interface
+**
+** Returns btav_interface_t
+**
+*******************************************************************************/
+const btav_interface_t *btif_av_get_interface(void)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ return &bt_av_interface;
+}
+
+/*******************************************************************************
+**
+** Function btif_av_is_rc_open_without_a2dp
+**
+** Description Checks if GAVDTP Open notification to app is pending (2 second timer)
+**
+** Returns boolean
+**
+*******************************************************************************/
+BOOLEAN btif_av_is_connected(void)
+{
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+ return ((state == BTIF_AV_STATE_OPENED) || (state == BTIF_AV_STATE_STARTED));
+}
diff --git a/btif/src/btif_config.c b/btif/src/btif_config.c
new file mode 100644
index 0000000..00e40bd
--- /dev/null
+++ b/btif/src/btif_config.c
@@ -0,0 +1,744 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_config.c
+ *
+ * Description: Stores the local BT adapter and remote device properties in
+ * NVRAM storage, typically as xml file in the
+ * mobile's filesystem
+ *
+ *
+ ***********************************************************************************/
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <private/android_filesystem_config.h>
+
+#define LOG_TAG "btif_config.c"
+
+#include <hardware/bluetooth.h>
+#include "btif_config.h"
+#include "btif_config_util.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define warn(fmt, ...) ALOGW ("## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+//#define UNIT_TEST
+#define CFG_PATH "/data/misc/bluedroid/"
+#define CFG_FILE_NAME "bt_config"
+#define CFG_FILE_EXT ".xml"
+#define CFG_FILE_EXT_OLD ".old"
+#define CFG_FILE_EXT_NEW ".new"
+#define CFG_GROW_SIZE (10*sizeof(cfg_node))
+#define GET_CHILD_MAX_COUNT(node) (short)((int)(node)->bytes / sizeof(cfg_node))
+#define IS_EMPTY(node) ((node)->name == NULL)
+#define GET_NODE_COUNT(bytes) (bytes / sizeof(cfg_node))
+#define MAX_NODE_BYTES 32000
+#define MAX_CACHED_COUNT 150
+#define CFG_CMD_SAVE 1
+
+#ifndef FALSE
+#define TRUE 1
+#define FALSE 0
+#endif
+typedef struct cfg_node_s
+{
+ const char* name;
+ union
+ {
+ struct cfg_node_s* child;
+ char* value;
+ };
+ short bytes;
+ short type;
+ short used;
+ short flag;
+} cfg_node;
+
+static pthread_mutex_t slot_lock;
+static int pth = -1; //poll thread handle
+static cfg_node root;
+static int cached_change;
+static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
+static inline short alloc_node(cfg_node* p, short grow);
+static inline void free_node(cfg_node* p);
+static inline void free_inode(cfg_node* p, int child);
+static inline short find_inode(const cfg_node* p, const char* name);
+static cfg_node* find_node(const char* section, const char* key, const char* name);
+static int remove_node(const char* section, const char* key, const char* name);
+static inline cfg_node* find_free_node(cfg_node* p);
+static int set_node(const char* section, const char* key, const char* name,
+ const char* value, short bytes, short type);
+static int save_cfg();
+static void load_cfg();
+static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
+static int create_dir(const char* path);
+#ifdef UNIT_TEST
+static void cfg_test_load();
+static void cfg_test_write();
+static void cfg_test_read();
+#endif
+static inline void dump_node(const char* title, const cfg_node* p)
+{
+ if(p)
+ debug("%s, p->name:%s, child/value:%p, bytes:%d, p->used:%d, type:%x, p->flag:%d",
+ title, p->name, p->child, p->bytes, p->used, p->type, p->flag);
+ else debug("%s is NULL", title);
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+int btif_config_init()
+{
+ static int initialized;
+ debug("in initialized:%d", initialized);
+ if(!initialized)
+ {
+ initialized = 1;
+ struct stat st;
+ if(stat(CFG_PATH, &st) != 0)
+ error("%s does not exist, need provision", CFG_PATH);
+ btsock_thread_init();
+ init_slot_lock(&slot_lock);
+ lock_slot(&slot_lock);
+ root.name = "Bluedroid";
+ alloc_node(&root, CFG_GROW_SIZE);
+ dump_node("root", &root);
+ pth = btsock_thread_create(NULL, cfg_cmd_callback);
+ load_cfg();
+ unlock_slot(&slot_lock);
+ #ifdef UNIT_TEST
+ //cfg_test_load();
+ cfg_test_write();
+ cfg_test_read();
+ #endif
+ }
+ return pth >= 0;
+}
+int btif_config_get_int(const char* section, const char* key, const char* name, int* value)
+{
+ int size = sizeof(*value);
+ int type = BTIF_CFG_TYPE_INT;
+ return btif_config_get(section, key, name, (char*)value, &size, &type);
+}
+int btif_config_set_int(const char* section, const char* key, const char* name, int value)
+{
+ return btif_config_set(section, key, name, (char*)&value, sizeof(value), BTIF_CFG_TYPE_INT);
+}
+int btif_config_get_str(const char* section, const char* key, const char* name, char* value, int* size)
+{
+ int type = BTIF_CFG_TYPE_STR;
+ if(value)
+ *value = 0;
+ return btif_config_get(section, key, name, value, size, &type);
+}
+int btif_config_set_str(const char* section, const char* key, const char* name, const char* value)
+{
+ value = value ? value : "";
+ return btif_config_set(section, key, name, value, strlen(value) + 1, BTIF_CFG_TYPE_STR);
+}
+int btif_config_exist(const char* section, const char* key, const char* name)
+{
+ int ret = FALSE;
+ if(section && *section && key && *key)
+ {
+ lock_slot(&slot_lock);
+ ret = find_node(section, key, name) != NULL;
+ unlock_slot(&slot_lock);
+ }
+ return ret;
+}
+int btif_config_get(const char* section, const char* key, const char* name, char* value, int* bytes, int* type)
+{
+ //debug("in");
+
+ int ret = FALSE;
+ asrt(section && *section && key && *key && name && *name && bytes && type);
+ //debug("section:%s, key:%s, name:%s, value:%p, bytes:%d, type:%d",
+ // section, key, name, value, *bytes, *type);
+ if(section && *section && key && *key && name && *name && bytes && type)
+ {
+ lock_slot(&slot_lock);
+ const cfg_node* node = find_node(section, key, name);
+ dump_node("found node", node);
+ if(node)
+ {
+ if(*type == node->type && value && *bytes >= node->used)
+ {
+ if(node->used > 0)
+ memcpy(value, node->value, node->used);
+ ret = TRUE;
+ }
+ *type = node->type;
+ *bytes = node->used;
+ if(ret != TRUE)
+ {
+ if(*type != node->type)
+ error("value:%s, wrong type:%d, need to be type: %d", name, *type, node->type);
+ if(value && *bytes < node->used)
+ error("value:%s, not enough size: %d bytes, need %d bytes", name, node->used, *bytes);
+ }
+ }
+ unlock_slot(&slot_lock);
+ }
+ //debug("out");
+ return ret;
+}
+int btif_config_set(const char* section, const char* key, const char* name, const char* value, int bytes, int type)
+{
+ int ret = FALSE;
+ asrt(section && *section && key && *key && name && *name);
+ asrt(bytes < MAX_NODE_BYTES);
+ if(section && *section && key && *key && name && *name && bytes < MAX_NODE_BYTES)
+ {
+ lock_slot(&slot_lock);
+ ret = set_node(section, key, name, value, (short)bytes, (short)type);
+ if(ret && !(type & BTIF_CFG_TYPE_VOLATILE) && ++cached_change > MAX_CACHED_COUNT)
+ {
+ cached_change = 0;
+ btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
+ }
+
+ unlock_slot(&slot_lock);
+ }
+ return ret;
+}
+int btif_config_remove(const char* section, const char* key, const char* name)
+{
+ asrt(section && *section && key && *key);
+ int ret = FALSE;
+ if(section && *section && key && *key)
+ {
+ lock_slot(&slot_lock);
+ ret = remove_node(section, key, name);
+ if(ret)
+ cached_change++;
+ unlock_slot(&slot_lock);
+ }
+ return ret;
+}
+typedef struct {
+ short si;
+ short ki;
+ short vi;
+ short reserved;
+} cfg_node_pos;
+short btif_config_next_key(short pos, const char* section, char * name, int* bytes)
+{
+ int next = -1;
+ lock_slot(&slot_lock);
+ short si = find_inode(&root, section);
+ if(si >= 0)
+ {
+ const cfg_node* section_node = &root.child[si];
+ next = find_next_node(section_node, pos, name, bytes);
+ }
+ unlock_slot(&slot_lock);
+ return next;
+}
+short btif_config_next_value(short pos, const char* section, const char* key, char* name, int* bytes)
+{
+ int next = -1;
+ lock_slot(&slot_lock);
+ short si = find_inode(&root, section);
+ if(si >= 0)
+ {
+ const cfg_node* section_node = &root.child[si];
+ short ki = find_inode(section_node, key);
+ if(ki >= 0)
+ {
+ const cfg_node* key_node = &section_node->child[ki];
+ next = find_next_node(key_node, pos, name, bytes);
+ }
+ }
+ unlock_slot(&slot_lock);
+ return next;
+}
+int btif_config_enum(btif_config_enum_callback cb, void* user_data)
+{
+ asrt(cb);
+ if(!cb)
+ return FALSE;
+ lock_slot(&slot_lock);
+ int si, ki, vi;
+ cfg_node *section_node, *key_node, *value_node;
+ for(si = 0; si < GET_CHILD_MAX_COUNT(&root); si++)
+ {
+ section_node = &root.child[si];
+ if(section_node->name && *section_node->name)
+ {
+ for(ki = 0; ki < GET_CHILD_MAX_COUNT(section_node); ki++)
+ {
+ key_node = &section_node->child[ki];
+ if(key_node->name && *key_node->name)
+ {
+ for(vi = 0; vi < GET_CHILD_MAX_COUNT(key_node); vi++)
+ {
+ value_node = &key_node->child[vi];
+ if(value_node->name && *value_node->name)
+ {
+ cb(user_data, section_node->name, key_node->name, value_node->name,
+ value_node->value, value_node->used, value_node->type);
+ }
+ }
+ }
+ }
+ }
+ }
+ unlock_slot(&slot_lock);
+ return TRUE;
+}
+int btif_config_save()
+{
+ lock_slot(&slot_lock);
+ if(cached_change > 0)
+ {
+ cached_change = 0;
+ btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
+ }
+ unlock_slot(&slot_lock);
+ return TRUE;
+}
+void btif_config_flush()
+{
+ lock_slot(&slot_lock);
+ if(cached_change > 0)
+ save_cfg();
+ unlock_slot(&slot_lock);
+}
+/////////////////////////////////////////////////////////////////////////////////////////////
+static inline short alloc_node(cfg_node* p, short grow)
+{
+ int new_bytes = p->bytes + grow;
+ //debug("in, bytes:%d, new bytes:%d, grow:%d", p->bytes, new_bytes, grow);
+ if(grow > 0 && new_bytes < MAX_NODE_BYTES)
+ {
+ char* value = (char*)realloc(p->value, new_bytes);
+ if(value)
+ {
+ short old_bytes = p->bytes;
+ //clear to zero
+ memset(value + old_bytes, 0, grow);
+ p->bytes = old_bytes + grow;
+ p->value = value;
+ //debug("out");
+ return old_bytes;//return the previous size
+ }
+ else error("realloc failed, old_bytes:%d, grow:%d, total:%d", p->bytes, grow, p->bytes + grow);
+ }
+ //debug("out, alloc failed");
+ return -1;
+}
+static inline void free_node(cfg_node* p)
+{
+ if(p)
+ {
+ if(p->child)
+ {
+ free(p->child);
+ p->child = NULL;
+ }
+ if(p->name)
+ {
+ free((void*)p->name);
+ p->name = 0;
+ }
+ p->used = p->bytes = p->flag = p->type = 0;
+ }
+}
+static inline short find_inode(const cfg_node* p, const char* name)
+{
+ //debug("in");
+ if(p && p->child && name && *name)
+ {
+ int i;
+ int count = GET_CHILD_MAX_COUNT(p);
+ //debug("child name:%s, child max count:%d", name, count);
+ for(i = 0; i < count; i++)
+ {
+ if(p->child[i].name && *p->child[i].name &&
+ strcmp(p->child[i].name, name) == 0)
+ {
+ //debug("out found child index:%d", i);
+ return (short)i;
+ }
+ }
+ }
+ //debug("out, child name: %s not found", name);
+ return -1;
+}
+static inline cfg_node* find_free_node(cfg_node* p)
+{
+ if(p && p->child)
+ {
+ int i;
+ int count = GET_CHILD_MAX_COUNT(p);
+ //debug("p->name:%s, max child count:%d", p->name, count);
+ for(i = 0; i < count; i++)
+ {
+ if(IS_EMPTY(p->child + i))
+ return p->child + i;
+ }
+ }
+ return NULL;
+}
+static cfg_node* find_add_node(cfg_node* p, const char* name)
+{
+ int i = -1;
+ cfg_node* node = NULL;
+ //debug("in, p->name:%s, p->bytes:%d, adding child:%s", p->name, p->bytes, name);
+ if((i = find_inode(p, name)) < 0)
+ {
+ if(!(node = find_free_node(p)))
+ {
+ int old_size = alloc_node(p, CFG_GROW_SIZE);
+ if(old_size >= 0)
+ {
+ i = GET_NODE_COUNT(old_size);
+ node = &p->child[i];
+ }
+ }
+ }
+ else node = &p->child[i];
+ if(!node->name)
+ node->name = strdup(name);
+ //debug("out");
+ return node;
+}
+static int set_node(const char* section, const char* key, const char* name,
+ const char* value, short bytes, short type)
+{
+ int si = -1, ki = -1, vi = -1;
+ cfg_node* section_node = NULL;
+ //debug("in");
+ //dump_node("root", &root);
+ if((section_node = find_add_node(&root, section)))
+ {
+ //dump_node("section node", section_node);
+ cfg_node* key_node;
+ if((key_node = find_add_node(section_node, key)))
+ {
+ //dump_node("key node", key_node);
+ cfg_node* value_node;
+ if((value_node = find_add_node(key_node, name)))
+ {
+ //dump_node("value node", value_node);
+ if(value_node->bytes < bytes)
+ {
+ if(value_node->value)
+ free(value_node->value);
+ value_node->value = (char*)malloc(bytes);
+ if(value_node->value)
+ value_node->bytes = bytes;
+ else
+ {
+ error("not enough memory!");
+ value_node->bytes = 0;
+ return FALSE;
+ }
+ }
+ if(value_node->value && value != NULL && bytes > 0)
+ memcpy(value_node->value, value, bytes);
+ value_node->type = type;
+ value_node->used = bytes;
+ //dump_node("changed value node", value_node);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+static cfg_node* find_node(const char* section, const char* key, const char* name)
+{
+ int si = -1, ki = -1, vi = -1;
+ if((si = find_inode(&root, section)) >= 0)
+ {
+ cfg_node* section_node = &root.child[si];
+ if(key)
+ {
+ //dump_node("found section node", section_node);
+ if((ki = find_inode(section_node, key)) >= 0)
+ {
+ cfg_node* key_node = &section_node->child[ki];
+ //dump_node("found key node", key_node);
+ if(name)
+ {
+ if((vi = find_inode(key_node, name)) >= 0)
+ {
+ //dump_node("found value node", &key_node->child[vi]);
+ return &key_node->child[vi];
+ }
+ //debug("value node:%s not found", name);
+ return NULL;
+ }
+ return key_node;
+ }
+ //debug("key node:%s not found", key);
+ return NULL;
+ }
+ return section_node;
+ }
+ //debug("section node:%s not found", section);
+ return NULL;
+}
+static short find_next_node(const cfg_node* p, short start, char* name, int* bytes)
+{
+ asrt(0 <= start && start < GET_CHILD_MAX_COUNT(p));
+ //debug("in, start:%d, max child count:%d", start, GET_CHILD_MAX_COUNT(p));
+ //dump_node("find_next_node, parent", p);
+ short next = -1;
+ if(name) *name = 0;
+ if(0 <= start && start < GET_CHILD_MAX_COUNT(p))
+ {
+ int i;
+ for(i = start; i < GET_CHILD_MAX_COUNT(p); i++)
+ {
+ cfg_node* child = &p->child[i];
+ if(child->name)
+ {
+ int name_bytes = strlen(child->name) + 1;
+ if(name && bytes && *bytes >= name_bytes)
+ {
+ memcpy(name, child->name, name_bytes);
+ if(i + 1 < GET_CHILD_MAX_COUNT(p))
+ next = (short)(i + 1);
+ *bytes = name_bytes;
+ }
+ else if(bytes)
+ {
+ //debug("not enough room to copy the name, size in:%d, size needed:%d", *bytes, name_bytes);
+ *bytes = name_bytes;
+ }
+ break;
+ }
+ }
+ }
+ return next;
+}
+static int remove_node(const char* section, const char* key, const char* name)
+{
+ short si = -1, ki = -1, vi = -1;
+ if((si = find_inode(&root, section)) >= 0)
+ {
+ cfg_node* section_node = &root.child[si];
+ if((ki = find_inode(section_node, key)) >= 0)
+ {
+ cfg_node* key_node = &section_node->child[ki];
+ if(name == NULL)
+ {
+ int count = GET_CHILD_MAX_COUNT(key_node);
+ int i;
+ for(i = 0; i < count; i++)
+ free_node(&key_node->child[i]);
+ free_node(key_node);
+ return TRUE;
+ }
+ else if((vi = find_inode(key_node, name)) >= 0)
+ {
+ //debug("remove value:%s", key_node->child[vi].name);
+ free_node(&key_node->child[vi]);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+static int save_cfg()
+{
+ debug("in");
+ const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
+ const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
+ const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
+ int ret = FALSE;
+ if(access(file_name_old, F_OK) == 0)
+ unlink(file_name_old);
+ if(access(file_name_new, F_OK) == 0)
+ unlink(file_name_new);
+ if(btif_config_save_file(file_name_new))
+ {
+ cached_change = 0;
+ chown(file_name_new, -1, AID_NET_BT_STACK);
+ chmod(file_name_new, 0660);
+ rename(file_name, file_name_old);
+ rename(file_name_new, file_name);
+ ret = TRUE;
+ }
+ else error("btif_config_save_file failed");
+ debug("out");
+ return ret;
+}
+
+static int load_bluez_cfg()
+{
+ char adapter_path[256];
+ if(load_bluez_adapter_info(adapter_path, sizeof(adapter_path)))
+ {
+ if(load_bluez_linkkeys(adapter_path))
+ return TRUE;
+ }
+ return FALSE;
+}
+static void remove_bluez_cfg()
+{
+ rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
+}
+static void load_cfg()
+{
+ const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
+ const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
+ const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
+ if(!btif_config_load_file(file_name))
+ {
+ unlink(file_name);
+ if(!btif_config_load_file(file_name_old))
+ {
+ unlink(file_name_old);
+ if(load_bluez_cfg() && save_cfg())
+ remove_bluez_cfg();
+ }
+ }
+}
+static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id)
+{
+ debug("cmd type:%d, size:%d", type, size);
+ switch(type)
+ {
+ case CFG_CMD_SAVE:
+ lock_slot(&slot_lock);
+ save_cfg();
+ unlock_slot(&slot_lock);
+ break;
+ }
+}
+#ifdef UNIT_TEST
+static void cfg_test_load()
+{
+ load_cfg();
+ char kname[128], vname[128];
+ short kpos, vpos;
+ int kname_size, vname_size;
+ debug("in");
+ debug("list all remote devices values:");
+ kname_size = sizeof(kname);
+ kname[0] = 0;
+ kpos = 0;
+ do
+ {
+ kpos = btif_config_next_key(kpos, "Remote Devices", kname, &kname_size);
+ debug("Remote devices:%s, size:%d", kname, kname_size);
+ vpos = 0;
+ vname[0] = 0;
+ vname_size = sizeof(vname);
+ while((vpos = btif_config_next_value(vpos, "Remote Devices", kname, vname, &vname_size)) != -1)
+ {
+ char v[128] = {0};
+ int vtype = BTIF_CFG_TYPE_STR;
+ int vsize = sizeof(v);
+ int ret = btif_config_get("Remote Devices", kname, vname, v, &vsize, &vtype);
+ debug("btif_config_get return:%d, Remote devices:%s, value name:%s, value:%s, value size:%d, type:0x%x",
+ ret, kname, vname, v, vsize, vtype);
+
+ vname[0] = 0;
+ vname_size = sizeof(vname);
+ }
+ kname[0] = 0;
+ kname_size = sizeof(kname);
+ } while(kpos != -1);
+ debug("out");
+}
+static void cfg_test_write()
+{
+ debug("in");
+ int i;
+
+ char key[128];
+ const char* section;
+ char link_key[64];
+ for(i = 0; i < (int)sizeof(link_key); i++)
+ link_key[i] = i;
+ for(i = 0; i < 100; i++)
+ {
+ sprintf(key, "00:22:5F:97:56:%02d", i);
+ link_key[0] = i;
+ section = "Remote Devices";
+ btif_config_set_str(section, key, "class", "smart phone");
+ btif_config_set(section, key, "link keys", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
+ btif_config_set_int(section, key, "connect time out", i);
+ }
+ btif_config_save();
+ debug("out");
+}
+static void cfg_test_read()
+{
+ debug("in");
+ char class[128] = {0};
+ char link_key[128] = {0};
+ int size, type;
+ char key[128];
+ const char* section;
+ int ret, i;
+ for(i = 0; i < 100; i++)
+ {
+ sprintf(key, "00:22:5F:97:56:%02d", i);
+ section = "Remote Devices";
+ size = sizeof(class);
+ ret = btif_config_get_str(section, key, "class", class, &size);
+ debug("btif_config_get_str return:%d, Remote devices:%s, class:%s", ret, key, class);
+
+ size = sizeof(link_key);
+ type = BTIF_CFG_TYPE_BIN;
+ ret = btif_config_get(section, key, "link keys", link_key, &size, &type);
+ debug("btif_config_get return:%d, Remote devices:%s, link key:%x, %x",
+ ret, key, *(int *)link_key, *((int *)link_key + 1));
+
+ int timeout;
+ ret = btif_config_get_int(section, key, "connect time out", &timeout);
+ debug("btif_config_get_int return:%d, Remote devices:%s, connect time out:%d", ret, key, timeout);
+ }
+
+ debug("testing btif_config_remove");
+ size = sizeof(class);
+ type = BTIF_CFG_TYPE_STR;
+ btif_config_set("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, strlen(class) + 1, BTIF_CFG_TYPE_STR);
+
+ btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
+ debug("Remote devices, 00:22:5F:97:56:04 Class Delete:%s", class);
+ btif_config_remove("Remote Devices", "00:22:5F:97:56:04", "Class Delete");
+
+ size = sizeof(class);
+ type = BTIF_CFG_TYPE_STR;
+ ret = btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
+ debug("after removed, btif_config_get ret:%d, Remote devices, 00:22:5F:97:56:04 Class Delete:%s", ret, class);
+ debug("out");
+}
+#endif
diff --git a/btif/src/btif_config_util.cpp b/btif/src/btif_config_util.cpp
new file mode 100644
index 0000000..19fa30b
--- /dev/null
+++ b/btif/src/btif_config_util.cpp
@@ -0,0 +1,674 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+
+#include "btif_config.h"
+#include "btif_config_util.h"
+#ifndef ANDROID_NDK
+#define ANDROID_NDK
+#endif
+#include "tinyxml2.h"
+#ifndef FALSE
+#define TRUE 1
+#define FALSE 0
+#endif
+#define LOG_TAG "btif_config_util"
+extern "C" {
+#include "btif_sock_util.h"
+}
+#include <stdlib.h>
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define warn(fmt, ...) ALOGW ("## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+#define BLUEDROID_ROOT "Bluedroid"
+#define BLUEDROID_NAME_TAG "Tag"
+#define BLUEDROID_VALUE_TYPE "Type"
+#define BLUEDROID_TAG_REMOTE_DEVICE "Remote Devices"
+
+using namespace tinyxml2;
+struct enum_user_data
+{
+ const char* sn; //current section name
+ const char* kn; //current key name
+ const char* vn; //current value name
+ int si, ki, vi;
+ XMLDocument* xml;
+ XMLElement* se;
+ XMLElement* ke;
+ XMLElement* ve;
+};
+
+
+static int type_str2int(const char* type);
+static const char* type_int2str(int type);
+static inline void create_ele_name(int index, char* element, int len);
+static inline int validate_ele_name(const char* key);
+static int parse_sections(const char* section_name, const XMLElement* section);
+static void enum_config(void* user_data, const char* section, const char* key, const char* name,
+ const char* value, int bytes, int type);
+static inline void bytes2hex(const char* data, int bytes, char* str)
+{
+ static const char* hex_table = "0123456789abcdef";
+ for(int i = 0; i < bytes; i++)
+ {
+ *str = hex_table[(data[i] >> 4) & 0xf];
+ ++str;
+ *str = hex_table[data[i] & 0xf];
+ ++str;
+ }
+ *str = 0;
+}
+static inline int hex2byte(char hex)
+{
+ if('0' <= hex && hex <= '9')
+ return hex - '0';
+ if('a' <= hex && hex <= 'z')
+ return hex - 'a' + 0xa;
+ if('A' <= hex && hex <= 'Z')
+ return hex - 'A' + 0xa;
+ return -1;
+}
+static inline int trim_bin_str_value(const char** str)
+{
+ while(**str == ' ' || **str == '\r' || **str == '\t' || **str == '\n')
+ (*str)++;
+ int len = 0;
+ const char* s = *str;
+ while(*s && *s != ' ' && *s != '\r' && *s != '\t' && *s != '\n')
+ {
+ len++;
+ s++;
+ }
+ return len;
+}
+static inline bool hex2bytes(const char* str, int len, char* data)
+{
+ if(len % 2)
+ {
+ error("cannot convert odd len hex str: %s, len:%d to binary", str, len);
+ return false;
+ }
+ for(int i = 0; i < len; i+= 2)
+ {
+ int d = hex2byte(str[i]);
+ if(d < 0)
+ {
+ error("cannot convert hex: %s, len:%d to binary", str, len);
+ return false;
+ }
+ *data = (char)(d << 4);
+ d = hex2byte(str[i+1]);
+ if(d < 0)
+ {
+ error("cannot convert hex: %s, len:%d to binary", str, len);
+ return false;
+ }
+ *data++ |= (char)d;
+ }
+ return true;
+}
+static inline void reverse_bin(char *bin, int size)
+{
+ for(int i = 0; i < size /2; i++)
+ {
+ int b = bin[i];
+ bin[i] = bin[size - i - 1];
+ bin[size -i - 1] = b;
+ }
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////
+int btif_config_save_file(const char* file_name)
+{
+ debug("in file name:%s", file_name);
+ XMLDocument xml;
+ XMLElement* root = xml.NewElement(BLUEDROID_ROOT);
+ xml.InsertFirstChild(root);
+ int ret = FALSE;
+ enum_user_data data;
+ memset(&data, 0, sizeof(data));
+ data.xml = &xml;
+ if(btif_config_enum(enum_config, &data))
+ ret = xml.SaveFile(file_name) == XML_SUCCESS;
+ return ret;
+}
+int btif_config_load_file(const char* file_name)
+{
+ //if(access(file_name, 0) != 0)
+ // return XML_ERROR_FILE_NOT_FOUND;
+ XMLDocument xml;
+ int err = xml.LoadFile(file_name);
+ const XMLElement* root = xml.RootElement();
+ int ret = FALSE;
+ if(err == XML_SUCCESS && root && strcmp(root->Name(), BLUEDROID_ROOT) == 0)
+ {
+ const XMLElement* section;
+ for(section = root->FirstChildElement(); section; section = section->NextSiblingElement())
+ {
+ //debug("section tag:%s", section->Name());
+ if(validate_ele_name(section->Name()))
+ {
+ const char* section_name = section->Attribute(BLUEDROID_NAME_TAG);
+ if(section_name && *section_name)
+ if(parse_sections(section_name, section))
+ ret = TRUE;
+ }
+ }
+ }
+ return ret;
+}
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+static int parse_sections(const char* section_name, const XMLElement* section)
+{
+ const XMLElement* key;
+ //debug("in");
+ for(key = section->FirstChildElement(); key; key = key->NextSiblingElement())
+ {
+ //debug("key tag:%s", key->Name());
+ if(validate_ele_name(key->Name()))
+ {
+ const char* key_name = key->Attribute(BLUEDROID_NAME_TAG);
+ //debug("key name:%s", key_name);
+ if(key_name && *key_name)
+ {
+ const XMLElement* value;
+ for(value = key->FirstChildElement(); value; value = value->NextSiblingElement())
+ {
+ const char* value_name = value->Attribute(BLUEDROID_NAME_TAG);
+ const char* value_type = value->Attribute(BLUEDROID_VALUE_TYPE);
+ //debug("value ele name:%s, section name:%s, key name:%s, value name:%s, value type:%s",
+ // value->Name(), section_name, key_name, value_name, value_type);
+ int type = type_str2int(value_type);
+ if(value_name && *value_name && type != BTIF_CFG_TYPE_INVALID)
+ {
+ const char* value_str = value->GetText() ? value->GetText() : "";
+ //debug("value_name:%s, value_str:%s, value_type:%s, type:%x",
+ // value_name, value_str, value_type, type);
+ if(type & BTIF_CFG_TYPE_STR)
+ btif_config_set_str(section_name, key_name, value_name, value_str);
+ else if(type & BTIF_CFG_TYPE_INT)
+ {
+ if(*value_str)
+ {
+ int v = atoi(value_str);
+ btif_config_set_int(section_name, key_name, value_name, v);
+ }
+ }
+ else if(type & BTIF_CFG_TYPE_BIN)
+ {
+ int len = trim_bin_str_value(&value_str);
+ if(len > 0 && len % 2 == 0)
+ {
+ char *bin = (char*)alloca(len / 2);
+ if(hex2bytes(value_str, len, bin))
+ btif_config_set(section_name, key_name, value_name, bin, len/2, BTIF_CFG_TYPE_BIN);
+ }
+ }
+ else error("Unsupported value:%s, type:%s not loaded", value_name, value_type);
+ }
+ }
+ }
+ }
+ }
+ //debug("out");
+ return TRUE;
+}
+static inline XMLElement* add_ele(XMLDocument* xml, XMLElement* p, int index,
+ const char* name_tag, const char* value_type = NULL)
+{
+ //debug("in, tag:%s", name_tag);
+ char ele_name[128] = {0};
+ create_ele_name(index, ele_name, sizeof(ele_name));
+ XMLElement* ele = xml->NewElement(ele_name);
+ //debug("ele name:%s, tag:%s, index:%d, value type:%s", ele_name, name_tag, index, value_type);
+ ele->SetAttribute(BLUEDROID_NAME_TAG, name_tag);
+ if(value_type && *value_type)
+ ele->SetAttribute(BLUEDROID_VALUE_TYPE, value_type);
+ p->InsertEndChild(ele);
+ //debug("out, tag:%s", name_tag);
+ return ele;
+}
+static void enum_config(void* user_data, const char* section_name, const char* key_name, const char* value_name,
+ const char* value, int bytes, int type)
+{
+ enum_user_data& d = *(enum_user_data*)user_data;
+ //debug("in, key:%s, value:%s", key_name, value_name);
+ //debug("section name:%s, key name:%s, value name:%s, value type:%s",
+ // section_name, key_name, value_name, type_int2str(type));
+ if(type & BTIF_CFG_TYPE_VOLATILE)
+ return; //skip any volatile value
+ if(d.sn != section_name)
+ {
+ d.sn = section_name;
+ d.se = add_ele(d.xml, d.xml->RootElement(), ++d.si, section_name);
+ d.ki = 0;
+ }
+ if(d.kn != key_name)
+ {
+ d.kn = key_name;
+ d.ke = add_ele(d.xml, d.se, ++d.ki, key_name);
+ d.vi = 0;
+ }
+ if(d.vn != value_name)
+ {
+ if(type & BTIF_CFG_TYPE_STR)
+ {
+ d.vn = value_name;
+ d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
+ d.ve->InsertFirstChild(d.xml->NewText(value));
+ }
+ else if(type & BTIF_CFG_TYPE_INT)
+ {
+ d.vn = value_name;
+ d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
+ char value_str[64] = {0};
+ snprintf(value_str, sizeof(value_str), "%d", *(int*)value);
+ d.ve->InsertFirstChild(d.xml->NewText(value_str));
+ }
+ else if(type & BTIF_CFG_TYPE_BIN)
+ {
+ d.vn = value_name;
+ d.ve = add_ele(d.xml, d.ke, ++d.vi, value_name, type_int2str(type));
+ char* value_str = (char*)alloca(bytes*2 + 1);
+ bytes2hex(value, bytes, value_str);
+ d.ve->InsertFirstChild(d.xml->NewText(value_str));
+ }
+ else error("unsupported config value name:%s, type:%s not saved", d.vn, type_int2str(type));
+ }
+ //debug("out, key:%s, value:%s", key_name, value_name);
+}
+
+static int type_str2int(const char* type)
+{
+ if(strcmp(type, "int") == 0)
+ return BTIF_CFG_TYPE_INT;
+ if(strcmp(type, "binary") == 0)
+ return BTIF_CFG_TYPE_BIN;
+ if(type == 0 || *type == 0 || strcmp(type, "string") == 0)
+ return BTIF_CFG_TYPE_STR;
+ error("unknown value type:%s", type);
+ return BTIF_CFG_TYPE_INVALID;
+}
+static const char* type_int2str(int type)
+{
+ switch(type)
+ {
+ case BTIF_CFG_TYPE_INT:
+ return "int";
+ case BTIF_CFG_TYPE_BIN:
+ return "binary";
+ case BTIF_CFG_TYPE_STR:
+ return "string";
+ default:
+ error("unknown type:%d", type);
+ break;
+ }
+ return NULL;
+}
+
+static inline void create_ele_name(int index, char* element, int len)
+{
+ snprintf(element, len, "N%d", index);
+}
+static inline int validate_ele_name(const char* key)
+{
+ //must be 'N' followed with numbers
+ if(key && *key == 'N' && *++key)
+ {
+ while(*key)
+ {
+ if(*key < '0' || *key > '9')
+ return FALSE;
+ ++key;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+static int open_file_map(const char *pathname, const char**map, int* size)
+{
+ struct stat st;
+ st.st_size = 0;
+ int fd;
+ //debug("in");
+ if((fd = open(pathname, O_RDONLY)) >= 0)
+ {
+ //debug("fd:%d", fd);
+ if(fstat(fd, &st) == 0 && st.st_size)
+ {
+ *size = st.st_size;
+ *map = (const char*)mmap(NULL, *size, PROT_READ, MAP_SHARED, fd, 0);
+ if(*map && *map != MAP_FAILED)
+ {
+ //debug("out map:%p, size:%d", *map, *size);
+ return fd;
+ }
+ }
+ close(fd);
+ }
+ //debug("out, failed");
+ return -1;
+}
+static void close_file_map(int fd, const char* map, int size)
+{
+ munmap((void*)map, size);
+ close(fd);
+}
+static int read_file_line(const char* map, int start_pos, int size, int* line_size)
+{
+ *line_size = 0;
+ //debug("in, start pos:%d, size:%d", start_pos, size);
+ int i;
+ for(i = start_pos; i < size; i++)
+ {
+ ++*line_size;
+ if(map[i] == '\r' || map[i] == '\n')
+ break;
+ }
+ //debug("out, ret:%d, start pos:%d, size:%d, line_size:%d", i, start_pos, size, *line_size);
+ return i + 1;
+}
+static const char* find_value_line(const char* map, int size, const char *key, int* value_size)
+{
+ int key_len = strlen(key);
+ int i;
+ for(i = 0; i < size; i++)
+ {
+ if(map[i] == *key)
+ {
+ if(i + key_len + 1 > size)
+ return NULL;
+ if(memcmp(map + i, key, key_len) == 0)
+ {
+ read_file_line(map, i + key_len + 1, size, value_size);
+ if(*value_size)
+ return map + i + key_len + 1;
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+static int read_line_word(const char* line, int start_pos, int line_size, char* word, int *word_size, bool lower_case = false)
+{
+ int i;
+ //skip space
+ //debug("in, line start_pos:%d, line_size:%d", start_pos, line_size);
+ for(i = start_pos; i < line_size; i++)
+ {
+ //debug("skip space loop, line[%d]:%c", i, line[i]);
+ if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n')
+ break;
+ }
+ *word_size = 0;
+ for(; i < line_size; i++)
+ {
+ //debug("add word loop, line[%d]:%c", i, line[i]);
+ if(line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] !='\n')
+ {
+ ++*word_size;
+ if(lower_case && 'A' <= line[i] && line[i] <= 'Z')
+ *word++ = 'a' - 'A' + line[i];
+ else
+ *word++ = line[i];
+ }
+ else break;
+ }
+ *word = 0;
+ //debug("out, ret:%d, word:%s, word_size:%d, line start_pos:%d, line_size:%d",
+ // i, word, *word_size, start_pos, line_size);
+ return i;
+}
+static int is_valid_bd_addr(const char* addr)
+{
+ int len = strlen(addr);
+ //debug("addr: %s, len:%d", addr, len);
+ return len == 17 && addr[2] == ':' && addr[5] == ':' && addr[14] == ':';
+}
+static int load_bluez_cfg_value(const char* adapter_path, const char* file_name)
+{
+ //debug("in");
+
+ const char* map = NULL;
+ int size = 0;
+ int ret = FALSE;
+ char path[256];
+ snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name);
+ int fd = open_file_map(path, &map, &size);
+ //debug("in, path:%s, fd:%d, size:%d", path, fd, size);
+ if(fd < 0 || size == 0)
+ {
+ error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
+ //debug("out");
+ return FALSE;
+ }
+ //get local bt device name from bluez config
+ int line_size = 0;
+ const char *value_line = find_value_line(map, size, "name", &line_size);
+ if(value_line && line_size > 0)
+ {
+ char value[line_size + 1];
+ memcpy(value, value_line, line_size);
+ value[line_size] = 0;
+ //debug("import local bt dev names:%s", value);
+ btif_config_set_str("Local", "Adapter", "Name", value);
+ ret = TRUE;
+ }
+
+ close_file_map(fd, map, size);
+ //debug("out, ret:%d", ret);
+ return ret;
+}
+
+int load_bluez_adapter_info(char* adapter_path, int size)
+{
+ struct dirent *dptr;
+ DIR *dirp;
+ int ret = FALSE;
+ if((dirp = opendir(BLUEZ_PATH)) != NULL)
+ {
+ while((dptr = readdir(dirp)) != NULL)
+ {
+ //debug("readdir: %s",dptr->d_name);
+ if(is_valid_bd_addr(dptr->d_name))
+ {
+ snprintf(adapter_path, size, "%s%s", BLUEZ_PATH, dptr->d_name);
+ btif_config_set_str("Local", "Adapter", "Address", dptr->d_name);
+ load_bluez_cfg_value(adapter_path, BLUEZ_CONFIG);
+ ret = TRUE;
+ break;
+ }
+ }
+ closedir(dirp);
+ }
+ return ret;
+}
+static inline void upcase_addr(const char* laddr, char* uaddr, int size)
+{
+ int i;
+ for(i = 0; i < size && laddr[i]; i++)
+ uaddr[i] = ('a' <= laddr[i] && laddr[i] <= 'z') ?
+ laddr[i] - ('a' - 'A') : laddr[i];
+ uaddr[i] = 0;
+}
+static int load_bluez_dev_value(const char* adapter_path, const char* bd_addr,
+ const char* file_name, const char* cfg_value_name, int type)
+{
+ //debug("in");
+ char addr[32];
+ upcase_addr(bd_addr, addr, sizeof(addr));
+
+ const char* map = NULL;
+ int size = 0;
+ int ret = FALSE;
+ char path[256];
+ snprintf(path, sizeof(path), "%s/%s", adapter_path, file_name);
+ int fd = open_file_map(path, &map, &size);
+ //debug("in, path:%s, addr:%s, fd:%d, size:%d", path, addr, fd, size);
+ if(fd < 0 || size == 0)
+ {
+ error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
+ //debug("out");
+ return FALSE;
+ }
+ int line_size = 0;
+ const char *value_line = find_value_line(map, size, addr, &line_size);
+ if(value_line && line_size)
+ {
+ char line[line_size + 1];
+ memcpy(line, value_line, line_size);
+ line[line_size] = 0;
+ //debug("addr:%s, Names:%s", bd_addr, line);
+ if(type == BTIF_CFG_TYPE_STR)
+ btif_config_set_str("Remote", bd_addr, cfg_value_name, line);
+ else if(type == BTIF_CFG_TYPE_INT)
+ {
+ int v = strtol(line, NULL, 16);
+ //filter out unspported devices by its class
+ if(strcmp(file_name, BLUEZ_CLASSES) == 0)
+ {
+ switch((v & 0x1f00) >> 8)
+ {
+ case 0x5: //hid device
+ error("skip paired hid devices");
+ close_file_map(fd, map, size);
+ return FALSE;
+ }
+ }
+ btif_config_set_int("Remote", bd_addr, cfg_value_name, v);
+ }
+ ret = TRUE;
+ }
+ close_file_map(fd, map, size);
+ //debug("out, ret:%d", ret);
+ return ret;
+}
+static inline int bz2bd_linkkeytype(int type)
+{
+#if 1
+ return type;
+#else
+ int table[5] = {0, 0, 0, 0, 0};
+ if(0 <= type && type < (int)(sizeof(table)/sizeof(int)))
+ return table[type];
+ return 0;
+#endif
+}
+int load_bluez_linkkeys(const char* adapter_path)
+{
+ const char* map = NULL;
+ int size = 0;
+ int ret = FALSE;
+ char path[256];
+ //debug("in");
+ snprintf(path, sizeof(path), "%s/%s", adapter_path, BLUEZ_LINKKEY);
+ int fd = open_file_map(path, &map, &size);
+ if(fd < 0 || size == 0)
+ {
+ error("open_file_map fail, fd:%d, path:%s, size:%d", fd, path, size);
+ //debug("out");
+ return FALSE;
+ }
+ int pos = 0;
+ //debug("path:%s, size:%d", path, size);
+ while(pos < size)
+ {
+ int line_size = 0;
+ int next_pos = read_file_line(map, pos, size, &line_size);
+ //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size);
+ if(line_size)
+ {
+ const char* line = map + pos;
+ char addr[line_size + 1];
+ int word_pos = 0;
+ int addr_size = 0;
+ word_pos = read_line_word(line, word_pos, line_size, addr, &addr_size, true);
+ //debug("read_line_word addr:%s, addr_size:%d", addr, addr_size);
+ if(*addr)
+ {
+ char value[line_size + 1];
+ int value_size = 0;
+ //read link key
+ word_pos = read_line_word(line, word_pos, line_size, value, &value_size);
+ //debug("read_line_word linkkey:%s, size:%d", value, value_size);
+ if(*value)
+ {
+ int linkkey_size = value_size / 2;
+ char linkkey[linkkey_size];
+ if(hex2bytes(value, value_size, linkkey))
+ { //read link key type
+ //bluez save the linkkey in reversed order
+ reverse_bin(linkkey, linkkey_size);
+ word_pos = read_line_word(line, word_pos,
+ line_size, value, &value_size);
+ if(*value)
+ {
+ if(load_bluez_dev_value(adapter_path, addr,
+ BLUEZ_CLASSES, "DevClass", BTIF_CFG_TYPE_INT) &&
+ load_bluez_dev_value(adapter_path, addr,
+ BLUEZ_NAMES, "Name", BTIF_CFG_TYPE_STR) &&
+ load_bluez_dev_value(adapter_path, addr,
+ BLUEZ_TYPES, "DevType", BTIF_CFG_TYPE_INT) &&
+ load_bluez_dev_value(adapter_path, addr,
+ BLUEZ_PROFILES, "Service", BTIF_CFG_TYPE_STR))
+ {
+ load_bluez_dev_value(adapter_path, addr,
+ BLUEZ_ALIASES, "Aliase", BTIF_CFG_TYPE_STR);
+ int key_type = bz2bd_linkkeytype(atoi(value));
+
+ //read pin len
+ word_pos = read_line_word(line, word_pos, line_size, value, &value_size);
+ if(*value)
+ {
+ int pin_len = atoi(value);
+ ret = TRUE;
+ btif_config_set("Remote", addr, "LinkKey", linkkey,
+ linkkey_size, BTIF_CFG_TYPE_BIN);
+ //dump_bin("import bluez linkkey", linkkey, linkkey_size);
+ btif_config_set_int("Remote", addr, "LinkKeyType", key_type);
+ btif_config_set_int("Remote", addr, "PinLength", pin_len);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //debug("pos:%d, next_pos:%d, size:%d, line_size:%d", pos, next_pos, size, line_size);
+ pos = next_pos;
+ }
+ close_file_map(fd, map, size);
+ //debug("out, ret:%d", ret);
+ return ret;
+}
+
diff --git a/btif/src/btif_core.c b/btif/src/btif_core.c
new file mode 100755
index 0000000..62339a9
--- /dev/null
+++ b/btif/src/btif_core.c
@@ -0,0 +1,1431 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_core.c
+ *
+ * Description: Contains core functionality related to interfacing between
+ * Bluetooth HAL and BTE core stack.
+ *
+ ***********************************************************************************/
+
+#include <stdlib.h>
+#include <hardware/bluetooth.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+
+#define LOG_TAG "BTIF_CORE"
+#include "btif_api.h"
+#include "bta_api.h"
+#include "gki.h"
+#include "btu.h"
+#include "bte.h"
+#include "bd.h"
+#include "btif_av.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "btif_sock.h"
+#include "btif_pan.h"
+#include "btif_profile_queue.h"
+#include "btif_config.h"
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#ifndef BTIF_TASK_STACK_SIZE
+#define BTIF_TASK_STACK_SIZE 0x2000 /* In bytes */
+#endif
+
+#ifndef BTE_DID_CONF_FILE
+#define BTE_DID_CONF_FILE "/etc/bluetooth/bt_did.conf"
+#endif
+
+#define BTIF_TASK_STR ((INT8 *) "BTIF")
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/* These type definitions are used when passing data from the HAL to BTIF context
+* in the downstream path for the adapter and remote_device property APIs */
+
+typedef struct {
+ bt_bdaddr_t bd_addr;
+ bt_property_type_t type;
+} btif_storage_read_t;
+
+typedef struct {
+ bt_bdaddr_t bd_addr;
+ bt_property_t prop;
+} btif_storage_write_t;
+
+typedef union {
+ btif_storage_read_t read_req;
+ btif_storage_write_t write_req;
+} btif_storage_req_t;
+
+typedef enum {
+ BTIF_CORE_STATE_DISABLED = 0,
+ BTIF_CORE_STATE_ENABLING,
+ BTIF_CORE_STATE_ENABLED,
+ BTIF_CORE_STATE_DISABLING
+} btif_core_state_t;
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+bt_bdaddr_t btif_local_bd_addr;
+
+static UINT32 btif_task_stack[(BTIF_TASK_STACK_SIZE + 3) / 4];
+
+/* holds main adapter state */
+static btif_core_state_t btif_core_state = BTIF_CORE_STATE_DISABLED;
+
+static int btif_shutdown_pending = 0;
+static tBTA_SERVICE_MASK btif_enabled_services = 0;
+
+/*
+* This variable should be set to 1, if the Bluedroid+BTIF libraries are to
+* function in DUT mode.
+*
+* To set this, the btif_init_bluetooth needs to be called with argument as 1
+*/
+static UINT8 btif_dut_mode = 0;
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+static bt_status_t btif_associate_evt(void);
+static bt_status_t btif_disassociate_evt(void);
+
+/* sends message to btif task */
+static void btif_sendmsg(void *p_msg);
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+extern void bte_load_did_conf(const char *p_path);
+
+/** TODO: Move these to _common.h */
+void bte_main_boot_entry(void);
+void bte_main_enable(uint8_t *local_addr);
+void bte_main_disable(void);
+void bte_main_shutdown(void);
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+void bte_main_enable_lpm(BOOLEAN enable);
+#endif
+void bte_main_postload_cfg(void);
+void btif_dm_execute_service_request(UINT16 event, char *p_param);
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void);
+#endif
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+
+/*****************************************************************************
+** Context switching functions
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function btif_context_switched
+**
+** Description Callback used to execute transferred context callback
+**
+** p_msg : message to be executed in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_context_switched(void *p_msg)
+{
+ tBTIF_CONTEXT_SWITCH_CBACK *p;
+
+ BTIF_TRACE_VERBOSE0("btif_context_switched");
+
+ p = (tBTIF_CONTEXT_SWITCH_CBACK *) p_msg;
+
+ /* each callback knows how to parse the data */
+ if (p->p_cb)
+ p->p_cb(p->event, p->p_param);
+}
+
+
+/*******************************************************************************
+**
+** Function btif_transfer_context
+**
+** Description This function switches context to btif task
+**
+** p_cback : callback used to process message in btif context
+** event : event id of message
+** p_params : parameter area passed to callback (copied)
+** param_len : length of parameter area
+** p_copy_cback : If set this function will be invoked for deep copy
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_transfer_context (tBTIF_CBACK *p_cback, UINT16 event, char* p_params, int param_len, tBTIF_COPY_CBACK *p_copy_cback)
+{
+ tBTIF_CONTEXT_SWITCH_CBACK *p_msg;
+
+ BTIF_TRACE_VERBOSE2("btif_transfer_context event %d, len %d", event, param_len);
+
+ /* allocate and send message that will be executed in btif context */
+ if ((p_msg = (tBTIF_CONTEXT_SWITCH_CBACK *) GKI_getbuf(sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len)) != NULL)
+ {
+ p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */
+ p_msg->p_cb = p_cback;
+
+ p_msg->event = event; /* callback event */
+
+ /* check if caller has provided a copy callback to do the deep copy */
+ if (p_copy_cback)
+ {
+ p_copy_cback(event, p_msg->p_param, p_params);
+ }
+ else if (p_params)
+ {
+ memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */
+ }
+
+ btif_sendmsg(p_msg);
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ /* let caller deal with a failed allocation */
+ return BT_STATUS_NOMEM;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_is_dut_mode
+**
+** Description checks if BTIF is currently in DUT mode
+**
+** Returns 1 if test mode, otherwize 0
+**
+*******************************************************************************/
+
+UINT8 btif_is_dut_mode(void)
+{
+ return (btif_dut_mode == 1);
+}
+
+/*******************************************************************************
+**
+** Function btif_is_enabled
+**
+** Description checks if main adapter is fully enabled
+**
+** Returns 1 if fully enabled, otherwize 0
+**
+*******************************************************************************/
+
+int btif_is_enabled(void)
+{
+ return ((!btif_is_dut_mode()) && (btif_core_state == BTIF_CORE_STATE_ENABLED));
+}
+
+/*******************************************************************************
+**
+** Function btif_task
+**
+** Description BTIF task handler managing all messages being passed
+** Bluetooth HAL and BTA.
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_task(UINT32 params)
+{
+ UINT16 event;
+ BT_HDR *p_msg;
+
+ BTIF_TRACE_DEBUG0("btif task starting");
+
+ btif_associate_evt();
+
+ for(;;)
+ {
+ /* wait for specified events */
+ event = GKI_wait(0xFFFF, 0);
+
+ /*
+ * Wait for the trigger to init chip and stack. This trigger will
+ * be received by btu_task once the UART is opened and ready
+ */
+ if (event == BT_EVT_TRIGGER_STACK_INIT)
+ {
+ BTIF_TRACE_DEBUG0("btif_task: received trigger stack init event");
+ BTA_EnableBluetooth(bte_dm_evt);
+ }
+
+ if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
+ break;
+
+ if(event & TASK_MBOX_1_EVT_MASK)
+ {
+ while((p_msg = GKI_read_mbox(BTU_BTIF_MBOX)) != NULL)
+ {
+ BTIF_TRACE_VERBOSE1("btif task fetched event %x", p_msg->event);
+
+ switch (p_msg->event)
+ {
+ case BT_EVT_CONTEXT_SWITCH_EVT:
+ btif_context_switched(p_msg);
+ break;
+ default:
+ BTIF_TRACE_ERROR1("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
+ break;
+ }
+
+ GKI_freebuf(p_msg);
+ }
+ }
+ }
+
+ btif_disassociate_evt();
+
+ BTIF_TRACE_DEBUG0("btif task exiting");
+}
+
+
+/*******************************************************************************
+**
+** Function btif_sendmsg
+**
+** Description Sends msg to BTIF task
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_sendmsg(void *p_msg)
+{
+ GKI_send_msg(BTIF_TASK, BTU_BTIF_MBOX, p_msg);
+}
+
+static void btif_fetch_local_bdaddr(bt_bdaddr_t *local_addr)
+{
+ char val[256];
+ uint8_t valid_bda = FALSE;
+ int val_size = 0;
+ const uint8_t null_bdaddr[BD_ADDR_LEN] = {0,0,0,0,0,0};
+
+ /* Get local bdaddr storage path from property */
+ if (property_get(PROPERTY_BT_BDADDR_PATH, val, NULL))
+ {
+ int addr_fd;
+
+ BTIF_TRACE_DEBUG1("local bdaddr is stored in %s", val);
+
+ if ((addr_fd = open(val, O_RDONLY)) != -1)
+ {
+ memset(val, 0, sizeof(val));
+ read(addr_fd, val, FACTORY_BT_BDADDR_STORAGE_LEN);
+ str2bd(val, local_addr);
+ /* If this is not a reserved/special bda, then use it */
+ if (memcmp(local_addr->address, null_bdaddr, BD_ADDR_LEN) != 0)
+ {
+ valid_bda = TRUE;
+ BTIF_TRACE_DEBUG6("Got Factory BDA %02X:%02X:%02X:%02X:%02X:%02X",
+ local_addr->address[0], local_addr->address[1], local_addr->address[2],
+ local_addr->address[3], local_addr->address[4], local_addr->address[5]);
+ }
+
+ close(addr_fd);
+ }
+ }
+
+ if(!valid_bda)
+ {
+ val_size = sizeof(val);
+ if(btif_config_get_str("Local", "Adapter", "Address", val, &val_size))
+ {
+ str2bd(val, local_addr);
+ BTIF_TRACE_DEBUG1("local bdaddr from bt_config.xml is %s", val);
+ return;
+ }
+ }
+
+ /* No factory BDADDR found. Look for previously generated random BDA */
+ if ((!valid_bda) && \
+ (property_get(PERSIST_BDADDR_PROPERTY, val, NULL)))
+ {
+ str2bd(val, local_addr);
+ valid_bda = TRUE;
+ BTIF_TRACE_DEBUG6("Got prior random BDA %02X:%02X:%02X:%02X:%02X:%02X",
+ local_addr->address[0], local_addr->address[1], local_addr->address[2],
+ local_addr->address[3], local_addr->address[4], local_addr->address[5]);
+ }
+
+ /* Generate new BDA if necessary */
+ if (!valid_bda)
+ {
+ bdstr_t bdstr;
+ /* Seed the random number generator */
+ srand((unsigned int) (time(0)));
+
+ /* No autogen BDA. Generate one now. */
+ local_addr->address[0] = 0x22;
+ local_addr->address[1] = 0x22;
+ local_addr->address[2] = (uint8_t) ((rand() >> 8) & 0xFF);
+ local_addr->address[3] = (uint8_t) ((rand() >> 8) & 0xFF);
+ local_addr->address[4] = (uint8_t) ((rand() >> 8) & 0xFF);
+ local_addr->address[5] = (uint8_t) ((rand() >> 8) & 0xFF);
+
+ /* Convert to ascii, and store as a persistent property */
+ bd2str(local_addr, &bdstr);
+
+ BTIF_TRACE_DEBUG2("No preset BDA. Generating BDA: %s for prop %s",
+ (char*)bdstr, PERSIST_BDADDR_PROPERTY);
+
+ if (property_set(PERSIST_BDADDR_PROPERTY, (char*)bdstr) < 0)
+ BTIF_TRACE_ERROR1("Failed to set random BDA in prop %s",PERSIST_BDADDR_PROPERTY);
+ }
+
+ //save the bd address to config file
+ bdstr_t bdstr;
+ bd2str(local_addr, &bdstr);
+ val_size = sizeof(val);
+ if (btif_config_get_str("Local", "Adapter", "Address", val, &val_size))
+ {
+ if (strcmp(bdstr, val) ==0)
+ {
+ // BDA is already present in the config file.
+ return;
+ }
+ }
+ btif_config_set_str("Local", "Adapter", "Address", bdstr);
+ btif_config_save();
+}
+
+/*****************************************************************************
+**
+** btif core api functions
+**
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_init_bluetooth
+**
+** Description Creates BTIF task and prepares BT scheduler for startup
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_init_bluetooth()
+{
+ UINT8 status;
+ btif_config_init();
+ bte_main_boot_entry();
+
+ /* As part of the init, fetch the local BD ADDR */
+ memset(&btif_local_bd_addr, 0, sizeof(bt_bdaddr_t));
+ btif_fetch_local_bdaddr(&btif_local_bd_addr);
+
+ /* start btif task */
+ status = GKI_create_task(btif_task, BTIF_TASK, BTIF_TASK_STR,
+ (UINT16 *) ((UINT8 *)btif_task_stack + BTIF_TASK_STACK_SIZE),
+ sizeof(btif_task_stack));
+
+ if (status != GKI_SUCCESS)
+ return BT_STATUS_FAIL;
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_associate_evt
+**
+** Description Event indicating btif_task is up
+** Attach btif_task to JVM
+**
+** Returns void
+**
+*******************************************************************************/
+
+static bt_status_t btif_associate_evt(void)
+{
+ BTIF_TRACE_DEBUG1("%s: notify ASSOCIATE_JVM", __FUNCTION__);
+ HAL_CBACK(bt_hal_cbacks, thread_evt_cb, ASSOCIATE_JVM);
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_enable_bluetooth
+**
+** Description Performs chip power on and kickstarts OS scheduler
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_enable_bluetooth(void)
+{
+ BTIF_TRACE_DEBUG0("BTIF ENABLE BLUETOOTH");
+
+ if (btif_core_state != BTIF_CORE_STATE_DISABLED)
+ {
+ ALOGD("not disabled\n");
+ return BT_STATUS_DONE;
+ }
+
+ btif_core_state = BTIF_CORE_STATE_ENABLING;
+
+ /* Create the GKI tasks and run them */
+ bte_main_enable(btif_local_bd_addr.address);
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_enable_bluetooth_evt
+**
+** Description Event indicating bluetooth enable is completed
+** Notifies HAL user with updated adapter state
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_enable_bluetooth_evt(tBTA_STATUS status, BD_ADDR local_bd)
+{
+ bt_bdaddr_t bd_addr;
+ bdstr_t bdstr;
+
+ bdcpy(bd_addr.address, local_bd);
+ BTIF_TRACE_DEBUG3("%s: status %d, local bd [%s]", __FUNCTION__, status,
+ bd2str(&bd_addr, &bdstr));
+
+ if (bdcmp(btif_local_bd_addr.address,local_bd))
+ {
+ bdstr_t buf;
+ bt_property_t prop;
+
+ /**
+ * The Controller's BDADDR does not match to the BTIF's initial BDADDR!
+ * This could be because the factory BDADDR was stored separatley in
+ * the Controller's non-volatile memory rather than in device's file
+ * system.
+ **/
+ BTIF_TRACE_WARNING0("***********************************************");
+ BTIF_TRACE_WARNING6("BTIF init BDA was %02X:%02X:%02X:%02X:%02X:%02X",
+ btif_local_bd_addr.address[0], btif_local_bd_addr.address[1],
+ btif_local_bd_addr.address[2], btif_local_bd_addr.address[3],
+ btif_local_bd_addr.address[4], btif_local_bd_addr.address[5]);
+ BTIF_TRACE_WARNING6("Controller BDA is %02X:%02X:%02X:%02X:%02X:%02X",
+ local_bd[0], local_bd[1], local_bd[2],
+ local_bd[3], local_bd[4], local_bd[5]);
+ BTIF_TRACE_WARNING0("***********************************************");
+
+ bdcpy(btif_local_bd_addr.address, local_bd);
+
+ //save the bd address to config file
+ bd2str(&btif_local_bd_addr, &buf);
+ btif_config_set_str("Local", "Adapter", "Address", buf);
+ btif_config_save();
+
+ //fire HAL callback for property change
+ memcpy(buf, &btif_local_bd_addr, sizeof(bt_bdaddr_t));
+ prop.type = BT_PROPERTY_BDADDR;
+ prop.val = (void*)buf;
+ prop.len = sizeof(bt_bdaddr_t);
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1, &prop);
+ }
+
+ bte_main_postload_cfg();
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+ bte_main_enable_lpm(TRUE);
+#endif
+ /* add passing up bd address as well ? */
+
+ /* callback to HAL */
+ if (status == BTA_SUCCESS)
+ {
+ /* initialize a2dp service */
+ btif_av_init();
+
+ /* init rfcomm & l2cap api */
+ btif_sock_init();
+
+ /* init pan */
+ btif_pan_init();
+
+ /* load did configuration */
+ bte_load_did_conf(BTE_DID_CONF_FILE);
+
+#ifdef BTIF_DM_OOB_TEST
+ btif_dm_load_local_oob();
+#endif
+ /* now fully enabled, update state */
+ btif_core_state = BTIF_CORE_STATE_ENABLED;
+
+ HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_ON);
+ }
+ else
+ {
+ /* cleanup rfcomm & l2cap api */
+ btif_sock_cleanup();
+
+ btif_pan_cleanup();
+
+ /* we failed to enable, reset state */
+ btif_core_state = BTIF_CORE_STATE_DISABLED;
+
+ HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_disable_bluetooth
+**
+** Description Inititates shutdown of Bluetooth system.
+** Any active links will be dropped and device entering
+** non connectable/discoverable mode
+**
+** Returns void
+**
+*******************************************************************************/
+bt_status_t btif_disable_bluetooth(void)
+{
+ tBTA_STATUS status;
+
+ if (!btif_is_enabled())
+ {
+ BTIF_TRACE_ERROR0("btif_disable_bluetooth : not yet enabled");
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTIF_TRACE_DEBUG0("BTIF DISABLE BLUETOOTH");
+
+ btif_dm_on_disable();
+ btif_core_state = BTIF_CORE_STATE_DISABLING;
+
+ /* cleanup rfcomm & l2cap api */
+ btif_sock_cleanup();
+
+ btif_pan_cleanup();
+
+ status = BTA_DisableBluetooth();
+
+ btif_config_flush();
+
+ if (status != BTA_SUCCESS)
+ {
+ BTIF_TRACE_ERROR1("disable bt failed (%d)", status);
+
+ /* reset the original state to allow attempting disable again */
+ btif_core_state = BTIF_CORE_STATE_ENABLED;
+
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_disable_bluetooth_evt
+**
+** Description Event notifying BT disable is now complete.
+** Terminates main stack tasks and notifies HAL
+** user with updated BT state.
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_disable_bluetooth_evt(void)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
+ bte_main_enable_lpm(FALSE);
+#endif
+
+ bte_main_disable();
+
+ /* update local state */
+ btif_core_state = BTIF_CORE_STATE_DISABLED;
+
+ /* callback to HAL */
+ HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);
+
+ if (btif_shutdown_pending)
+ {
+ BTIF_TRACE_DEBUG1("%s: calling btif_shutdown_bluetooth", __FUNCTION__);
+ btif_shutdown_bluetooth();
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btif_shutdown_bluetooth
+**
+** Description Finalizes BT scheduler shutdown and terminates BTIF
+** task.
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_shutdown_bluetooth(void)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_is_enabled())
+ {
+ BTIF_TRACE_WARNING0("shutdown while still enabled, initiate disable");
+
+ /* shutdown called prior to disabling, initiate disable */
+ btif_disable_bluetooth();
+ btif_shutdown_pending = 1;
+ return BT_STATUS_NOT_READY;
+ }
+
+ btif_shutdown_pending = 0;
+
+ GKI_destroy_task(BTIF_TASK);
+ btif_queue_release();
+ bte_main_shutdown();
+
+ btif_dut_mode = 0;
+
+ BTIF_TRACE_DEBUG1("%s done", __FUNCTION__);
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_disassociate_evt
+**
+** Description Event indicating btif_task is going down
+** Detach btif_task to JVM
+**
+** Returns void
+**
+*******************************************************************************/
+
+static bt_status_t btif_disassociate_evt(void)
+{
+ BTIF_TRACE_DEBUG1("%s: notify DISASSOCIATE_JVM", __FUNCTION__);
+
+ HAL_CBACK(bt_hal_cbacks, thread_evt_cb, DISASSOCIATE_JVM);
+
+ /* shutdown complete, all events notified and we reset HAL callbacks */
+ bt_hal_cbacks = NULL;
+
+ return BT_STATUS_SUCCESS;
+}
+
+/****************************************************************************
+**
+** BTIF Test Mode APIs
+**
+*****************************************************************************/
+/*******************************************************************************
+**
+** Function btif_dut_mode_cback
+**
+** Description Callback invoked on completion of vendor specific test mode command
+**
+** Returns None
+**
+*******************************************************************************/
+static void btif_dut_mode_cback( tBTM_VSC_CMPL *p )
+{
+ /* For now nothing to be done. */
+}
+
+/*******************************************************************************
+**
+** Function btif_dut_mode_configure
+**
+** Description Configure Test Mode - 'enable' to 1 puts the device in test mode and 0 exits
+** test mode
+**
+** Returns BT_STATUS_SUCCESS on success
+**
+*******************************************************************************/
+bt_status_t btif_dut_mode_configure(uint8_t enable)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_core_state != BTIF_CORE_STATE_ENABLED) {
+ BTIF_TRACE_ERROR0("btif_dut_mode_configure : Bluetooth not enabled");
+ return BT_STATUS_NOT_READY;
+ }
+
+ btif_dut_mode = enable;
+ if (enable == 1) {
+ BTA_EnableTestMode();
+ } else {
+ BTA_DisableTestMode();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dut_mode_send
+**
+** Description Sends a HCI Vendor specific command to the controller
+**
+** Returns BT_STATUS_SUCCESS on success
+**
+*******************************************************************************/
+bt_status_t btif_dut_mode_send(uint16_t opcode, uint8_t *buf, uint8_t len)
+{
+ /* TODO: Check that opcode is a vendor command group */
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ if (!btif_is_dut_mode()) {
+ BTIF_TRACE_ERROR0("Bluedroid HAL needs to be init with test_mode set to 1.");
+ return BT_STATUS_FAIL;
+ }
+ BTM_VendorSpecificCommand(opcode, len, buf, btif_dut_mode_cback);
+ return BT_STATUS_SUCCESS;
+}
+/*****************************************************************************
+**
+** btif api adapter property functions
+**
+*****************************************************************************/
+
+static bt_status_t btif_in_get_adapter_properties(void)
+{
+ bt_property_t properties[6];
+ uint32_t num_props;
+
+ bt_bdaddr_t addr;
+ bt_bdname_t name;
+ bt_scan_mode_t mode;
+ uint32_t disc_timeout;
+ bt_bdaddr_t bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];
+ bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+ num_props = 0;
+
+ /* BD_ADDR */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDADDR,
+ sizeof(addr), &addr);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* BD_NAME */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDNAME,
+ sizeof(name), &name);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* SCAN_MODE */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_ADAPTER_SCAN_MODE,
+ sizeof(mode), &mode);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* DISC_TIMEOUT */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ sizeof(disc_timeout), &disc_timeout);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* BONDED_DEVICES */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+ sizeof(bonded_devices), bonded_devices);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* LOCAL UUIDs */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_UUIDS,
+ sizeof(local_uuids), local_uuids);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb,
+ BT_STATUS_SUCCESS, num_props, properties);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btif_in_get_remote_device_properties(bt_bdaddr_t *bd_addr)
+{
+ bt_property_t remote_properties[8];
+ uint32_t num_props = 0;
+
+ bt_bdname_t name, alias;
+ uint32_t cod, devtype;
+ bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+
+ memset(remote_properties, 0, sizeof(remote_properties));
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_BDNAME,
+ sizeof(name), &name);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_REMOTE_FRIENDLY_NAME,
+ sizeof(alias), &alias);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_CLASS_OF_DEVICE,
+ sizeof(cod), &cod);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_TYPE_OF_DEVICE,
+ sizeof(devtype), &devtype);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_UUIDS,
+ sizeof(remote_uuids), remote_uuids);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ BT_STATUS_SUCCESS, bd_addr, num_props, remote_properties);
+
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function execute_storage_request
+**
+** Description Executes adapter storage request in BTIF context
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+static void execute_storage_request(UINT16 event, char *p_param)
+{
+ uint8_t is_local;
+ int num_entries = 0;
+ bt_status_t status = BT_STATUS_SUCCESS;
+
+ BTIF_TRACE_EVENT1("execute storage request event : %d", event);
+
+ switch(event)
+ {
+ case BTIF_CORE_STORAGE_ADAPTER_WRITE:
+ {
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ bt_property_t *p_prop = &(p_req->write_req.prop);
+ BTIF_TRACE_EVENT3("type: %d, len %d, 0x%x", p_prop->type,
+ p_prop->len, p_prop->val);
+
+ status = btif_storage_set_adapter_property(p_prop);
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, p_prop);
+ } break;
+
+ case BTIF_CORE_STORAGE_ADAPTER_READ:
+ {
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ char buf[512];
+ bt_property_t prop;
+ prop.type = p_req->read_req.type;
+ prop.val = (void*)buf;
+ prop.len = sizeof(buf);
+ status = btif_storage_get_adapter_property(&prop);
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, &prop);
+ } break;
+
+ case BTIF_CORE_STORAGE_ADAPTER_READ_ALL:
+ {
+ status = btif_in_get_adapter_properties();
+ } break;
+
+ case BTIF_CORE_STORAGE_NOTIFY_STATUS:
+ {
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 0, NULL);
+ } break;
+
+ default:
+ BTIF_TRACE_ERROR2("%s invalid event id (%d)", __FUNCTION__, event);
+ break;
+ }
+}
+
+static void execute_storage_remote_request(UINT16 event, char *p_param)
+{
+ bt_status_t status = BT_STATUS_FAIL;
+ bt_property_t prop;
+
+ BTIF_TRACE_EVENT1("execute storage remote request event : %d", event);
+
+ switch (event)
+ {
+ case BTIF_CORE_STORAGE_REMOTE_READ:
+ {
+ char buf[1024];
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ prop.type = p_req->read_req.type;
+ prop.val = (void*) buf;
+ prop.len = sizeof(buf);
+
+ status = btif_storage_get_remote_device_property(&(p_req->read_req.bd_addr),
+ &prop);
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ status, &(p_req->read_req.bd_addr), 1, &prop);
+ }break;
+ case BTIF_CORE_STORAGE_REMOTE_WRITE:
+ {
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ status = btif_storage_set_remote_device_property(&(p_req->write_req.bd_addr),
+ &(p_req->write_req.prop));
+ }break;
+ case BTIF_CORE_STORAGE_REMOTE_READ_ALL:
+ {
+ btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
+ btif_in_get_remote_device_properties(&p_req->read_req.bd_addr);
+ }break;
+ }
+}
+
+void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props,
+ bt_property_t *p_props)
+{
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb,
+ status, num_props, p_props);
+
+}
+void btif_remote_properties_evt(bt_status_t status, bt_bdaddr_t *remote_addr,
+ uint32_t num_props, bt_property_t *p_props)
+{
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ status, remote_addr, num_props, p_props);
+}
+
+/*******************************************************************************
+**
+** Function btif_in_storage_request_copy_cb
+**
+** Description Switch context callback function to perform the deep copy for
+** both the adapter and remote_device property API
+**
+** Returns None
+**
+*******************************************************************************/
+static void btif_in_storage_request_copy_cb(UINT16 event,
+ char *p_new_buf, char *p_old_buf)
+{
+ btif_storage_req_t *new_req = (btif_storage_req_t*)p_new_buf;
+ btif_storage_req_t *old_req = (btif_storage_req_t*)p_old_buf;
+
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ switch (event)
+ {
+ case BTIF_CORE_STORAGE_REMOTE_WRITE:
+ case BTIF_CORE_STORAGE_ADAPTER_WRITE:
+ {
+ bdcpy(new_req->write_req.bd_addr.address, old_req->write_req.bd_addr.address);
+ /* Copy the member variables one at a time */
+ new_req->write_req.prop.type = old_req->write_req.prop.type;
+ new_req->write_req.prop.len = old_req->write_req.prop.len;
+
+ new_req->write_req.prop.val = (UINT8 *)(p_new_buf + sizeof(btif_storage_req_t));
+ memcpy(new_req->write_req.prop.val, old_req->write_req.prop.val,
+ old_req->write_req.prop.len);
+ }break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_get_adapter_properties
+**
+** Description Fetch all available properties (local & remote)
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_adapter_properties(void)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ if (!btif_is_enabled())
+ return BT_STATUS_NOT_READY;
+
+ return btif_transfer_context(execute_storage_request,
+ BTIF_CORE_STORAGE_ADAPTER_READ_ALL,
+ NULL, 0, NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_get_adapter_property
+**
+** Description Fetches property value from local cache
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_get_adapter_property(bt_property_type_t type)
+{
+ btif_storage_req_t req;
+
+ BTIF_TRACE_EVENT2("%s %d", __FUNCTION__, type);
+
+ /* Allow get_adapter_property only for BDADDR and BDNAME if BT is disabled */
+ if (!btif_is_enabled() && (type != BT_PROPERTY_BDADDR) && (type != BT_PROPERTY_BDNAME))
+ return BT_STATUS_NOT_READY;
+
+ memset(&(req.read_req.bd_addr), 0, sizeof(bt_bdaddr_t));
+ req.read_req.type = type;
+
+ return btif_transfer_context(execute_storage_request,
+ BTIF_CORE_STORAGE_ADAPTER_READ,
+ (char*)&req, sizeof(btif_storage_req_t), NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_set_adapter_property
+**
+** Description Updates core stack with property value and stores it in
+** local cache
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_set_adapter_property(const bt_property_t *property)
+{
+ btif_storage_req_t req;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ int storage_req_id = BTIF_CORE_STORAGE_NOTIFY_STATUS; /* default */
+ char bd_name[BTM_MAX_LOC_BD_NAME_LEN +1];
+ UINT16 name_len = 0;
+
+ BTIF_TRACE_EVENT3("btif_set_adapter_property type: %d, len %d, 0x%x",
+ property->type, property->len, property->val);
+
+ if (!btif_is_enabled())
+ return BT_STATUS_NOT_READY;
+
+ switch(property->type)
+ {
+ case BT_PROPERTY_BDNAME:
+ {
+ name_len = property->len > BTM_MAX_LOC_BD_NAME_LEN ? BTM_MAX_LOC_BD_NAME_LEN:
+ property->len;
+ memcpy(bd_name,property->val, name_len);
+ bd_name[name_len] = '\0';
+
+ BTIF_TRACE_EVENT1("set property name : %s", (char *)bd_name);
+
+ BTA_DmSetDeviceName((char *)bd_name);
+
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ }
+ break;
+
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ {
+ bt_scan_mode_t mode = *(bt_scan_mode_t*)property->val;
+ tBTA_DM_DISC disc_mode;
+ tBTA_DM_CONN conn_mode;
+
+ switch(mode)
+ {
+ case BT_SCAN_MODE_NONE:
+ disc_mode = BTA_DM_NON_DISC;
+ conn_mode = BTA_DM_NON_CONN;
+ break;
+
+ case BT_SCAN_MODE_CONNECTABLE:
+ disc_mode = BTA_DM_NON_DISC;
+ conn_mode = BTA_DM_CONN;
+ break;
+
+ case BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ disc_mode = BTA_DM_GENERAL_DISC;
+ conn_mode = BTA_DM_CONN;
+ break;
+
+ default:
+ BTIF_TRACE_ERROR1("invalid scan mode (0x%x)", mode);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ BTIF_TRACE_EVENT1("set property scan mode : %x", mode);
+
+ BTA_DmSetVisibility(disc_mode, conn_mode, BTA_DM_IGNORE, BTA_DM_IGNORE);
+
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ }
+ break;
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ {
+ /* Nothing to do beside store the value in NV. Java
+ will change the SCAN_MODE property after setting timeout,
+ if required */
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ }
+ break;
+ case BT_PROPERTY_BDADDR:
+ case BT_PROPERTY_UUIDS:
+ case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ /* no write support through HAL, these properties are only populated from BTA events */
+ status = BT_STATUS_FAIL;
+ break;
+ default:
+ BTIF_TRACE_ERROR1("btif_get_adapter_property : invalid type %d",
+ property->type);
+ status = BT_STATUS_FAIL;
+ break;
+ }
+
+ if (storage_req_id != BTIF_CORE_STORAGE_NO_ACTION)
+ {
+ int btif_status;
+ /* pass on to storage for updating local database */
+
+ memset(&(req.write_req.bd_addr), 0, sizeof(bt_bdaddr_t));
+ memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
+
+ return btif_transfer_context(execute_storage_request,
+ storage_req_id,
+ (char*)&req,
+ sizeof(btif_storage_req_t)+property->len,
+ btif_in_storage_request_copy_cb);
+ }
+
+ return status;
+
+}
+
+/*******************************************************************************
+**
+** Function btif_get_remote_device_property
+**
+** Description Fetches the remote device property from the NVRAM
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_device_property(bt_bdaddr_t *remote_addr,
+ bt_property_type_t type)
+{
+ btif_storage_req_t req;
+
+ if (!btif_is_enabled())
+ return BT_STATUS_NOT_READY;
+
+ memcpy(&(req.read_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ req.read_req.type = type;
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_READ,
+ (char*)&req, sizeof(btif_storage_req_t),
+ NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_get_remote_device_properties
+**
+** Description Fetches all the remote device properties from NVRAM
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_device_properties(bt_bdaddr_t *remote_addr)
+{
+ btif_storage_req_t req;
+
+ if (!btif_is_enabled())
+ return BT_STATUS_NOT_READY;
+
+ memcpy(&(req.read_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_READ_ALL,
+ (char*)&req, sizeof(btif_storage_req_t),
+ NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_set_remote_device_property
+**
+** Description Writes the remote device property to NVRAM.
+** Currently, BT_PROPERTY_REMOTE_FRIENDLY_NAME is the only
+** remote device property that can be set
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_set_remote_device_property(bt_bdaddr_t *remote_addr,
+ const bt_property_t *property)
+{
+ btif_storage_req_t req;
+
+ if (!btif_is_enabled())
+ return BT_STATUS_NOT_READY;
+
+ memcpy(&(req.write_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
+
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_WRITE,
+ (char*)&req,
+ sizeof(btif_storage_req_t)+property->len,
+ btif_in_storage_request_copy_cb);
+}
+
+
+/*******************************************************************************
+**
+** Function btif_get_remote_service_record
+**
+** Description Looks up the service matching uuid on the remote device
+** and fetches the SCN and service_name if the UUID is found
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_get_remote_service_record(bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid)
+{
+ if (!btif_is_enabled())
+ return BT_STATUS_NOT_READY;
+
+ return btif_dm_get_remote_service_record(remote_addr, uuid);
+}
+
+
+/*******************************************************************************
+**
+** Function btif_get_enabled_services_mask
+**
+** Description Fetches currently enabled services
+**
+** Returns tBTA_SERVICE_MASK
+**
+*******************************************************************************/
+
+tBTA_SERVICE_MASK btif_get_enabled_services_mask(void)
+{
+ return btif_enabled_services;
+}
+
+/*******************************************************************************
+**
+** Function btif_enable_service
+**
+** Description Enables the service 'service_ID' to the service_mask.
+** Upon BT enable, BTIF core shall invoke the BTA APIs to
+** enable the profiles
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id)
+{
+ tBTA_SERVICE_ID *p_id = &service_id;
+
+ /* If BT is enabled, we need to switch to BTIF context and trigger the
+ * enable for that profile
+ *
+ * Otherwise, we just set the flag. On BT_Enable, the DM will trigger
+ * enable for the profiles that have been enabled */
+
+ btif_enabled_services |= (1 << service_id);
+
+ BTIF_TRACE_ERROR2("%s: current services:0x%x", __FUNCTION__, btif_enabled_services);
+
+ if (btif_is_enabled())
+ {
+ btif_transfer_context(btif_dm_execute_service_request,
+ BTIF_DM_ENABLE_SERVICE,
+ (char*)p_id, sizeof(tBTA_SERVICE_ID), NULL);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+/*******************************************************************************
+**
+** Function btif_disable_service
+**
+** Description Disables the service 'service_ID' to the service_mask.
+** Upon BT disable, BTIF core shall invoke the BTA APIs to
+** disable the profiles
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_disable_service(tBTA_SERVICE_ID service_id)
+{
+ tBTA_SERVICE_ID *p_id = &service_id;
+
+ /* If BT is enabled, we need to switch to BTIF context and trigger the
+ * disable for that profile so that the appropriate uuid_property_changed will
+ * be triggerred. Otherwise, we just need to clear the service_id in the mask
+ */
+
+ btif_enabled_services &= (tBTA_SERVICE_MASK)(~(1<<service_id));
+
+ BTIF_TRACE_ERROR2("%s: Current Services:0x%x", __FUNCTION__, btif_enabled_services);
+
+ if (btif_is_enabled())
+ {
+ btif_transfer_context(btif_dm_execute_service_request,
+ BTIF_DM_DISABLE_SERVICE,
+ (char*)p_id, sizeof(tBTA_SERVICE_ID), NULL);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
new file mode 100755
index 0000000..5517f55
--- /dev/null
+++ b/btif/src/btif_dm.c
@@ -0,0 +1,1876 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_dm.c
+ *
+ * Description: Contains Device Management (DM) related functionality
+ *
+ *
+ ***********************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include "gki.h"
+#include "btu.h"
+#include "bd.h"
+#include "bta_api.h"
+#include "btif_api.h"
+#include "btif_util.h"
+#include "btif_storage.h"
+#include "btif_hh.h"
+#include "btif_config.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#define COD_UNCLASSIFIED ((0x1F) << 8)
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+#define COD_AV_HEADSETS 0x0404
+#define COD_AV_HANDSFREE 0x0408
+#define COD_AV_HEADPHONES 0x0418
+#define COD_AV_PORTABLE_AUDIO 0x041C
+#define COD_AV_HIFI_AUDIO 0x0428
+
+
+#define BTIF_DM_DEFAULT_INQ_MAX_RESULTS 0
+#define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10
+
+typedef struct {
+ bt_bond_state_t state;
+ BD_ADDR bd_addr;
+ UINT8 is_temp;
+ UINT8 pin_code_len;
+ UINT8 is_ssp;
+ UINT8 autopair_attempts;
+ UINT8 is_local_initiated;
+ UINT8 bonded_pending_sdp;
+} btif_dm_pairing_cb_t;
+
+typedef struct {
+ BD_ADDR bd_addr;
+ BD_NAME bd_name;
+} btif_dm_remote_name_t;
+
+typedef struct
+{
+ BT_OCTET16 sp_c;
+ BT_OCTET16 sp_r;
+ BD_ADDR oob_bdaddr; /* peer bdaddr*/
+} btif_dm_oob_cb_t;
+#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
+
+/* This flag will be true if HCI_Inquiry is in progress */
+static BOOLEAN btif_dm_inquiry_in_progress = FALSE;
+
+/******************************************************************************
+** Static functions
+******************************************************************************/
+static btif_dm_pairing_cb_t pairing_cb;
+static btif_dm_oob_cb_t oob_cb;
+static void btif_dm_generic_evt(UINT16 event, char* p_param);
+static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr);
+static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME *p_remote_name);
+static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+ DEV_CLASS dev_class, tBT_DEVICE_TYPE dev_type);
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+extern UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID];
+extern bt_status_t btif_hf_execute_service(BOOLEAN b_enable);
+extern bt_status_t btif_av_execute_service(BOOLEAN b_enable);
+extern bt_status_t btif_hh_execute_service(BOOLEAN b_enable);
+extern int btif_hh_connect(bt_bdaddr_t *bd_addr);
+
+
+/******************************************************************************
+** Functions
+******************************************************************************/
+
+bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
+ BOOLEAN b_enable)
+{
+ /* Check the service_ID and invoke the profile's BT state changed API */
+ switch (service_id)
+ {
+ case BTA_HFP_SERVICE_ID:
+ case BTA_HSP_SERVICE_ID:
+ {
+ btif_hf_execute_service(b_enable);
+ }break;
+ case BTA_A2DP_SERVICE_ID:
+ {
+ btif_av_execute_service(b_enable);
+ }break;
+ case BTA_HID_SERVICE_ID:
+ {
+ btif_hh_execute_service(b_enable);
+ }break;
+
+ default:
+ BTIF_TRACE_ERROR1("%s: Unknown service being enabled", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function check_eir_remote_name
+**
+** Description Check if remote name is in the EIR data
+**
+** Returns TRUE if remote name found
+** Populate p_remote_name, if provided and remote name found
+**
+*******************************************************************************/
+static BOOLEAN check_eir_remote_name(tBTA_DM_SEARCH *p_search_data,
+ UINT8 *p_remote_name, UINT8 *p_remote_name_len)
+{
+ UINT8 *p_eir_remote_name = NULL;
+ UINT8 remote_name_len = 0;
+
+ /* Check EIR for remote name and services */
+ if (p_search_data->inq_res.p_eir)
+ {
+ p_eir_remote_name = BTA_CheckEirData(p_search_data->inq_res.p_eir,
+ BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+ if (!p_eir_remote_name)
+ {
+ p_eir_remote_name = BTA_CheckEirData(p_search_data->inq_res.p_eir,
+ BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+ }
+
+ if (p_eir_remote_name)
+ {
+ if (remote_name_len > BD_NAME_LEN)
+ remote_name_len = BD_NAME_LEN;
+
+ if (p_remote_name && p_remote_name_len)
+ {
+ memcpy(p_remote_name, p_eir_remote_name, remote_name_len);
+ *(p_remote_name + remote_name_len) = 0;
+ *p_remote_name_len = remote_name_len;
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+
+}
+
+/*******************************************************************************
+**
+** Function check_cached_remote_name
+**
+** Description Check if remote name is in the NVRAM cache
+**
+** Returns TRUE if remote name found
+** Populate p_remote_name, if provided and remote name found
+**
+*******************************************************************************/
+static BOOLEAN check_cached_remote_name(tBTA_DM_SEARCH *p_search_data,
+ UINT8 *p_remote_name, UINT8 *p_remote_name_len)
+{
+ bt_bdname_t bdname;
+ bt_bdaddr_t remote_bdaddr;
+ bt_property_t prop_name;
+
+ /* check if we already have it in our btif_storage cache */
+ bdcpy(remote_bdaddr.address, p_search_data->inq_res.bd_addr);
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property(
+ &remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS)
+ {
+ if (p_remote_name && p_remote_name_len)
+ {
+ strcpy((char *)p_remote_name, (char *)bdname.name);
+ *p_remote_name_len = strlen((char *)p_remote_name);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod)
+{
+ uint32_t remote_cod;
+ bt_property_t prop_name;
+
+ /* check if we already have it in our btif_storage cache */
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_CLASS_OF_DEVICE,
+ sizeof(uint32_t), &remote_cod);
+ if (btif_storage_get_remote_device_property((bt_bdaddr_t *)remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS)
+ {
+ if ((remote_cod & 0x7ff) == cod)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void bond_state_changed(bt_status_t status, bt_bdaddr_t *bd_addr, bt_bond_state_t state)
+{
+ /* Send bonding state only once - based on outgoing/incoming we may receive duplicates */
+ if ( (pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING) )
+ return;
+
+ if (pairing_cb.is_temp)
+ {
+ state = BT_BOND_STATE_NONE;
+ }
+ BTIF_TRACE_DEBUG3("%s: state=%d prev_state=%d", __FUNCTION__, state, pairing_cb.state);
+
+ HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, bd_addr, state);
+
+ if (state == BT_BOND_STATE_BONDING)
+ {
+ pairing_cb.state = state;
+ bdcpy(pairing_cb.bd_addr, bd_addr->address);
+ }
+ else
+ {
+ memset(&pairing_cb, 0, sizeof(pairing_cb));
+ }
+
+}
+
+
+static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+ DEV_CLASS dev_class, tBT_DEVICE_TYPE device_type)
+{
+ int num_properties = 0;
+ bt_property_t properties[3];
+ bt_bdaddr_t bdaddr;
+ bt_status_t status;
+ UINT32 cod;
+ bt_device_type_t dev_type;
+
+ memset(properties, 0, sizeof(properties));
+ bdcpy(bdaddr.address, bd_addr);
+
+ /* remote name */
+ if (strlen((const char *) bd_name))
+ {
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_BDNAME, strlen((char *)bd_name), bd_name);
+ status = btif_storage_set_remote_device_property(&bdaddr, &properties[num_properties]);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device name", status);
+ num_properties++;
+ }
+
+ /* class of device */
+ cod = devclass2uint(dev_class);
+ if ( cod == 0) {
+ BTIF_TRACE_DEBUG1("%s():cod is 0, set as unclassified", __FUNCTION__);
+ cod = COD_UNCLASSIFIED;
+ }
+
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+ status = btif_storage_set_remote_device_property(&bdaddr, &properties[num_properties]);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device class", status);
+ num_properties++;
+
+ /* device type */
+ dev_type = device_type;
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type), &dev_type);
+ status = btif_storage_set_remote_device_property(&bdaddr, &properties[num_properties]);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device type", status);
+ num_properties++;
+
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ status, &bdaddr, num_properties, properties);
+}
+/*******************************************************************************
+**
+** Function hid_remote_name_cback
+**
+** Description Remote name callback for HID device. Called in stack context
+** Special handling for HID devices
+**
+** Returns void
+**
+*******************************************************************************/
+static void hid_remote_name_cback(void *p_param)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_HID_REMOTE_NAME,
+ (char *)p_param, sizeof(tBTM_REMOTE_DEV_NAME), NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_cb_hid_remote_name
+**
+** Description Remote name callback for HID device. Called in btif context
+** Special handling for HID devices
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME *p_remote_name)
+{
+ BTIF_TRACE_DEBUG3("%s: status=%d pairing_cb.state=%d", __FUNCTION__, p_remote_name->status, pairing_cb.state);
+ if (pairing_cb.state == BT_BOND_STATE_BONDING)
+ {
+ bt_bdaddr_t remote_bd;
+
+ bdcpy(remote_bd.address, pairing_cb.bd_addr);
+
+ if (p_remote_name->status == BTM_SUCCESS)
+ {
+ bond_state_changed(BT_STATUS_SUCCESS, &remote_bd, BT_BOND_STATE_BONDED);
+ }
+ else
+ bond_state_changed(BT_STATUS_FAIL, &remote_bd, BT_BOND_STATE_NONE);
+ }
+}
+
+int remove_hid_bond(bt_bdaddr_t *bd_addr)
+{
+ /* For HID device, inorder to avoid the HID device from re-connecting again after unpairing,
+ * we need to do virtual unplug
+ */
+ bdstr_t bdstr;
+ BTIF_TRACE_DEBUG2("%s---Removing HID bond--%s", __FUNCTION__,bd2str((bt_bdaddr_t *)bd_addr, &bdstr));
+ return btif_hh_virtual_unplug(bd_addr);
+}
+/*******************************************************************************
+**
+** Function btif_dm_cb_create_bond
+**
+** Description Create bond initiated from the BTIF thread context
+** Special handling for HID devices
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_cb_create_bond(bt_bdaddr_t *bd_addr)
+{
+ bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
+ if (check_cod(bd_addr, COD_HID_POINTING)){
+ int status;
+ status = btif_hh_connect(bd_addr);
+ if(status != BT_STATUS_SUCCESS)
+ bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);
+ }
+ else
+ BTA_DmBond ((UINT8 *)bd_addr->address);
+
+ /* Track originator of bond creation */
+ pairing_cb.is_local_initiated = TRUE;
+
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_cb_remove_bond
+**
+** Description remove bond initiated from the BTIF thread context
+** Special handling for HID devices
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_dm_cb_remove_bond(bt_bdaddr_t *bd_addr)
+{
+ bdstr_t bdstr;
+ /*special handling for HID devices */
+ if (check_cod(bd_addr, COD_HID_POINTING) ||
+ check_cod(bd_addr, COD_HID_KEYBOARD) ||
+ check_cod(bd_addr, COD_HID_COMBO))
+ {
+ #if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
+ if(remove_hid_bond(bd_addr) != BTA_SUCCESS)
+ BTA_DmRemoveDevice((UINT8 *)bd_addr->address);
+ #endif
+ }
+ else
+ {
+ if (BTA_DmRemoveDevice((UINT8 *)bd_addr->address) == BTA_SUCCESS)
+ {
+ BTIF_TRACE_DEBUG1("Successfully removed bonding with device: %s",
+ bd2str((bt_bdaddr_t *)bd_addr, &bdstr));
+ }
+ else
+ BTIF_TRACE_DEBUG1("Removed bonding with device failed: %s",
+ bd2str((bt_bdaddr_t *)bd_addr, &bdstr));
+ }
+}
+
+/*******************************************************************************
+**
+** Function search_devices_copy_cb
+**
+** Description Deep copy callback for search devices event
+**
+** Returns void
+**
+*******************************************************************************/
+static void search_devices_copy_cb(UINT16 event, char *p_dest, char *p_src)
+{
+ tBTA_DM_SEARCH *p_dest_data = (tBTA_DM_SEARCH *) p_dest;
+ tBTA_DM_SEARCH *p_src_data = (tBTA_DM_SEARCH *) p_src;
+
+ if (!p_src)
+ return;
+
+ BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_dm_search_event(event));
+ memcpy(p_dest_data, p_src_data, sizeof(tBTA_DM_SEARCH));
+ switch (event)
+ {
+ case BTA_DM_INQ_RES_EVT:
+ {
+ if (p_src_data->inq_res.p_eir)
+ {
+ p_dest_data->inq_res.p_eir = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
+ memcpy(p_dest_data->inq_res.p_eir, p_src_data->inq_res.p_eir, HCI_EXT_INQ_RESPONSE_LEN);
+ }
+ }
+ break;
+
+ case BTA_DM_DISC_RES_EVT:
+ {
+ if (p_src_data->disc_res.raw_data_size && p_src_data->disc_res.p_raw_data)
+ {
+ p_dest_data->disc_res.p_raw_data = (UINT8 *)(p_dest + sizeof(tBTA_DM_SEARCH));
+ memcpy(p_dest_data->disc_res.p_raw_data,
+ p_src_data->disc_res.p_raw_data, p_src_data->disc_res.raw_data_size);
+ }
+ }
+ break;
+ }
+}
+
+static void search_services_copy_cb(UINT16 event, char *p_dest, char *p_src)
+{
+ tBTA_DM_SEARCH *p_dest_data = (tBTA_DM_SEARCH *) p_dest;
+ tBTA_DM_SEARCH *p_src_data = (tBTA_DM_SEARCH *) p_src;
+
+ if (!p_src)
+ return;
+ memcpy(p_dest_data, p_src_data, sizeof(tBTA_DM_SEARCH));
+ switch (event)
+ {
+ case BTA_DM_DISC_RES_EVT:
+ {
+ if ((p_src_data->disc_res.result == BTA_SUCCESS) &&
+ (p_src_data->disc_res.num_uuids > 0))
+ {
+ p_dest_data->disc_res.p_uuid_list = (UINT8*)(p_dest + sizeof(tBTA_DM_SEARCH));
+ memcpy(p_dest_data->disc_res.p_uuid_list, p_src_data->disc_res.p_uuid_list,
+ p_src_data->disc_res.num_uuids*MAX_UUID_SIZE);
+ }
+ } break;
+ }
+}
+/******************************************************************************
+**
+** BTIF DM callback events
+**
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_dm_pin_req_evt
+**
+** Description Executes pin request event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ *p_pin_req)
+{
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ UINT32 cod;
+ bt_pin_code_t pin_code;
+
+ /* Remote properties update */
+ btif_update_remote_properties(p_pin_req->bd_addr, p_pin_req->bd_name,
+ p_pin_req->dev_class, BT_DEVICE_TYPE_BREDR);
+
+ bdcpy(bd_addr.address, p_pin_req->bd_addr);
+ memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+
+ cod = devclass2uint(p_pin_req->dev_class);
+
+ if ( cod == 0) {
+ BTIF_TRACE_DEBUG1("%s():cod is 0, set as unclassified", __FUNCTION__);
+ cod = COD_UNCLASSIFIED;
+ }
+
+ /* check for auto pair possiblity only if bond was initiated by local device */
+ if (pairing_cb.is_local_initiated)
+ {
+ if (check_cod(&bd_addr, COD_AV_HEADSETS) ||
+ check_cod(&bd_addr, COD_AV_HANDSFREE) ||
+ check_cod(&bd_addr, COD_AV_HEADPHONES) ||
+ check_cod(&bd_addr, COD_AV_PORTABLE_AUDIO) ||
+ check_cod(&bd_addr, COD_AV_HIFI_AUDIO) ||
+ check_cod(&bd_addr, COD_HID_POINTING))
+ {
+ BTIF_TRACE_DEBUG1("%s()cod matches for auto pair", __FUNCTION__);
+ /* Check if this device can be auto paired */
+ if ((btif_storage_is_device_autopair_blacklisted(&bd_addr) == FALSE) &&
+ (pairing_cb.autopair_attempts == 0))
+ {
+ BTIF_TRACE_DEBUG1("%s() Attempting auto pair", __FUNCTION__);
+ pin_code.pin[0] = 0x30;
+ pin_code.pin[1] = 0x30;
+ pin_code.pin[2] = 0x30;
+ pin_code.pin[3] = 0x30;
+
+ pairing_cb.autopair_attempts++;
+ BTA_DmPinReply( (UINT8*)bd_addr.address, TRUE, 4, pin_code.pin);
+ return;
+ }
+ }
+ else if (check_cod(&bd_addr, COD_HID_KEYBOARD) ||
+ check_cod(&bd_addr, COD_HID_COMBO))
+ {
+ if(( btif_storage_is_fixed_pin_zeros_keyboard (&bd_addr) == TRUE) &&
+ (pairing_cb.autopair_attempts == 0))
+ {
+ BTIF_TRACE_DEBUG1("%s() Attempting auto pair", __FUNCTION__);
+ pin_code.pin[0] = 0x30;
+ pin_code.pin[1] = 0x30;
+ pin_code.pin[2] = 0x30;
+ pin_code.pin[3] = 0x30;
+
+ pairing_cb.autopair_attempts++;
+ BTA_DmPinReply( (UINT8*)bd_addr.address, TRUE, 4, pin_code.pin);
+ return;
+ }
+ }
+ }
+ HAL_CBACK(bt_hal_cbacks, pin_request_cb,
+ &bd_addr, &bd_name, cod);
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_ssp_cfm_req_evt
+**
+** Description Executes SSP confirm request event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ *p_ssp_cfm_req)
+{
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ UINT32 cod;
+ BOOLEAN is_incoming = !(pairing_cb.state == BT_BOND_STATE_BONDING);
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ /* Remote properties update */
+ btif_update_remote_properties(p_ssp_cfm_req->bd_addr, p_ssp_cfm_req->bd_name,
+ p_ssp_cfm_req->dev_class, BT_DEVICE_TYPE_BREDR);
+
+ bdcpy(bd_addr.address, p_ssp_cfm_req->bd_addr);
+ memcpy(bd_name.name, p_ssp_cfm_req->bd_name, BD_NAME_LEN);
+
+ /* Set the pairing_cb based on the local & remote authentication requirements */
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+
+ /* if just_works and bonding bit is not set treat this as temporary */
+ if (p_ssp_cfm_req->just_works && !(p_ssp_cfm_req->loc_auth_req & BTM_AUTH_BONDS) &&
+ !(p_ssp_cfm_req->rmt_auth_req & BTM_AUTH_BONDS))
+ pairing_cb.is_temp = TRUE;
+ else
+ pairing_cb.is_temp = FALSE;
+
+ pairing_cb.is_ssp = TRUE;
+
+ /* If JustWorks auto-accept */
+ if (p_ssp_cfm_req->just_works)
+ {
+ /* Pairing consent for JustWorks needed if:
+ * 1. Incoming pairing is detected AND
+ * 2. local IO capabilities are DisplayYesNo AND
+ * 3. remote IO capabiltiies are DisplayOnly or NoInputNoOutput;
+ */
+ if ((is_incoming) && ((p_ssp_cfm_req->loc_io_caps == 0x01) &&
+ (p_ssp_cfm_req->rmt_io_caps == 0x00 || p_ssp_cfm_req->rmt_io_caps == 0x03)))
+ {
+ BTIF_TRACE_EVENT3("%s: User consent needed for incoming pairing request. loc_io_caps: %d, rmt_io_caps: %d",
+ __FUNCTION__, p_ssp_cfm_req->loc_io_caps, p_ssp_cfm_req->rmt_io_caps);
+ }
+ else
+ {
+ BTIF_TRACE_EVENT1("%s: Auto-accept JustWorks pairing", __FUNCTION__);
+ btif_dm_ssp_reply(&bd_addr, BT_SSP_VARIANT_CONSENT, TRUE, 0);
+ return;
+ }
+ }
+
+ cod = devclass2uint(p_ssp_cfm_req->dev_class);
+
+ if ( cod == 0) {
+ ALOGD("cod is 0, set as unclassified");
+ cod = COD_UNCLASSIFIED;
+ }
+
+ pairing_cb.bonded_pending_sdp = FALSE;
+ HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+ (p_ssp_cfm_req->just_works ? BT_SSP_VARIANT_CONSENT : BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
+ p_ssp_cfm_req->num_val);
+}
+
+static void btif_dm_ssp_key_notif_evt(tBTA_DM_SP_KEY_NOTIF *p_ssp_key_notif)
+{
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ UINT32 cod;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ /* Remote properties update */
+ btif_update_remote_properties(p_ssp_key_notif->bd_addr, p_ssp_key_notif->bd_name,
+ p_ssp_key_notif->dev_class, BT_DEVICE_TYPE_BREDR);
+
+ bdcpy(bd_addr.address, p_ssp_key_notif->bd_addr);
+ memcpy(bd_name.name, p_ssp_key_notif->bd_name, BD_NAME_LEN);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ pairing_cb.is_ssp = TRUE;
+ cod = devclass2uint(p_ssp_key_notif->dev_class);
+
+ if ( cod == 0) {
+ ALOGD("cod is 0, set as unclassified");
+ cod = COD_UNCLASSIFIED;
+ }
+
+ HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name,
+ cod, BT_SSP_VARIANT_PASSKEY_NOTIFICATION,
+ p_ssp_key_notif->passkey);
+}
+/*******************************************************************************
+**
+** Function btif_dm_auth_cmpl_evt
+**
+** Description Executes authentication complete event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
+{
+ /* Save link key, if not temporary */
+ bt_bdaddr_t bd_addr;
+ bt_status_t status = BT_STATUS_FAIL;
+ bt_bond_state_t state = BT_BOND_STATE_NONE;
+
+ bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+ if ( (p_auth_cmpl->success == TRUE) && (p_auth_cmpl->key_present) )
+ {
+ if ((p_auth_cmpl->key_type < HCI_LKEY_TYPE_DEBUG_COMB) || (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) ||
+ (p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) || (!pairing_cb.is_temp))
+ {
+ bt_status_t ret;
+ BTIF_TRACE_DEBUG3("%s: Storing link key. key_type=0x%x, is_temp=%d",
+ __FUNCTION__, p_auth_cmpl->key_type, pairing_cb.is_temp);
+ ret = btif_storage_add_bonded_device(&bd_addr,
+ p_auth_cmpl->key, p_auth_cmpl->key_type,
+ pairing_cb.pin_code_len);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG3("%s: Temporary key. Not storing. key_type=0x%x, is_temp=%d",
+ __FUNCTION__, p_auth_cmpl->key_type, pairing_cb.is_temp);
+ }
+ }
+ if (p_auth_cmpl->success)
+ {
+ status = BT_STATUS_SUCCESS;
+ state = BT_BOND_STATE_BONDED;
+
+ /* Trigger SDP on the device */
+ pairing_cb.bonded_pending_sdp = TRUE;
+ btif_dm_get_remote_services(&bd_addr);
+ /* Do not call bond_state_changed_cb yet. Wait till fetch remote service is complete */
+ }
+ else
+ {
+ /*Map the HCI fail reason to bt status */
+ switch(p_auth_cmpl->fail_reason)
+ {
+ case HCI_ERR_PAGE_TIMEOUT:
+ case HCI_ERR_CONNECTION_TOUT:
+ status = BT_STATUS_RMT_DEV_DOWN;
+ break;
+
+ /* map the auth failure codes, so we can retry pairing if necessary */
+ case HCI_ERR_AUTH_FAILURE:
+ case HCI_ERR_HOST_REJECT_SECURITY:
+ case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE:
+ case HCI_ERR_UNIT_KEY_USED:
+ case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED:
+ case HCI_ERR_INSUFFCIENT_SECURITY:
+ BTIF_TRACE_DEBUG1(" %s() Authentication fail ", __FUNCTION__);
+ if (pairing_cb.autopair_attempts == 1)
+ {
+ BTIF_TRACE_DEBUG1("%s(): Adding device to blacklist ", __FUNCTION__);
+
+ /* Add the device to dynamic black list only if this device belongs to Audio/pointing dev class */
+ if (check_cod(&bd_addr, COD_AV_HEADSETS) ||
+ check_cod(&bd_addr, COD_AV_HANDSFREE) ||
+ check_cod(&bd_addr, COD_AV_HEADPHONES) ||
+ check_cod(&bd_addr, COD_AV_PORTABLE_AUDIO) ||
+ check_cod(&bd_addr, COD_AV_HIFI_AUDIO) ||
+ check_cod(&bd_addr, COD_HID_POINTING))
+ {
+ btif_storage_add_device_to_autopair_blacklist (&bd_addr);
+ }
+ pairing_cb.autopair_attempts++;
+
+ /* Create the Bond once again */
+ BTIF_TRACE_DEBUG1("%s() auto pair failed. Reinitiate Bond", __FUNCTION__);
+ btif_dm_cb_create_bond (&bd_addr);
+ return;
+ }
+ else
+ {
+ /* if autopair attempts are more than 1, or not attempted */
+ status = BT_STATUS_AUTH_FAILURE;
+ }
+ break;
+
+ default:
+ status = BT_STATUS_FAIL;
+ }
+ bond_state_changed(status, &bd_addr, state);
+ }
+}
+
+/******************************************************************************
+**
+** Function btif_dm_search_devices_evt
+**
+** Description Executes search devices callback events in btif context
+**
+** Returns void
+**
+******************************************************************************/
+static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
+{
+ tBTA_DM_SEARCH *p_search_data;
+ BTIF_TRACE_EVENT2("%s event=%s", __FUNCTION__, dump_dm_search_event(event));
+
+ switch (event)
+ {
+ case BTA_DM_DISC_RES_EVT:
+ {
+ p_search_data = (tBTA_DM_SEARCH *)p_param;
+ /* Remote name update */
+ if (strlen((const char *) p_search_data->disc_res.bd_name))
+ {
+ bt_property_t properties[1];
+ bt_bdaddr_t bdaddr;
+ bt_status_t status;
+
+ properties[0].type = BT_PROPERTY_BDNAME;
+ properties[0].val = p_search_data->disc_res.bd_name;
+ properties[0].len = strlen((char *)p_search_data->disc_res.bd_name);
+ bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);
+
+ status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status);
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ status, &bdaddr, 1, properties);
+ }
+ /* TODO: Services? */
+ }
+ break;
+
+ case BTA_DM_INQ_RES_EVT:
+ {
+ /* inquiry result */
+ UINT32 cod;
+ UINT8 *p_eir_remote_name = NULL;
+ bt_bdname_t bdname;
+ bt_bdaddr_t bdaddr;
+ UINT8 remote_name_len;
+ UINT8 *p_cached_name = NULL;
+ tBTA_SERVICE_MASK services = 0;
+ bdstr_t bdstr;
+
+ p_search_data = (tBTA_DM_SEARCH *)p_param;
+ bdcpy(bdaddr.address, p_search_data->inq_res.bd_addr);
+
+ BTIF_TRACE_DEBUG3("%s() %s device_type = 0x%x\n", __FUNCTION__, bd2str(&bdaddr, &bdstr),
+#if (BLE_INCLUDED == TRUE)
+ p_search_data->inq_res.device_type);
+#else
+ BT_DEVICE_TYPE_BREDR);
+#endif
+ bdname.name[0] = 0;
+
+ cod = devclass2uint (p_search_data->inq_res.dev_class);
+
+ if ( cod == 0) {
+ ALOGD("cod is 0, set as unclassified");
+ cod = COD_UNCLASSIFIED;
+ }
+
+ if (!check_eir_remote_name(p_search_data, bdname.name, &remote_name_len))
+ check_cached_remote_name(p_search_data, bdname.name, &remote_name_len);
+
+ /* Check EIR for remote name and services */
+ if (p_search_data->inq_res.p_eir)
+ {
+ BTA_GetEirService(p_search_data->inq_res.p_eir, &services);
+ BTIF_TRACE_DEBUG2("%s()EIR BTA services = %08X", __FUNCTION__, (UINT32)services);
+ /* TODO: Get the service list and check to see which uuids we got and send it back to the client. */
+ }
+
+
+ {
+ bt_property_t properties[5];
+ bt_device_type_t dev_type;
+ uint32_t num_properties = 0;
+ bt_status_t status;
+
+ memset(properties, 0, sizeof(properties));
+ /* BD_ADDR */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_BDADDR, sizeof(bdaddr), &bdaddr);
+ num_properties++;
+ /* BD_NAME */
+ /* Don't send BDNAME if it is empty */
+ if (bdname.name[0]) {
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_BDNAME,
+ strlen((char *)bdname.name), &bdname);
+ num_properties++;
+ }
+
+ /* DEV_CLASS */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+ num_properties++;
+ /* DEV_TYPE */
+#if (BLE_INCLUDED == TRUE)
+ /* FixMe: Assumption is that bluetooth.h and BTE enums match */
+ dev_type = p_search_data->inq_res.device_type;
+#else
+ dev_type = BT_DEVICE_TYPE_BREDR;
+#endif
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type), &dev_type);
+ num_properties++;
+ /* RSSI */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_REMOTE_RSSI, sizeof(int8_t),
+ &(p_search_data->inq_res.rssi));
+ num_properties++;
+
+ status = btif_storage_add_remote_device(&bdaddr, num_properties, properties);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device (inquiry)", status);
+
+ /* Callback to notify upper layer of device */
+ HAL_CBACK(bt_hal_cbacks, device_found_cb,
+ num_properties, properties);
+ }
+ }
+ break;
+
+ case BTA_DM_INQ_CMPL_EVT:
+ {
+ }
+ break;
+ case BTA_DM_DISC_CMPL_EVT:
+ {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED);
+ }
+ break;
+ case BTA_DM_SEARCH_CANCEL_CMPL_EVT:
+ {
+ /* if inquiry is not in progress and we get a cancel event, then
+ * it means we are done with inquiry, but remote_name fetches are in
+ * progress
+ *
+ * if inquiry is in progress, then we don't want to act on this cancel_cmpl_evt
+ * but instead wait for the cancel_cmpl_evt via the Busy Level
+ *
+ */
+ if (btif_dm_inquiry_in_progress == FALSE)
+ {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED);
+ }
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_search_services_evt
+**
+** Description Executes search services event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_search_services_evt(UINT16 event, char *p_param)
+{
+ tBTA_DM_SEARCH *p_data = (tBTA_DM_SEARCH*)p_param;
+
+ BTIF_TRACE_EVENT2("%s: event = %d", __FUNCTION__, event);
+ switch (event)
+ {
+ case BTA_DM_DISC_RES_EVT:
+ {
+ bt_uuid_t uuid_arr[BT_MAX_NUM_UUIDS]; /* Max 32 services */
+ bt_property_t prop;
+ uint32_t i = 0, j = 0;
+ bt_bdaddr_t bd_addr;
+ bt_status_t ret;
+
+ bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
+
+ BTIF_TRACE_DEBUG3("%s:(result=0x%x, services 0x%x)", __FUNCTION__,
+ p_data->disc_res.result, p_data->disc_res.services);
+ prop.type = BT_PROPERTY_UUIDS;
+ prop.len = 0;
+ if ((p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0))
+ {
+ prop.val = p_data->disc_res.p_uuid_list;
+ prop.len = p_data->disc_res.num_uuids * MAX_UUID_SIZE;
+ for (i=0; i < p_data->disc_res.num_uuids; i++)
+ {
+ char temp[256];
+ uuid_to_string((bt_uuid_t*)(p_data->disc_res.p_uuid_list + (i*MAX_UUID_SIZE)), temp);
+ BTIF_TRACE_ERROR2("Index: %d uuid:%s", i, temp);
+ }
+ }
+
+ /* onUuidChanged requires getBondedDevices to be populated.
+ ** bond_state_changed needs to be sent prior to remote_device_property
+ */
+ if ((pairing_cb.state == BT_BOND_STATE_BONDING) &&
+ (bdcmp(p_data->disc_res.bd_addr, pairing_cb.bd_addr) == 0)&&
+ pairing_cb.bonded_pending_sdp == TRUE)
+ {
+ BTIF_TRACE_DEBUG1("%s Remote Service SDP done. Call bond_state_changed_cb BONDED",
+ __FUNCTION__);
+ pairing_cb.bonded_pending_sdp = FALSE;
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
+ }
+
+ /* Also write this to the NVRAM */
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+ /* Send the event to the BTIF */
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+ }
+ break;
+
+ case BTA_DM_DISC_CMPL_EVT:
+ /* fixme */
+ break;
+
+ default:
+ {
+ ASSERTC(0, "unhandled search services event", event);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_remote_service_record_evt
+**
+** Description Executes search service record event in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_remote_service_record_evt(UINT16 event, char *p_param)
+{
+ tBTA_DM_SEARCH *p_data = (tBTA_DM_SEARCH*)p_param;
+
+ BTIF_TRACE_EVENT2("%s: event = %d", __FUNCTION__, event);
+ switch (event)
+ {
+ case BTA_DM_DISC_RES_EVT:
+ {
+ bt_service_record_t rec;
+ bt_property_t prop;
+ uint32_t i = 0;
+ bt_bdaddr_t bd_addr;
+
+ memset(&rec, 0, sizeof(bt_service_record_t));
+ bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
+
+ BTIF_TRACE_DEBUG3("%s:(result=0x%x, services 0x%x)", __FUNCTION__,
+ p_data->disc_res.result, p_data->disc_res.services);
+ prop.type = BT_PROPERTY_SERVICE_RECORD;
+ prop.val = (void*)&rec;
+ prop.len = sizeof(rec);
+
+ /* disc_res.result is overloaded with SCN. Cannot check result */
+ p_data->disc_res.services &= ~BTA_USER_SERVICE_MASK;
+ /* TODO: Get the UUID as well */
+ rec.channel = p_data->disc_res.result - 3;
+ /* TODO: Need to get the service name using p_raw_data */
+ rec.name[0] = 0;
+
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+ BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+ }
+ break;
+
+ default:
+ {
+ ASSERTC(0, "unhandled remote service record event", event);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_upstreams_cback
+**
+** Description Executes UPSTREAMS events in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
+{
+ tBTA_DM_SEC_EVT dm_event = (tBTA_DM_SEC_EVT)event;
+ tBTA_DM_SEC *p_data = (tBTA_DM_SEC*)p_param;
+ tBTA_SERVICE_MASK service_mask;
+ uint32_t i;
+ bt_bdaddr_t bd_addr;
+
+ BTIF_TRACE_EVENT1("btif_dm_upstreams_cback ev: %s", dump_dm_event(event));
+
+ switch (event)
+ {
+ case BTA_DM_ENABLE_EVT:
+ {
+ BD_NAME bdname;
+ bt_status_t status;
+ bt_property_t prop;
+ prop.type = BT_PROPERTY_BDNAME;
+ prop.len = BD_NAME_LEN;
+ prop.val = (void*)bdname;
+
+ status = btif_storage_get_adapter_property(&prop);
+ /* Storage does not have a name yet.
+ ** Use the default name and write it to the chip
+ */
+ if (status != BT_STATUS_SUCCESS)
+ {
+ BTA_DmSetDeviceName((char *)BTM_DEF_LOCAL_NAME);
+ /* Hmmm...Should we store this too??? */
+ }
+ else
+ {
+ /* A name exists in the storage. Make this the device name */
+ BTA_DmSetDeviceName((char*)prop.val);
+ }
+
+ /* for each of the enabled services in the mask, trigger the profile
+ * enable */
+ service_mask = btif_get_enabled_services_mask();
+ for (i=0; i <= BTA_MAX_SERVICE_ID; i++)
+ {
+ if (service_mask &
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i)))
+ {
+ btif_in_execute_service_request(i, TRUE);
+ }
+ }
+ /* clear control blocks */
+ memset(&pairing_cb, 0, sizeof(btif_dm_pairing_cb_t));
+
+ /* This function will also trigger the adapter_properties_cb
+ ** and bonded_devices_info_cb
+ */
+ btif_storage_load_bonded_devices();
+
+ btif_storage_load_autopair_device_list();
+
+ btif_enable_bluetooth_evt(p_data->enable.status, p_data->enable.bd_addr);
+ }
+ break;
+
+ case BTA_DM_DISABLE_EVT:
+ /* for each of the enabled services in the mask, trigger the profile
+ * disable */
+ service_mask = btif_get_enabled_services_mask();
+ for (i=0; i <= BTA_MAX_SERVICE_ID; i++)
+ {
+ if (service_mask &
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i)))
+ {
+ btif_in_execute_service_request(i, FALSE);
+ }
+ }
+ btif_disable_bluetooth_evt();
+ break;
+
+ case BTA_DM_PIN_REQ_EVT:
+ btif_dm_pin_req_evt(&p_data->pin_req);
+ break;
+
+ case BTA_DM_AUTH_CMPL_EVT:
+ btif_dm_auth_cmpl_evt(&p_data->auth_cmpl);
+ break;
+
+ case BTA_DM_BOND_CANCEL_CMPL_EVT:
+ if (pairing_cb.state == BT_BOND_STATE_BONDING)
+ {
+ bdcpy(bd_addr.address, pairing_cb.bd_addr);
+ bond_state_changed(p_data->bond_cancel_cmpl.result, &bd_addr, BT_BOND_STATE_NONE);
+ }
+ break;
+
+ case BTA_DM_SP_CFM_REQ_EVT:
+ btif_dm_ssp_cfm_req_evt(&p_data->cfm_req);
+ break;
+ case BTA_DM_SP_KEY_NOTIF_EVT:
+ btif_dm_ssp_key_notif_evt(&p_data->key_notif);
+ break;
+
+ case BTA_DM_DEV_UNPAIRED_EVT:
+ bdcpy(bd_addr.address, p_data->link_down.bd_addr);
+
+ /*special handling for HID devices */
+ #if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE))
+ if (check_cod(&bd_addr, COD_HID_KEYBOARD )|| check_cod(&bd_addr, COD_HID_COMBO) || check_cod(&bd_addr, COD_HID_POINTING)) {
+ btif_hh_remove_device(bd_addr);
+ }
+ #endif
+ btif_storage_remove_bonded_device(&bd_addr);
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);
+ break;
+
+ case BTA_DM_BUSY_LEVEL_EVT:
+ {
+ UINT8 busy_level;
+ busy_level = p_data->busy_level.level;
+ if (busy_level & BTM_BL_INQUIRY_PAGING_MASK)
+ {
+ if (busy_level == BTM_BL_INQUIRY_STARTED)
+ {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+ BT_DISCOVERY_STARTED);
+ btif_dm_inquiry_in_progress = TRUE;
+ }
+ else if (busy_level == BTM_BL_INQUIRY_CANCELLED)
+ {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+ BT_DISCOVERY_STOPPED);
+ btif_dm_inquiry_in_progress = FALSE;
+ }
+ else if (busy_level == BTM_BL_INQUIRY_COMPLETE)
+ {
+ btif_dm_inquiry_in_progress = FALSE;
+ }
+ }
+ }break;
+
+ case BTA_DM_LINK_UP_EVT:
+ bdcpy(bd_addr.address, p_data->link_up.bd_addr);
+ BTIF_TRACE_DEBUG0("BTA_DM_LINK_UP_EVT. Sending BT_ACL_STATE_CONNECTED");
+ HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
+ &bd_addr, BT_ACL_STATE_CONNECTED);
+ break;
+
+ case BTA_DM_LINK_DOWN_EVT:
+ bdcpy(bd_addr.address, p_data->link_down.bd_addr);
+ BTIF_TRACE_DEBUG0("BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
+ HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
+ &bd_addr, BT_ACL_STATE_DISCONNECTED);
+ break;
+
+ case BTA_DM_HW_ERROR_EVT:
+ BTIF_TRACE_ERROR0("Received H/W Error. ");
+ /* Flush storage data */
+ btif_config_flush();
+ usleep(100000); /* 100milliseconds */
+ /* Killing the process to force a restart as part of fault tolerance */
+ kill(getpid(), SIGKILL);
+ break;
+
+ case BTA_DM_AUTHORIZE_EVT:
+ case BTA_DM_SIG_STRENGTH_EVT:
+ case BTA_DM_SP_RMT_OOB_EVT:
+ case BTA_DM_SP_KEYPRESS_EVT:
+ case BTA_DM_ROLE_CHG_EVT:
+ case BTA_DM_BLE_KEY_EVT:
+ case BTA_DM_BLE_SEC_REQ_EVT:
+ case BTA_DM_BLE_PASSKEY_NOTIF_EVT:
+ case BTA_DM_BLE_PASSKEY_REQ_EVT:
+ case BTA_DM_BLE_OOB_REQ_EVT:
+ case BTA_DM_BLE_LOCAL_IR_EVT:
+ case BTA_DM_BLE_LOCAL_ER_EVT:
+ case BTA_DM_BLE_AUTH_CMPL_EVT:
+ default:
+ BTIF_TRACE_WARNING1( "btif_dm_cback : unhandled event (%d)", event );
+ break;
+ }
+} /* btui_security_cback() */
+
+
+/*******************************************************************************
+**
+** Function btif_dm_generic_evt
+**
+** Description Executes non-BTA upstream events in BTIF context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_dm_generic_evt(UINT16 event, char* p_param)
+{
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ switch(event)
+ {
+ case BTIF_DM_CB_DISCOVERY_STARTED:
+ {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STARTED);
+ }
+ break;
+
+ case BTIF_DM_CB_CREATE_BOND:
+ {
+ btif_dm_cb_create_bond((bt_bdaddr_t *)p_param);
+ }
+ break;
+
+ case BTIF_DM_CB_REMOVE_BOND:
+ {
+ btif_dm_cb_remove_bond((bt_bdaddr_t *)p_param);
+ }
+ break;
+
+ case BTIF_DM_CB_HID_REMOTE_NAME:
+ {
+ btif_dm_cb_hid_remote_name((tBTM_REMOTE_DEV_NAME *)p_param);
+ }
+ break;
+
+ case BTIF_DM_CB_BOND_STATE_BONDING:
+ {
+ bond_state_changed(BT_STATUS_SUCCESS, (bt_bdaddr_t *)p_param, BT_BOND_STATE_BONDING);
+ }
+ break;
+ default:
+ {
+ BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bte_dm_evt
+**
+** Description Switches context from BTE to BTIF for all DM events
+**
+** Returns void
+**
+*******************************************************************************/
+
+void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data)
+{
+ bt_status_t status;
+
+ /* switch context to btif task context (copy full union size for convenience) */
+ status = btif_transfer_context(btif_dm_upstreams_evt, (uint16_t)event, (void*)p_data, sizeof(tBTA_DM_SEC), NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+**
+** Function bte_search_devices_evt
+**
+** Description Switches context from BTE to BTIF for DM search events
+**
+** Returns void
+**
+*******************************************************************************/
+static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
+{
+ UINT16 param_len = 0;
+
+ if (p_data)
+ param_len += sizeof(tBTA_DM_SEARCH);
+ /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
+ switch (event)
+ {
+ case BTA_DM_INQ_RES_EVT:
+ {
+ if (p_data->inq_res.p_eir)
+ param_len += HCI_EXT_INQ_RESPONSE_LEN;
+ }
+ break;
+
+ case BTA_DM_DISC_RES_EVT:
+ {
+ if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data)
+ param_len += p_data->disc_res.raw_data_size;
+ }
+ break;
+ }
+ BTIF_TRACE_DEBUG3("%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);
+
+ /* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
+ if (event == BTA_DM_INQ_RES_EVT)
+ p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
+
+ btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
+ (param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
+}
+
+/*******************************************************************************
+**
+** Function bte_dm_search_services_evt
+**
+** Description Switches context from BTE to BTIF for DM search services
+** event
+**
+** Returns void
+**
+*******************************************************************************/
+static void bte_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
+{
+ UINT16 param_len = 0;
+ if (p_data)
+ param_len += sizeof(tBTA_DM_SEARCH);
+ switch (event)
+ {
+ case BTA_DM_DISC_RES_EVT:
+ {
+ if ((p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0)) {
+ param_len += (p_data->disc_res.num_uuids * MAX_UUID_SIZE);
+ }
+ } break;
+ }
+ /* TODO: The only other member that needs a deep copy is the p_raw_data. But not sure
+ * if raw_data is needed. */
+ btif_transfer_context(btif_dm_search_services_evt, event, (char*)p_data, param_len,
+ (param_len > sizeof(tBTA_DM_SEARCH)) ? search_services_copy_cb : NULL);
+}
+
+/*******************************************************************************
+**
+** Function bte_dm_remote_service_record_evt
+**
+** Description Switches context from BTE to BTIF for DM search service
+** record event
+**
+** Returns void
+**
+*******************************************************************************/
+static void bte_dm_remote_service_record_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
+{
+ /* TODO: The only member that needs a deep copy is the p_raw_data. But not sure yet if this is needed. */
+ btif_transfer_context(btif_dm_remote_service_record_evt, event, (char*)p_data, sizeof(tBTA_DM_SEARCH), NULL);
+}
+
+/*****************************************************************************
+**
+** btif api functions (no context switch)
+**
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function btif_dm_start_discovery
+**
+** Description Start device discovery/inquiry
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_start_discovery(void)
+{
+ tBTA_DM_INQ inq_params;
+ tBTA_SERVICE_MASK services = 0;
+
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ /* TODO: Do we need to handle multiple inquiries at the same time? */
+
+ /* Set inquiry params and call API */
+#if (BLE_INCLUDED == TRUE)
+ inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;
+#else
+ inq_params.mode = BTA_DM_GENERAL_INQUIRY;
+#endif
+ inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
+
+ inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
+ inq_params.report_dup = TRUE;
+
+ inq_params.filter_type = BTA_DM_INQ_CLR;
+ /* TODO: Filter device by BDA needs to be implemented here */
+
+ /* Will be enabled to TRUE once inquiry busy level has been received */
+ btif_dm_inquiry_in_progress = FALSE;
+ /* find nearby devices */
+ BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_cancel_discovery
+**
+** Description Cancels search
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_cancel_discovery(void)
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ BTA_DmSearchCancel();
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_create_bond
+**
+** Description Initiate bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr)
+{
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: bd_addr=%s", __FUNCTION__, bd2str((bt_bdaddr_t *) bd_addr, &bdstr));
+ if (pairing_cb.state != BT_BOND_STATE_NONE)
+ return BT_STATUS_BUSY;
+
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_CREATE_BOND,
+ (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_cancel_bond
+**
+** Description Initiate bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t *bd_addr)
+{
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: bd_addr=%s", __FUNCTION__, bd2str((bt_bdaddr_t *)bd_addr, &bdstr));
+
+ /* TODO:
+ ** 1. Restore scan modes
+ ** 2. special handling for HID devices
+ */
+ if (pairing_cb.state == BT_BOND_STATE_BONDING)
+ {
+ if (pairing_cb.is_ssp)
+ {
+ BTA_DmConfirm( (UINT8 *)bd_addr->address, FALSE);
+ }
+ else
+ {
+ BTA_DmPinReply( (UINT8 *)bd_addr->address, FALSE, 0, NULL);
+ }
+ /* Cancel bonding, in case it is in ACL connection setup state */
+ BTA_DmBondCancel ((UINT8 *)bd_addr->address);
+ btif_storage_remove_bonded_device((bt_bdaddr_t *)bd_addr);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_remove_bond
+**
+** Description Removes bonding with the specified device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_remove_bond(const bt_bdaddr_t *bd_addr)
+{
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: bd_addr=%s", __FUNCTION__, bd2str((bt_bdaddr_t *)bd_addr, &bdstr));
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_REMOVE_BOND,
+ (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_pin_reply
+**
+** Description BT legacy pairing - PIN code reply
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_pin_reply( const bt_bdaddr_t *bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t *pin_code)
+{
+ BTIF_TRACE_EVENT2("%s: accept=%d", __FUNCTION__, accept);
+
+ BTA_DmPinReply( (UINT8 *)bd_addr->address, accept, pin_len, pin_code->pin);
+
+ if (accept)
+ pairing_cb.pin_code_len = pin_len;
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_ssp_reply
+**
+** Description BT SSP Reply - Just Works, Numeric Comparison & Passkey Entry
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+bt_status_t btif_dm_ssp_reply(const bt_bdaddr_t *bd_addr,
+ bt_ssp_variant_t variant, uint8_t accept,
+ uint32_t passkey)
+{
+ if (variant == BT_SSP_VARIANT_PASSKEY_ENTRY)
+ {
+ /* This is not implemented in the stack.
+ * For devices with display, this is not needed
+ */
+ BTIF_TRACE_WARNING1("%s: Not implemented", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ /* BT_SSP_VARIANT_CONSENT & BT_SSP_VARIANT_PASSKEY_CONFIRMATION supported */
+ BTIF_TRACE_EVENT2("%s: accept=%d", __FUNCTION__, accept);
+ BTA_DmConfirm( (UINT8 *)bd_addr->address, accept);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_adapter_property
+**
+** Description Queries the BTA for the adapter property
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_get_adapter_property(bt_property_t *prop)
+{
+ bt_status_t status;
+
+ BTIF_TRACE_EVENT2("%s: type=0x%x", __FUNCTION__, prop->type);
+ switch (prop->type)
+ {
+ case BT_PROPERTY_BDNAME:
+ {
+ bt_bdname_t *bd_name = (bt_bdname_t*)prop->val;
+ strcpy((char *)bd_name->name, (char *)BTM_DEF_LOCAL_NAME);
+ prop->len = strlen((char *)bd_name->name);
+ }
+ break;
+
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ {
+ /* if the storage does not have it. Most likely app never set it. Default is NONE */
+ bt_scan_mode_t *mode = (bt_scan_mode_t*)prop->val;
+ *mode = BT_SCAN_MODE_NONE;
+ prop->len = sizeof(bt_scan_mode_t);
+ }
+ break;
+
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ {
+ uint32_t *tmt = (uint32_t*)prop->val;
+ *tmt = 120; /* default to 120s, if not found in NV */
+ prop->len = sizeof(uint32_t);
+ }
+ break;
+
+ default:
+ prop->len = 0;
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_remote_services
+**
+** Description Start SDP to get remote services
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_get_remote_services(bt_bdaddr_t *remote_addr)
+{
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: remote_addr=%s", __FUNCTION__, bd2str(remote_addr, &bdstr));
+
+ BTA_DmDiscover(remote_addr->address, BTA_ALL_SERVICE_MASK,
+ bte_dm_search_services_evt, TRUE);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_dm_get_remote_service_record
+**
+** Description Start SDP to get remote service record
+**
+**
+** Returns bt_status_t
+*******************************************************************************/
+bt_status_t btif_dm_get_remote_service_record(bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid)
+{
+ tSDP_UUID sdp_uuid;
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT2("%s: remote_addr=%s", __FUNCTION__, bd2str(remote_addr, &bdstr));
+
+ sdp_uuid.len = MAX_UUID_SIZE;
+ memcpy(sdp_uuid.uu.uuid128, uuid->uu, MAX_UUID_SIZE);
+
+ BTA_DmDiscoverUUID(remote_addr->address, &sdp_uuid,
+ bte_dm_remote_service_record_evt, TRUE);
+
+ return BT_STATUS_SUCCESS;
+}
+
+void btif_dm_execute_service_request(UINT16 event, char *p_param)
+{
+ BOOLEAN b_enable = FALSE;
+ bt_status_t status;
+ if (event == BTIF_DM_ENABLE_SERVICE)
+ {
+ b_enable = TRUE;
+ }
+ status = btif_in_execute_service_request(*((tBTA_SERVICE_ID*)p_param), b_enable);
+ if (status == BT_STATUS_SUCCESS)
+ {
+ bt_property_t property;
+ bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+
+ /* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
+ BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
+ sizeof(local_uuids), local_uuids);
+ btif_storage_get_adapter_property(&property);
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb,
+ BT_STATUS_SUCCESS, 1, &property);
+ }
+ return;
+}
+
+#if (BTM_OOB_INCLUDED == TRUE)
+void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA *p_oob_data)
+{
+ if (oob_cb.sp_c[0] == 0 && oob_cb.sp_c[1] == 0 &&
+ oob_cb.sp_c[2] == 0 && oob_cb.sp_c[3] == 0 )
+ {
+ *p_oob_data = FALSE;
+ }
+ else
+ {
+ *p_oob_data = TRUE;
+ }
+ BTIF_TRACE_DEBUG1("btif_dm_set_oob_for_io_req *p_oob_data=%d", *p_oob_data);
+}
+#endif /* BTM_OOB_INCLUDED */
+
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void)
+{
+ char prop_oob[32];
+ property_get("service.brcm.bt.oob", prop_oob, "3");
+ BTIF_TRACE_DEBUG1("btif_dm_load_local_oob prop_oob = %s",prop_oob);
+ if (prop_oob[0] != '3')
+ {
+#if (BTM_OOB_INCLUDED == TRUE)
+ if (oob_cb.sp_c[0] == 0 && oob_cb.sp_c[1] == 0 &&
+ oob_cb.sp_c[2] == 0 && oob_cb.sp_c[3] == 0 )
+ {
+ BTIF_TRACE_DEBUG0("btif_dm_load_local_oob: read OOB, call BTA_DmLocalOob()");
+ BTA_DmLocalOob();
+ }
+#else
+ BTIF_TRACE_ERROR0("BTM_OOB_INCLUDED is FALSE!!(btif_dm_load_local_oob)");
+#endif
+ }
+}
+
+void btif_dm_proc_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r)
+{
+ FILE *fp;
+ char *path_a = "/data/misc/bluedroid/LOCAL/a.key";
+ char *path_b = "/data/misc/bluedroid/LOCAL/b.key";
+ char *path = NULL;
+ char prop_oob[32];
+ BTIF_TRACE_DEBUG1("btif_dm_proc_loc_oob: valid=%d", valid);
+ if (oob_cb.sp_c[0] == 0 && oob_cb.sp_c[1] == 0 &&
+ oob_cb.sp_c[2] == 0 && oob_cb.sp_c[3] == 0 &&
+ valid)
+ {
+ BTIF_TRACE_DEBUG0("save local OOB data in memory");
+ memcpy(oob_cb.sp_c, c, BT_OCTET16_LEN);
+ memcpy(oob_cb.sp_r, r, BT_OCTET16_LEN);
+ property_get("service.brcm.bt.oob", prop_oob, "3");
+ BTIF_TRACE_DEBUG1("btif_dm_proc_loc_oob prop_oob = %s",prop_oob);
+ if (prop_oob[0] == '1')
+ path = path_a;
+ else if (prop_oob[0] == '2')
+ path = path_b;
+ if (path)
+ {
+ fp = fopen(path, "wb+");
+ if (fp == NULL)
+ {
+ BTIF_TRACE_DEBUG1("btif_dm_proc_loc_oob: failed to save local OOB data to %s", path);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG1("btif_dm_proc_loc_oob: save local OOB data into file %s",path);
+ fwrite (c , 1 , BT_OCTET16_LEN , fp );
+ fwrite (r , 1 , BT_OCTET16_LEN , fp );
+ fclose(fp);
+ }
+ }
+ }
+}
+BOOLEAN btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r)
+{
+ char t[128];
+ FILE *fp;
+ char *path_a = "/data/misc/bluedroid/LOCAL/a.key";
+ char *path_b = "/data/misc/bluedroid/LOCAL/b.key";
+ char *path = NULL;
+ char prop_oob[32];
+ BOOLEAN result = FALSE;
+ bt_bdaddr_t bt_bd_addr;
+ bdcpy(oob_cb.oob_bdaddr, bd_addr);
+ property_get("service.brcm.bt.oob", prop_oob, "3");
+ BTIF_TRACE_DEBUG1("btif_dm_proc_rmt_oob prop_oob = %s",prop_oob);
+ if (prop_oob[0] == '1')
+ path = path_b;
+ else if (prop_oob[0] == '2')
+ path = path_a;
+ if (path)
+ {
+ fp = fopen(path, "rb");
+ if (fp == NULL)
+ {
+ BTIF_TRACE_DEBUG1("btapp_dm_rmt_oob_reply: failed to read OOB keys from %s",path);
+ return FALSE;
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG1("btif_dm_proc_rmt_oob: read OOB data from %s",path);
+ fread (p_c , 1 , BT_OCTET16_LEN , fp );
+ fread (p_r , 1 , BT_OCTET16_LEN , fp );
+ fclose(fp);
+ }
+ BTIF_TRACE_DEBUG0("----btif_dm_proc_rmt_oob: TRUE");
+ sprintf(t, "%02x:%02x:%02x:%02x:%02x:%02x",
+ oob_cb.oob_bdaddr[0], oob_cb.oob_bdaddr[1], oob_cb.oob_bdaddr[2],
+ oob_cb.oob_bdaddr[3], oob_cb.oob_bdaddr[4], oob_cb.oob_bdaddr[5]);
+ BTIF_TRACE_DEBUG1("----btif_dm_proc_rmt_oob: peer_bdaddr = %s", t);
+ sprintf(t, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ p_c[0], p_c[1], p_c[2], p_c[3], p_c[4], p_c[5], p_c[6], p_c[7],
+ p_c[8], p_c[9], p_c[10], p_c[11], p_c[12], p_c[13], p_c[14], p_c[15]);
+ BTIF_TRACE_DEBUG1("----btif_dm_proc_rmt_oob: c = %s",t);
+ sprintf(t, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ p_r[0], p_r[1], p_r[2], p_r[3], p_r[4], p_r[5], p_r[6], p_r[7],
+ p_r[8], p_r[9], p_r[10], p_r[11], p_r[12], p_r[13], p_r[14], p_r[15]);
+ BTIF_TRACE_DEBUG1("----btif_dm_proc_rmt_oob: r = %s",t);
+ bdcpy(bt_bd_addr.address, bd_addr);
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_BOND_STATE_BONDING,
+ (char *)&bt_bd_addr, sizeof(bt_bdaddr_t), NULL);
+ result = TRUE;
+ }
+ BTIF_TRACE_DEBUG1("btif_dm_proc_rmt_oob result=%d",result);
+ return result;
+}
+#endif /* BTIF_DM_OOB_TEST */
+
+void btif_dm_on_disable()
+{
+ /* cancel any pending pairing requests */
+ if (pairing_cb.state == BT_BOND_STATE_BONDING)
+ {
+ bt_bdaddr_t bd_addr;
+
+ BTIF_TRACE_DEBUG1("%s: Cancel pending pairing request", __FUNCTION__);
+ bdcpy(bd_addr.address, pairing_cb.bd_addr);
+ btif_dm_cancel_bond(&bd_addr);
+ }
+}
diff --git a/btif/src/btif_hf.c b/btif/src/btif_hf.c
new file mode 100755
index 0000000..7ce22b1
--- /dev/null
+++ b/btif/src/btif_hf.c
@@ -0,0 +1,1200 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <stdlib.h>
+
+#define LOG_TAG "BTIF_HF"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btif_profile_queue.h"
+
+#include "bd.h"
+#include "bta_ag_api.h"
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+#ifndef BTIF_HSAG_SERVICE_NAME
+#define BTIF_HSAG_SERVICE_NAME ("Headset Gateway")
+#endif
+
+#ifndef BTIF_HFAG_SERVICE_NAME
+#define BTIF_HFAG_SERVICE_NAME ("Handsfree Gateway")
+#endif
+
+#ifndef BTIF_HF_SERVICES
+#define BTIF_HF_SERVICES (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK )
+#endif
+
+#ifndef BTIF_HF_SERVICE_NAMES
+#define BTIF_HF_SERVICE_NAMES {BTIF_HSAG_SERVICE_NAME , BTIF_HFAG_SERVICE_NAME}
+#endif
+
+#ifndef BTIF_HF_SECURITY
+#define BTIF_HF_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTIF_HF_FEATURES
+#define BTIF_HF_FEATURES ( BTA_AG_FEAT_3WAY | \
+ BTA_AG_FEAT_ECNR | \
+ BTA_AG_FEAT_REJECT | \
+ BTA_AG_FEAT_ECS | \
+ BTA_AG_FEAT_EXTERR | \
+ BTA_AG_FEAT_BTRH | \
+ BTA_AG_FEAT_VREC | \
+ BTA_AG_FEAT_UNAT)
+#endif
+
+#define BTIF_HF_ID_1 0
+
+#define BTIF_HF_CALL_END_TIMEOUT 6
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+static bthf_callbacks_t *bt_hf_callbacks = NULL;
+
+#define CHECK_BTHF_INIT() if (bt_hf_callbacks == NULL)\
+ {\
+ BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+ }\
+ else\
+ {\
+ BTIF_TRACE_EVENT1("BTHF: %s", __FUNCTION__);\
+ }
+
+#define CHECK_BTHF_SLC_CONNECTED() if (bt_hf_callbacks == NULL)\
+ {\
+ BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+ }\
+ else if (btif_hf_cb.state != BTHF_CONNECTION_STATE_SLC_CONNECTED)\
+ {\
+ BTIF_TRACE_WARNING2("BTHF: %s: SLC connection not up. state=%s", __FUNCTION__, dump_hf_conn_state(btif_hf_cb.state));\
+ return BT_STATUS_NOT_READY;\
+ }\
+ else\
+ {\
+ BTIF_TRACE_EVENT1("BTHF: %s", __FUNCTION__);\
+ }
+
+/* BTIF-HF control block to map bdaddr to BTA handle */
+typedef struct _btif_hf_cb
+{
+ UINT16 handle;
+ bt_bdaddr_t connected_bda;
+ bthf_connection_state_t state;
+ bthf_vr_state_t vr_state;
+ tBTA_AG_PEER_FEAT peer_feat;
+ int num_active;
+ int num_held;
+ struct timespec call_end_timestamp;
+ bthf_call_state_t call_setup_state;
+} btif_hf_cb_t;
+
+static btif_hf_cb_t btif_hf_cb;
+
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*******************************************************************************
+**
+** Function is_connected
+**
+** Description Internal function to check if HF is connected
+**
+** Returns TRUE if connected
+**
+*******************************************************************************/
+static BOOLEAN is_connected(bt_bdaddr_t *bd_addr)
+{
+ if (((btif_hf_cb.state == BTHF_CONNECTION_STATE_CONNECTED) || (btif_hf_cb.state == BTHF_CONNECTION_STATE_SLC_CONNECTED))&&
+ ((bd_addr == NULL) || (bdcmp(bd_addr->address, btif_hf_cb.connected_bda.address) == 0)))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function callstate_to_callsetup
+**
+** Description Converts HAL call state to BTA call setup indicator value
+**
+** Returns BTA call indicator value
+**
+*******************************************************************************/
+static UINT8 callstate_to_callsetup(bthf_call_state_t call_state)
+{
+ UINT8 call_setup = 0;
+ if (call_state == BTHF_CALL_STATE_INCOMING)
+ call_setup = 1;
+ if (call_state == BTHF_CALL_STATE_DIALING)
+ call_setup = 2;
+ if (call_state == BTHF_CALL_STATE_ALERTING)
+ call_setup = 3;
+
+ return call_setup;
+}
+
+/*******************************************************************************
+**
+** Function send_at_result
+**
+** Description Send AT result code (OK/ERROR)
+**
+** Returns void
+**
+*******************************************************************************/
+static void send_at_result(UINT8 ok_flag, UINT16 errcode)
+{
+ tBTA_AG_RES_DATA ag_res;
+ memset (&ag_res, 0, sizeof (ag_res));
+
+ ag_res.ok_flag = ok_flag;
+ if (ok_flag == BTA_AG_OK_ERROR)
+ {
+ ag_res.errcode = errcode;
+ }
+
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+}
+
+/*******************************************************************************
+**
+** Function send_indicator_update
+**
+** Description Send indicator update (CIEV)
+**
+** Returns void
+**
+*******************************************************************************/
+static void send_indicator_update (UINT16 indicator, UINT16 value)
+{
+ tBTA_AG_RES_DATA ag_res;
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ ag_res.ind.id = indicator;
+ ag_res.ind.value = value;
+
+ BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
+}
+
+void clear_phone_state()
+{
+ btif_hf_cb.call_setup_state = BTHF_CALL_STATE_IDLE;
+ btif_hf_cb.num_active = btif_hf_cb.num_held = 0;
+}
+
+
+/*****************************************************************************
+** Section name (Group of functions)
+*****************************************************************************/
+
+/*****************************************************************************
+**
+** btif hf api functions (no context switch)
+**
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function btif_hf_upstreams_evt
+**
+** Description Executes HF UPSTREAMS events in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hf_upstreams_evt(UINT16 event, char* p_param)
+{
+ tBTA_AG *p_data = (tBTA_AG *)p_param;
+ bdstr_t bdstr;
+
+ BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_hf_event(event));
+
+ switch (event)
+ {
+ case BTA_AG_ENABLE_EVT:
+ case BTA_AG_DISABLE_EVT:
+ break;
+
+ case BTA_AG_REGISTER_EVT:
+ btif_hf_cb.handle = p_data->reg.hdr.handle;
+ break;
+
+ case BTA_AG_OPEN_EVT:
+ if (p_data->open.status == BTA_AG_SUCCESS)
+ {
+ bdcpy(btif_hf_cb.connected_bda.address, p_data->open.bd_addr);
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_CONNECTED;
+ btif_hf_cb.peer_feat = 0;
+ clear_phone_state();
+ }
+ else if (btif_hf_cb.state == BTHF_CONNECTION_STATE_CONNECTING)
+ {
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_DISCONNECTED;
+ }
+ else
+ {
+ BTIF_TRACE_WARNING4("%s: AG open failed, but another device connected. status=%d state=%d connected device=%s",
+ __FUNCTION__, p_data->open.status, btif_hf_cb.state, bd2str(&btif_hf_cb.connected_bda, &bdstr));
+ break;
+ }
+
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state, &btif_hf_cb.connected_bda);
+
+ if (btif_hf_cb.state == BTHF_CONNECTION_STATE_DISCONNECTED)
+ bdsetany(btif_hf_cb.connected_bda.address);
+
+ if (p_data->open.status != BTA_AG_SUCCESS)
+ btif_queue_advance();
+ break;
+
+ case BTA_AG_CLOSE_EVT:
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_DISCONNECTED;
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state, &btif_hf_cb.connected_bda);
+ bdsetany(btif_hf_cb.connected_bda.address);
+ btif_hf_cb.peer_feat = 0;
+ clear_phone_state();
+ /* If AG_OPEN was received but SLC was not setup in a specified time (10 seconds),
+ ** then AG_CLOSE may be received. We need to advance the queue here
+ */
+ btif_queue_advance();
+ break;
+
+ case BTA_AG_CONN_EVT:
+ btif_hf_cb.peer_feat = p_data->conn.peer_feat;
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_SLC_CONNECTED;
+
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb.state,
+ &btif_hf_cb.connected_bda);
+ btif_queue_advance();
+ break;
+
+ case BTA_AG_AUDIO_OPEN_EVT:
+ HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED, &btif_hf_cb.connected_bda);
+ break;
+
+ case BTA_AG_AUDIO_CLOSE_EVT:
+ HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED, &btif_hf_cb.connected_bda);
+ break;
+
+ /* BTA auto-responds, silently discard */
+ case BTA_AG_SPK_EVT:
+ case BTA_AG_MIC_EVT:
+ HAL_CBACK(bt_hf_callbacks, volume_cmd_cb,
+ (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK : BTHF_VOLUME_TYPE_MIC, p_data->val.num);
+ break;
+
+ case BTA_AG_AT_A_EVT:
+ HAL_CBACK(bt_hf_callbacks, answer_call_cmd_cb);
+ break;
+
+ /* Java needs to send OK/ERROR for these commands */
+ case BTA_AG_AT_BLDN_EVT:
+ case BTA_AG_AT_D_EVT:
+ HAL_CBACK(bt_hf_callbacks, dial_call_cmd_cb,
+ (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL);
+ break;
+
+ case BTA_AG_AT_CHUP_EVT:
+ HAL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb);
+ break;
+
+ case BTA_AG_AT_CIND_EVT:
+ HAL_CBACK(bt_hf_callbacks, cind_cmd_cb);
+ break;
+
+ case BTA_AG_AT_VTS_EVT:
+ HAL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0]);
+ break;
+
+ case BTA_AG_AT_BVRA_EVT:
+ HAL_CBACK(bt_hf_callbacks, vr_cmd_cb,
+ (p_data->val.num == 1) ? BTHF_VR_STATE_STARTED : BTHF_VR_STATE_STOPPED);
+ break;
+
+ case BTA_AG_AT_NREC_EVT:
+ HAL_CBACK(bt_hf_callbacks, nrec_cmd_cb,
+ (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP);
+ break;
+
+ /* TODO: Add a callback for CBC */
+ case BTA_AG_AT_CBC_EVT:
+ break;
+
+ case BTA_AG_AT_CKPD_EVT:
+ HAL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb);
+ break;
+
+ /* Java needs to send OK/ERROR for these commands */
+ case BTA_AG_AT_CHLD_EVT:
+ HAL_CBACK(bt_hf_callbacks, chld_cmd_cb, atoi(p_data->val.str));
+ break;
+
+ case BTA_AG_AT_CLCC_EVT:
+ HAL_CBACK(bt_hf_callbacks, clcc_cmd_cb, p_data->val.num);
+ break;
+
+ case BTA_AG_AT_COPS_EVT:
+ HAL_CBACK(bt_hf_callbacks, cops_cmd_cb);
+ break;
+
+ case BTA_AG_AT_UNAT_EVT:
+ HAL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb,
+ p_data->val.str);
+ break;
+
+ case BTA_AG_AT_CNUM_EVT:
+ HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb);
+ break;
+
+ /* TODO: Some of these commands may need to be sent to app. For now respond with error */
+ case BTA_AG_AT_BINP_EVT:
+ case BTA_AG_AT_BTRH_EVT:
+ send_at_result(BTA_AG_OK_ERROR, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ break;
+
+
+ default:
+ BTIF_TRACE_WARNING2("%s: Unhandled event: %d", __FUNCTION__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bte_hf_evt
+**
+** Description Switches context from BTE to BTIF for all HF events
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG *p_data)
+{
+ bt_status_t status;
+ int param_len = 0;
+
+ /* TODO: BTA sends the union members and not tBTA_AG. If using param_len=sizeof(tBTA_AG), we get a crash on memcpy */
+ if (BTA_AG_REGISTER_EVT == event)
+ param_len = sizeof(tBTA_AG_REGISTER);
+ else if (BTA_AG_OPEN_EVT == event)
+ param_len = sizeof(tBTA_AG_OPEN);
+ else if (BTA_AG_CONN_EVT == event)
+ param_len = sizeof(tBTA_AG_CONN);
+ else if ( (BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event))
+ param_len = sizeof(tBTA_AG_HDR);
+ else if (p_data)
+ param_len = sizeof(tBTA_AG_VAL);
+
+ /* switch context to btif task context (copy full union size for convenience) */
+ status = btif_transfer_context(btif_hf_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+
+/*******************************************************************************
+**
+** Function btif_in_hf_generic_evt
+**
+** Description Processes generic events to be sent to JNI that are not triggered from the BTA.
+** Always runs in BTIF context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_in_hf_generic_evt(UINT16 event, char *p_param)
+{
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ switch (event) {
+ case BTIF_HFP_CB_AUDIO_CONNECTING:
+ {
+ HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTING,
+ &btif_hf_cb.connected_bda);
+ } break;
+ default:
+ {
+ BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
+ }
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hf_init
+**
+** Description initializes the hf interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init( bthf_callbacks_t* callbacks )
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ bt_hf_callbacks = callbacks;
+
+ /* Invoke the enable service API to the core to set the appropriate service_id
+ * Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled (phone)
+ * othwerwise only HSP is enabled (tablet)
+ */
+#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+ btif_enable_service(BTA_HFP_SERVICE_ID);
+#else
+ btif_enable_service(BTA_HSP_SERVICE_ID);
+#endif
+
+ memset(&btif_hf_cb, 0, sizeof(btif_hf_cb_t));
+ clear_phone_state();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function connect
+**
+** Description connect to headset
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_int( bt_bdaddr_t *bd_addr )
+{
+ if (!is_connected(bd_addr))
+ {
+ btif_hf_cb.state = BTHF_CONNECTION_STATE_CONNECTING;
+ bdcpy(btif_hf_cb.connected_bda.address, bd_addr->address);
+
+ BTA_AgOpen(btif_hf_cb.handle, btif_hf_cb.connected_bda.address,
+ BTIF_HF_SECURITY, BTIF_HF_SERVICES);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_BUSY;
+}
+
+static bt_status_t connect( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHF_INIT();
+ return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+**
+** Function disconnect
+**
+** Description disconnect from headset
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(bd_addr))
+ {
+ BTA_AgClose(btif_hf_cb.handle);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function connect_audio
+**
+** Description create an audio connection
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(bd_addr))
+ {
+ BTA_AgAudioOpen(btif_hf_cb.handle);
+
+ /* Inform the application that the audio connection has been initiated successfully */
+ btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,
+ (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function disconnect_audio
+**
+** Description close the audio connection
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect_audio( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(bd_addr))
+ {
+ BTA_AgAudioClose(btif_hf_cb.handle);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function start_voice_recognition
+**
+** Description start voice recognition
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t start_voice_recognition()
+{
+ CHECK_BTHF_INIT();
+ if (is_connected(NULL))
+ {
+ if (btif_hf_cb.peer_feat & BTA_AG_PEER_FEAT_VREC)
+ {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.state = 1;
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_BVRA_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ return BT_STATUS_UNSUPPORTED;
+ }
+ }
+
+ return BT_STATUS_NOT_READY;
+}
+
+/*******************************************************************************
+**
+** Function stop_voice_recognition
+**
+** Description stop voice recognition
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t stop_voice_recognition()
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ if (btif_hf_cb.peer_feat & BTA_AG_PEER_FEAT_VREC)
+ {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.state = 0;
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_BVRA_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ return BT_STATUS_UNSUPPORTED;
+ }
+ }
+
+ return BT_STATUS_NOT_READY;
+}
+
+/*******************************************************************************
+**
+** Function volume_control
+**
+** Description volume control
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t volume_control(bthf_volume_type_t type, int volume)
+{
+ CHECK_BTHF_INIT();
+
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ if (is_connected(NULL))
+ {
+ ag_res.num = volume;
+ BTA_AgResult(btif_hf_cb.handle,
+ (type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
+ &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function device_status_notification
+**
+** Description Combined device status change notification
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t device_status_notification(bthf_network_state_t ntk_state,
+ bthf_service_type_t svc_type, int signal, int batt_chg)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ /* send all indicators to BTA.
+ ** BTA will make sure no duplicates are sent out
+ */
+ send_indicator_update(BTA_AG_IND_SERVICE,
+ (ntk_state == BTHF_NETWORK_STATE_AVAILABLE) ? 1 : 0);
+ send_indicator_update(BTA_AG_IND_ROAM,
+ (svc_type == BTHF_SERVICE_TYPE_HOME) ? 0 : 1);
+ send_indicator_update(BTA_AG_IND_SIGNAL, signal);
+ send_indicator_update(BTA_AG_IND_BATTCHG, batt_chg);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function cops_response
+**
+** Description Response for COPS command
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t cops_response(const char *cops)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ tBTA_AG_RES_DATA ag_res;
+
+ /* Format the response */
+ sprintf (ag_res.str, "0,0,\"%s\"", cops);
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_COPS_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function cind_response
+**
+** Description Response for CIND command
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t cind_response(int svc, int num_active, int num_held,
+ bthf_call_state_t call_setup_state,
+ int signal, int roam, int batt_chg)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ tBTA_AG_RES_DATA ag_res;
+
+ memset (&ag_res, 0, sizeof (ag_res));
+ /* per the errata 2043, call=1 implies atleast one call is in progress (active/held)
+ ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+ **/
+ sprintf (ag_res.str, "%d,%d,%d,%d,%d,%d,%d",
+ (num_active + num_held) ? 1 : 0, /* Call state */
+ callstate_to_callsetup(call_setup_state), /* Callsetup state */
+ svc, /* network service */
+ signal, /* Signal strength */
+ roam, /* Roaming indicator */
+ batt_chg, /* Battery level */
+ ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1))); /* Call held */
+
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_CIND_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function formatted_at_response
+**
+** Description Pre-formatted AT response, typically in response to unknown AT cmd
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t formatted_at_response(const char *rsp)
+{
+ CHECK_BTHF_INIT();
+ tBTA_AG_RES_DATA ag_res;
+
+ if (is_connected(NULL))
+ {
+ /* Format the response and send */
+ memset (&ag_res, 0, sizeof (ag_res));
+ strncpy(ag_res.str, rsp, BTA_AG_AT_MAX_LEN);
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function at_response
+**
+** Description ok/error response
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t at_response(bthf_at_response_t response_code, int error_code)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
+ : BTA_AG_OK_ERROR, error_code);
+ return BT_STATUS_SUCCESS;
+ }
+
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function clcc_response
+**
+** Description response for CLCC command
+** Can be iteratively called for each call index. Call index
+** of 0 will be treated as NULL termination (Completes response)
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
+ bthf_call_state_t state, bthf_call_mode_t mode,
+ bthf_call_mpty_type_t mpty, const char *number,
+ bthf_call_addrtype_t type)
+{
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL))
+ {
+ tBTA_AG_RES_DATA ag_res;
+ int xx;
+
+ memset (&ag_res, 0, sizeof (ag_res));
+
+ /* Format the response */
+ if (index == 0)
+ {
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+ }
+ else
+ {
+ BTIF_TRACE_EVENT6("clcc_response: [%d] dir %d state %d mode %d number = %s type = %d",
+ index, dir, state, mode, number, type);
+ xx = sprintf (ag_res.str, "%d,%d,%d,%d,%d",
+ index, dir, state, mode, mpty);
+
+ if (number)
+ {
+ if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
+ sprintf (&ag_res.str[xx], ",\"+%s\",%d", number, type);
+ else
+ sprintf (&ag_res.str[xx], ",\"%s\",%d", number, type);
+ }
+ }
+ BTA_AgResult (btif_hf_cb.handle, BTA_AG_CLCC_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function phone_state_change
+**
+** Description notify of a call state change
+** number & type: valid only for incoming & waiting call
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+
+static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_state_t call_setup_state,
+ const char *number, bthf_call_addrtype_t type)
+{
+ tBTA_AG_RES res = 0xff;
+ tBTA_AG_RES_DATA ag_res;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ BOOLEAN activeCallUpdated = FALSE;
+
+ CHECK_BTHF_SLC_CONNECTED();
+
+ BTIF_TRACE_DEBUG6("phone_state_change: num_active=%d [prev: %d] num_held=%d[prev: %d]"\
+ " call_setup=%s [prev: %s]", num_active, btif_hf_cb.num_active,
+ num_held, btif_hf_cb.num_held,
+ dump_hf_call_state(call_setup_state), dump_hf_call_state(btif_hf_cb.call_setup_state));
+
+ /* if all indicators are 0, send end call and return */
+ if (num_active == 0 && num_held == 0 && call_setup_state == BTHF_CALL_STATE_IDLE)
+ {
+ BTIF_TRACE_DEBUG1("%s: Phone on hook", __FUNCTION__);
+
+ /* record call termination timestamp if there was an active/held call or callsetup state > BTHF_CALL_STATE_IDLE */
+ if ((btif_hf_cb.call_setup_state != BTHF_CALL_STATE_IDLE ) || (btif_hf_cb.num_active) ||(btif_hf_cb.num_held))
+ {
+ BTIF_TRACE_DEBUG1("%s: Record call termination timestamp", __FUNCTION__);
+ clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb.call_end_timestamp);
+ }
+ BTA_AgResult (BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
+
+ /* if held call was present, reset that as well */
+ if (btif_hf_cb.num_held)
+ send_indicator_update(BTA_AG_IND_CALLHELD, 0);
+
+ goto update_call_states;
+ }
+
+ /* active state can change when:
+ ** 1. an outgoing/incoming call was answered
+ ** 2. an held was resumed
+ ** 3. without callsetup notifications, call became active
+ ** (3) can happen if call is active and a headset connects to us
+ **
+ ** In the case of (3), we will have to notify the stack of an active
+ ** call, instead of sending an indicator update. This will also
+ ** force the SCO to be setup. Handle this special case here prior to
+ ** call setup handling
+ */
+ if ( (num_active == 1) && (btif_hf_cb.num_active == 0) && (btif_hf_cb.num_held == 0) &&
+ (btif_hf_cb.call_setup_state == BTHF_CALL_STATE_IDLE) )
+ {
+ BTIF_TRACE_DEBUG1("%s: Active call notification received without call setup update",
+ __FUNCTION__);
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ ag_res.audio_handle = btif_hf_cb.handle;
+ res = BTA_AG_OUT_CALL_CONN_RES;
+ BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+ activeCallUpdated = TRUE;
+ }
+
+ /* Ringing call changed? */
+ if (call_setup_state != btif_hf_cb.call_setup_state)
+ {
+ BTIF_TRACE_DEBUG3("%s: Call setup states changed. old: %s new: %s",
+ __FUNCTION__, dump_hf_call_state(btif_hf_cb.call_setup_state),
+ dump_hf_call_state(call_setup_state));
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+ switch (call_setup_state)
+ {
+ case BTHF_CALL_STATE_IDLE:
+ {
+ switch (btif_hf_cb.call_setup_state)
+ {
+ case BTHF_CALL_STATE_INCOMING:
+ if (num_active > btif_hf_cb.num_active)
+ {
+ res = BTA_AG_IN_CALL_CONN_RES;
+ ag_res.audio_handle = btif_hf_cb.handle;
+ }
+ else if (num_held > btif_hf_cb.num_held)
+ res = BTA_AG_IN_CALL_HELD_RES;
+ else
+ res = BTA_AG_CALL_CANCEL_RES;
+ break;
+ case BTHF_CALL_STATE_DIALING:
+ case BTHF_CALL_STATE_ALERTING:
+ if (num_active > btif_hf_cb.num_active)
+ {
+ ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
+ res = BTA_AG_OUT_CALL_CONN_RES;
+ }
+ else
+ res = BTA_AG_CALL_CANCEL_RES;
+ break;
+ default:
+ BTIF_TRACE_ERROR1("%s: Incorrect Call setup state transition", __FUNCTION__);
+ status = BT_STATUS_PARM_INVALID;
+ break;
+ }
+ } break;
+
+ case BTHF_CALL_STATE_INCOMING:
+ if (num_active || num_held)
+ res = BTA_AG_CALL_WAIT_RES;
+ else
+ res = BTA_AG_IN_CALL_RES;
+ if (number)
+ {
+ int xx = 0;
+ if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
+ xx = sprintf (ag_res.str, "\"+%s\"", number);
+ else
+ xx = sprintf (ag_res.str, "\"%s\"", number);
+ ag_res.num = type;
+
+ if (res == BTA_AG_CALL_WAIT_RES)
+ sprintf(&ag_res.str[xx], ",%d", type);
+ }
+ break;
+ case BTHF_CALL_STATE_DIALING:
+ ag_res.audio_handle = btif_hf_cb.handle;
+ res = BTA_AG_OUT_CALL_ORIG_RES;
+ break;
+ case BTHF_CALL_STATE_ALERTING:
+ /* if we went from idle->alert, force SCO setup here. dialing usually triggers it */
+ if (btif_hf_cb.call_setup_state == BTHF_CALL_STATE_IDLE)
+ ag_res.audio_handle = btif_hf_cb.handle;
+ res = BTA_AG_OUT_CALL_ALERT_RES;
+ break;
+ default:
+ BTIF_TRACE_ERROR1("%s: Incorrect new ringing call state", __FUNCTION__);
+ status = BT_STATUS_PARM_INVALID;
+ break;
+ }
+ BTIF_TRACE_DEBUG3("%s: Call setup state changed. res=%d, audio_handle=%d", __FUNCTION__, res, ag_res.audio_handle);
+
+ if (res)
+ BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+
+ /* if call setup is idle, we have already updated call indicator, jump out */
+ if (call_setup_state == BTHF_CALL_STATE_IDLE)
+ {
+ /* check & update callheld */
+ if ((num_held > 0) && (num_active > 0))
+ send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+ goto update_call_states;
+ }
+ }
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+ /* per the errata 2043, call=1 implies atleast one call is in progress (active/held)
+ ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+ ** Handle call indicator change
+ **/
+ if (!activeCallUpdated && ((num_active + num_held) != (btif_hf_cb.num_active + btif_hf_cb.num_held)) )
+ {
+ BTIF_TRACE_DEBUG3("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.num_active, num_active);
+ send_indicator_update(BTA_AG_IND_CALL, ((num_active + num_held) > 0) ? 1 : 0);
+ }
+
+ /* Held Changed? */
+ if (num_held != btif_hf_cb.num_held)
+ {
+ BTIF_TRACE_DEBUG3("%s: Held call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb.num_held, num_held);
+ send_indicator_update(BTA_AG_IND_CALLHELD, ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
+ }
+
+ /* Calls Swapped? */
+ if ( (call_setup_state == btif_hf_cb.call_setup_state) &&
+ (num_active && num_held) &&
+ (num_active == btif_hf_cb.num_active) &&
+ (num_held == btif_hf_cb.num_held) )
+ {
+ BTIF_TRACE_DEBUG1("%s: Calls swapped", __FUNCTION__);
+ send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+ }
+
+update_call_states:
+ btif_hf_cb.num_active = num_active;
+ btif_hf_cb.num_held = num_held;
+ btif_hf_cb.call_setup_state = call_setup_state;
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hf_call_terminated_recently
+**
+** Description Checks if a call has been terminated
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+BOOLEAN btif_hf_call_terminated_recently()
+{
+ struct timespec now;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if (now.tv_sec < btif_hf_cb.call_end_timestamp.tv_sec + BTIF_HF_CALL_END_TIMEOUT)
+ {
+ return TRUE;
+ }
+ else
+ {
+ btif_hf_cb.call_end_timestamp.tv_sec = 0;
+ return FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function cleanup
+**
+** Description Closes the HF interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static void cleanup( void )
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ if (bt_hf_callbacks)
+ {
+ btif_disable_service(BTA_HFP_SERVICE_ID);
+ bt_hf_callbacks = NULL;
+ }
+}
+
+static const bthf_interface_t bthfInterface = {
+ sizeof(bt_interface_t),
+ init,
+ connect,
+ disconnect,
+ connect_audio,
+ disconnect_audio,
+ start_voice_recognition,
+ stop_voice_recognition,
+ volume_control,
+ device_status_notification,
+ cops_response,
+ cind_response,
+ formatted_at_response,
+ at_response,
+ clcc_response,
+ phone_state_change,
+ cleanup,
+};
+
+/*******************************************************************************
+**
+** Function btif_hf_execute_service
+**
+** Description Initializes/Shuts down the service
+**
+** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_hf_execute_service(BOOLEAN b_enable)
+{
+ char * p_service_names[] = BTIF_HF_SERVICE_NAMES;
+ if (b_enable)
+ {
+ /* Enable and register with BTA-AG */
+ BTA_AgEnable (BTA_AG_PARSE, bte_hf_evt);
+ BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY, BTIF_HF_FEATURES,
+ p_service_names, BTIF_HF_ID_1);
+ }
+ else {
+ /* De-register AG */
+ BTA_AgDeregister(btif_hf_cb.handle);
+ /* Disable AG */
+ BTA_AgDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_hf_get_interface
+**
+** Description Get the hf callback interface
+**
+** Returns bthf_interface_t
+**
+*******************************************************************************/
+const bthf_interface_t *btif_hf_get_interface()
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ return &bthfInterface;
+}
diff --git a/btif/src/btif_hh.c b/btif/src/btif_hh.c
new file mode 100644
index 0000000..61432b8
--- /dev/null
+++ b/btif/src/btif_hh.c
@@ -0,0 +1,1630 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hh.c
+ *
+ * Description: HID Host Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hh.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#define LOG_TAG "BTIF_HH"
+
+#include "bta_api.h"
+#include "bta_hh_api.h"
+#include "bd.h"
+#include "btif_storage.h"
+
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btif_hh.h"
+#include "gki.h"
+#include "l2c_api.h"
+
+
+#define BTIF_HH_APP_ID_MI 0x01
+#define BTIF_HH_APP_ID_KB 0x02
+
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+
+#define KEYSTATE_FILEPATH "/data/misc/bluedroid/bt_hh_ks" //keep this in sync with HID host jni
+
+#define HID_REPORT_CAPSLOCK 0x39
+#define HID_REPORT_NUMLOCK 0x53
+#define HID_REPORT_SCROLLLOCK 0x47
+
+//For Apple Magic Mouse
+#define MAGICMOUSE_VENDOR_ID 0x05ac
+#define MAGICMOUSE_PRODUCT_ID 0x030d
+
+#define LOGITECH_KB_MX5500_VENDOR_ID 0x046D
+#define LOGITECH_KB_MX5500_PRODUCT_ID 0xB30B
+
+extern const int BT_UID;
+extern const int BT_GID;
+static int btif_hh_prev_keyevents=0; //The previous key events
+static int btif_hh_keylockstates=0; //The current key state of each key
+
+#define BTIF_HH_ID_1 0
+#define BTIF_HH_DEV_DISCONNECTED 3
+
+
+#ifndef BTUI_HH_SECURITY
+#define BTUI_HH_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTUI_HH_MOUSE_SECURITY
+#define BTUI_HH_MOUSE_SECURITY (BTA_SEC_NONE)
+#endif
+
+/* HH request events */
+typedef enum
+{
+ BTIF_HH_CONNECT_REQ_EVT = 0,
+ BTIF_HH_DISCONNECT_REQ_EVT,
+ BTIF_HH_VUP_REQ_EVT
+} btif_hh_req_evt_t;
+
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+#define BTIF_HH_SERVICES (BTA_HID_SERVICE_MASK)
+
+
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+typedef struct hid_kb_list
+{
+ UINT16 product_id;
+ UINT16 version_id;
+ char* kb_name;
+} tHID_KB_LIST;
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+btif_hh_cb_t btif_hh_cb;
+
+static bthh_callbacks_t *bt_hh_callbacks = NULL;
+
+/* List of HID keyboards for which the NUMLOCK state needs to be
+ * turned ON by default. Add devices to this list to apply the
+ * NUMLOCK state toggle on fpr first connect.*/
+static tHID_KB_LIST hid_kb_numlock_on_list[] =
+{
+ {LOGITECH_KB_MX5500_PRODUCT_ID,
+ LOGITECH_KB_MX5500_VENDOR_ID,
+ "Logitech MX5500 Keyboard"}
+};
+
+
+#define CHECK_BTHH_INIT() if (bt_hh_callbacks == NULL)\
+ {\
+ BTIF_TRACE_WARNING1("BTHH: %s: BTHH not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+ }\
+ else\
+ {\
+ BTIF_TRACE_EVENT1("BTHH: %s", __FUNCTION__);\
+ }
+
+
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+extern void bta_hh_co_destroy(int fd);
+extern void bta_hh_co_write(int fd, UINT8* rpt, UINT16 len);
+extern bt_status_t btif_dm_remove_bond(const bt_bdaddr_t *bd_addr);
+extern void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 vendor_id,
+ UINT16 product_id, UINT16 version, UINT8 ctry_code,
+ int dscp_len, UINT8 *p_dscp);
+extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod);
+extern void btif_dm_cb_remove_bond(bt_bdaddr_t *bd_addr);
+extern int scru_ascii_2_hex(char *p_ascii, int len, UINT8 *p_hex);
+
+/*****************************************************************************
+** Local Function prototypes
+*****************************************************************************/
+static void set_keylockstate(int keymask, BOOLEAN isSet);
+static void toggle_os_keylockstates(int fd, int changedkeystates);
+static void sync_lockstate_on_connect(btif_hh_device_t *p_dev);
+//static void hh_update_keyboard_lockstates(btif_hh_device_t *p_dev);
+
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+static int get_keylockstates()
+{
+ return btif_hh_keylockstates;
+}
+
+static void set_keylockstate(int keymask, BOOLEAN isSet)
+{
+ if(isSet)
+ btif_hh_keylockstates |= keymask;
+}
+
+/*******************************************************************************
+**
+** Function toggle_os_keylockstates
+**
+** Description Function to toggle the keyboard lock states managed by the linux.
+** This function is used in by two call paths
+** (1) if the lock state change occurred from an onscreen keyboard,
+** this function is called to update the lock state maintained
+ for the HID keyboard(s)
+** (2) if a HID keyboard is disconnected and reconnected,
+** this function is called to update the lock state maintained
+ for the HID keyboard(s)
+** Returns void
+*******************************************************************************/
+
+static void toggle_os_keylockstates(int fd, int changedlockstates)
+{
+ BTIF_TRACE_EVENT3("%s: fd = %d, changedlockstates = 0x%x",
+ __FUNCTION__, fd, changedlockstates);
+ UINT8 hidreport[9];
+ int reportIndex;
+ memset(hidreport,0,9);
+ hidreport[0]=1;
+ reportIndex=4;
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_CAPSLOCK) {
+ BTIF_TRACE_DEBUG1("%s Setting CAPSLOCK", __FUNCTION__);
+ hidreport[reportIndex++] = (UINT8)HID_REPORT_CAPSLOCK;
+ }
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_NUMLOCK) {
+ BTIF_TRACE_DEBUG1("%s Setting NUMLOCK", __FUNCTION__);
+ hidreport[reportIndex++] = (UINT8)HID_REPORT_NUMLOCK;
+ }
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_SCROLLLOCK) {
+ BTIF_TRACE_DEBUG1("%s Setting SCROLLLOCK", __FUNCTION__);
+ hidreport[reportIndex++] = (UINT8) HID_REPORT_SCROLLLOCK;
+ }
+
+ BTIF_TRACE_DEBUG4("Writing hidreport #1 to os: "\
+ "%s: %x %x %x", __FUNCTION__,
+ hidreport[0], hidreport[1], hidreport[2]);
+ BTIF_TRACE_DEBUG4("%s: %x %x %x", __FUNCTION__,
+ hidreport[3], hidreport[4], hidreport[5]);
+ BTIF_TRACE_DEBUG4("%s: %x %x %x", __FUNCTION__,
+ hidreport[6], hidreport[7], hidreport[8]);
+ bta_hh_co_write(fd , hidreport, sizeof(hidreport));
+ usleep(200000);
+ memset(hidreport,0,9);
+ hidreport[0]=1;
+ BTIF_TRACE_DEBUG4("Writing hidreport #2 to os: "\
+ "%s: %x %x %x", __FUNCTION__,
+ hidreport[0], hidreport[1], hidreport[2]);
+ BTIF_TRACE_DEBUG4("%s: %x %x %x", __FUNCTION__,
+ hidreport[3], hidreport[4], hidreport[5]);
+ BTIF_TRACE_DEBUG4("%s: %x %x %x ", __FUNCTION__,
+ hidreport[6], hidreport[7], hidreport[8]);
+ bta_hh_co_write(fd , hidreport, sizeof(hidreport));
+}
+
+/*******************************************************************************
+**
+** Function update_keyboard_lockstates
+**
+** Description Sends a report to the keyboard to set the lock states of keys
+**
+*******************************************************************************/
+static void update_keyboard_lockstates(btif_hh_device_t *p_dev)
+{
+ UINT8 len = 2; /* reportid + 1 byte report*/
+ BD_ADDR* bda;
+
+ /* Set report for other keyboards */
+ BTIF_TRACE_EVENT3("%s: setting report on dev_handle %d to 0x%x",
+ __FUNCTION__, p_dev->dev_handle, btif_hh_keylockstates);
+
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ }
+ /* Get SetReport buffer */
+ p_dev->p_buf = GKI_getbuf((UINT16) (len + BTA_HH_MIN_OFFSET +
+ sizeof(BT_HDR)));
+ if (p_dev->p_buf != NULL) {
+ p_dev->p_buf->len = len;
+ p_dev->p_buf->offset = BTA_HH_MIN_OFFSET;
+
+ /* LED status updated by data event */
+ UINT8 *pbuf_data = (UINT8 *)(p_dev->p_buf + 1)
+ + p_dev->p_buf->offset;
+ pbuf_data[0]=0x01; /*report id */
+ pbuf_data[1]=btif_hh_keylockstates; /*keystate*/
+ bda = (BD_ADDR*) (&p_dev->bd_addr);
+ BTA_HhSendData(p_dev->dev_handle, *bda,
+ p_dev->p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function sync_lockstate_on_connect
+**
+** Description Function to update the keyboard lock states managed by the OS
+** when a HID keyboard is connected or disconnected and reconnected
+** Returns void
+*******************************************************************************/
+static void sync_lockstate_on_connect(btif_hh_device_t *p_dev)
+{
+ int keylockstates;
+
+ BTIF_TRACE_EVENT1("%s: Syncing keyboard lock states after "\
+ "reconnect...",__FUNCTION__);
+ /*If the device is connected, update keyboard state */
+ update_keyboard_lockstates(p_dev);
+
+ /*Check if the lockstate of caps,scroll,num is set.
+ If so, send a report to the kernel
+ so the lockstate is in sync */
+ keylockstates = get_keylockstates();
+ if (keylockstates)
+ {
+ BTIF_TRACE_DEBUG2("%s: Sending hid report to kernel "\
+ "indicating lock key state 0x%x",__FUNCTION__,
+ keylockstates);
+ usleep(200000);
+ toggle_os_keylockstates(p_dev->fd, keylockstates);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG2("%s: NOT sending hid report to kernel "\
+ "indicating lock key state 0x%x",__FUNCTION__,
+ keylockstates);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_find_dev_by_handle
+**
+** Description Return the device pointer of the specified device handle
+**
+** Returns Device entry pointer in the device table
+*******************************************************************************/
+static btif_hh_device_t *btif_hh_find_dev_by_handle(UINT8 handle)
+{
+ UINT32 i;
+ // LOGV("%s: handle = %d", __FUNCTION__, handle);
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status != BTHH_CONN_STATE_UNKNOWN &&
+ btif_hh_cb.devices[i].dev_handle == handle)
+ {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hh_find_connected_dev_by_handle
+**
+** Description Return the connected device pointer of the specified device handle
+**
+** Returns Device entry pointer in the device table
+*******************************************************************************/
+btif_hh_device_t *btif_hh_find_connected_dev_by_handle(UINT8 handle)
+{
+ UINT32 i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED &&
+ btif_hh_cb.devices[i].dev_handle == handle)
+ {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_find_dev_by_bda
+**
+** Description Return the device pointer of the specified bt_bdaddr_t.
+**
+** Returns Device entry pointer in the device table
+*******************************************************************************/
+static btif_hh_device_t *btif_hh_find_dev_by_bda(bt_bdaddr_t *bd_addr)
+{
+ UINT32 i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status != BTHH_CONN_STATE_UNKNOWN &&
+ memcmp(&(btif_hh_cb.devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0)
+ {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_find_connected_dev_by_bda
+**
+** Description Return the connected device pointer of the specified bt_bdaddr_t.
+**
+** Returns Device entry pointer in the device table
+*******************************************************************************/
+static btif_hh_device_t *btif_hh_find_connected_dev_by_bda(bt_bdaddr_t *bd_addr)
+{
+ UINT32 i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED &&
+ memcmp(&(btif_hh_cb.devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0)
+ {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_add_added_dev
+**
+** Description Add a new device to the added device list.
+**
+** Returns TRUE if add successfully, otherwise FALSE.
+*******************************************************************************/
+BOOLEAN btif_hh_add_added_dev(bt_bdaddr_t bda, tBTA_HH_ATTR_MASK attr_mask)
+{
+ int i;
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(&(btif_hh_cb.added_devices[i].bd_addr), &bda, BD_ADDR_LEN) == 0) {
+ BTIF_TRACE_WARNING6(" Device %02X:%02X:%02X:%02X:%02X:%02X already added",
+ bda.address[0], bda.address[1], bda.address[2], bda.address[3], bda.address[4], bda.address[5]);
+ return FALSE;
+ }
+ }
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (btif_hh_cb.added_devices[i].bd_addr.address[0] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[1] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[2] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[3] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[4] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[5] == 0)
+ {
+ BTIF_TRACE_WARNING6(" Added device %02X:%02X:%02X:%02X:%02X:%02X",
+ bda.address[0], bda.address[1], bda.address[2], bda.address[3], bda.address[4], bda.address[5]);
+ memcpy(&(btif_hh_cb.added_devices[i].bd_addr), &bda, BD_ADDR_LEN);
+ btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
+ btif_hh_cb.added_devices[i].attr_mask = attr_mask;
+ return TRUE;
+ }
+ }
+
+ BTIF_TRACE_WARNING1("%s: Error, out of space to add device",__FUNCTION__);
+ return FALSE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_hh_remove_device
+ **
+ ** Description Remove an added device from the stack.
+ **
+ ** Returns void
+ *******************************************************************************/
+void btif_hh_remove_device(bt_bdaddr_t bd_addr)
+{
+ int i;
+ btif_hh_device_t *p_dev;
+ btif_hh_added_device_t *p_added_dev;
+
+ ALOGI("%s: bda = %02x:%02x:%02x:%02x:%02x:%02x", __FUNCTION__,
+ bd_addr.address[0], bd_addr.address[1], bd_addr.address[2], bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ p_added_dev = &btif_hh_cb.added_devices[i];
+ if (memcmp(&(p_added_dev->bd_addr),&bd_addr, 6) == 0) {
+ BTA_HhRemoveDev(p_added_dev->dev_handle);
+ btif_storage_remove_hid_info(&(p_added_dev->bd_addr));
+ memset(&(p_added_dev->bd_addr), 0, 6);
+ p_added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ break;
+ }
+ }
+
+ p_dev = btif_hh_find_dev_by_bda(&bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING6(" Oops, can't find device [%02x:%02x:%02x:%02x:%02x:%02x]",
+ bd_addr.address[0], bd_addr.address[1], bd_addr.address[2], bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+ return;
+ }
+
+ p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN;
+ p_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ if (btif_hh_cb.device_num > 0) {
+ btif_hh_cb.device_num--;
+ }
+ else {
+ BTIF_TRACE_WARNING1("%s: device_num = 0", __FUNCTION__);
+ }
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ p_dev->p_buf = NULL;
+ }
+ BTIF_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
+ if (p_dev->fd >= 0) {
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+}
+
+
+BOOLEAN btif_hh_copy_hid_info(tBTA_HH_DEV_DSCP_INFO* dest , tBTA_HH_DEV_DSCP_INFO* src)
+{
+ dest->descriptor.dl_len = 0;
+ if (src->descriptor.dl_len >0)
+ {
+ dest->descriptor.dsc_list = (UINT8 *) GKI_getbuf(src->descriptor.dl_len);
+ if (dest->descriptor.dsc_list == NULL)
+ {
+ BTIF_TRACE_WARNING1("%s: Failed to allocate DSCP for CB", __FUNCTION__);
+ return FALSE;
+ }
+ }
+ memcpy(dest->descriptor.dsc_list, src->descriptor.dsc_list, src->descriptor.dl_len);
+ dest->descriptor.dl_len = src->descriptor.dl_len;
+ dest->vendor_id = src->vendor_id;
+ dest->product_id = src->product_id;
+ dest->version = src->version;
+ dest->ctry_code = src->ctry_code;
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hh_virtual_unplug
+**
+** Description Virtual unplug initiated from the BTIF thread context
+** Special handling for HID mouse-
+**
+** Returns void
+**
+*******************************************************************************/
+
+bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t *bd_addr)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ btif_hh_device_t *p_dev;
+ char bd_str[18];
+ sprintf(bd_str, "%02X:%02X:%02X:%02X:%02X:%02X",
+ bd_addr->address[0], bd_addr->address[1], bd_addr->address[2], bd_addr->address[3],
+ bd_addr->address[4], bd_addr->address[5]);
+ p_dev = btif_hh_find_dev_by_bda(bd_addr);
+ if ((p_dev != NULL) && (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED)
+ && (p_dev->attr_mask & HID_VIRTUAL_CABLE))
+ {
+ BTIF_TRACE_DEBUG1("%s Sending BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG", __FUNCTION__);
+ BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG);
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ BTIF_TRACE_ERROR2("%s: Error, device %s not opened.", __FUNCTION__, bd_str);
+ return BT_STATUS_FAIL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_connect
+**
+** Description connection initiated from the BTIF thread context
+**
+** Returns int status
+**
+*******************************************************************************/
+
+bt_status_t btif_hh_connect(bt_bdaddr_t *bd_addr)
+{
+ btif_hh_device_t *dev;
+ btif_hh_added_device_t *added_dev = NULL;
+ char bda_str[20];
+ int i;
+ BD_ADDR *bda = (BD_ADDR*)bd_addr;
+ tBTA_HH_CONN conn;
+ CHECK_BTHH_INIT();
+ dev = btif_hh_find_dev_by_bda(bd_addr);
+ BTIF_TRACE_DEBUG0("Connect _hh");
+ sprintf(bda_str, "%02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ if (dev == NULL && btif_hh_cb.device_num >= BTIF_HH_MAX_HID) {
+ // No space for more HID device now.
+ BTIF_TRACE_WARNING2("%s: Error, exceeded the maximum supported HID device number %d",
+ __FUNCTION__, BTIF_HH_MAX_HID);
+ return BT_STATUS_FAIL;
+ }
+
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(&(btif_hh_cb.added_devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0) {
+ added_dev = &btif_hh_cb.added_devices[i];
+ BTIF_TRACE_WARNING3("%s: Device %s already added, attr_mask = 0x%x",
+ __FUNCTION__, bda_str, added_dev->attr_mask);
+ }
+ }
+
+ if (added_dev != NULL) {
+ if (added_dev->dev_handle == BTA_HH_INVALID_HANDLE) {
+ // No space for more HID device now.
+ BTIF_TRACE_ERROR2("%s: Error, device %s added but addition failed", __FUNCTION__, bda_str);
+ memset(&(added_dev->bd_addr), 0, 6);
+ added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ return BT_STATUS_FAIL;
+ }
+ }
+ if (added_dev == NULL ||
+ (added_dev->attr_mask & HID_NORMALLY_CONNECTABLE) != 0 ||
+ (added_dev->attr_mask & HID_RECONN_INIT) == 0)
+ {
+ tBTA_SEC sec_mask = BTUI_HH_SECURITY;
+ btif_hh_cb.status = BTIF_HH_DEV_CONNECTING;
+ BD_ADDR *bda = (BD_ADDR*)bd_addr;
+ BTA_HhOpen(*bda, BTA_HH_PROTO_RPT_MODE, sec_mask);
+ }
+ else {
+ // This device shall be connected from the host side.
+ BTIF_TRACE_ERROR2("%s: Error, device %s can only be reconnected from device side",
+ __FUNCTION__, bda_str);
+ //TODO
+ /* if ((remote_class & BT_DEV_CLASS_MASK) == BT_DEV_CLASS_HID_POINTING) {
+ //SIG_HH_CONNECTION, *bda, HH_CONN_STATUS_FAILED_MOUSE_FROM_HOST);
+ }
+ else {
+ // SIG_HH_CONNECTION, *bda, HH_CONN_STATUS_FAILED_KBD_FROM_HOST);
+ }*/
+ return BT_STATUS_FAIL;
+
+ }
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr, BTHH_CONN_STATE_CONNECTING);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_disconnect
+**
+** Description disconnection initiated from the BTIF thread context
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_hh_disconnect(bt_bdaddr_t *bd_addr)
+{
+ BD_ADDR *bda = (BD_ADDR*)bd_addr;
+ btif_hh_device_t *p_dev;
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL)
+ {
+ BTA_HhClose(p_dev->dev_handle);
+ }
+ else
+ BTIF_TRACE_DEBUG1("%s-- Error: device not connected:",__FUNCTION__);
+}
+
+/*****************************************************************************
+** Section name (Group of functions)
+*****************************************************************************/
+
+/*****************************************************************************
+**
+** btif hh api functions (no context switch)
+**
+*****************************************************************************/
+
+
+/*******************************************************************************
+**
+** Function btif_hh_upstreams_evt
+**
+** Description Executes HH UPSTREAMS events in btif context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hh_upstreams_evt(UINT16 event, char* p_param)
+{
+ tBTA_HH *p_data = (tBTA_HH *)p_param;
+ bdstr_t bdstr;
+ btif_hh_device_t *p_dev = NULL;
+ int i;
+ int len, tmplen;
+
+ BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_hh_event(event));
+
+ switch (event)
+ {
+ case BTA_HH_ENABLE_EVT:
+ BTIF_TRACE_DEBUG2("%s: BTA_HH_ENABLE_EVT: status =%d",__FUNCTION__, p_data->status);
+ if (p_data->status == BTA_HH_OK) {
+ btif_hh_cb.status = BTIF_HH_ENABLED;
+ BTIF_TRACE_DEBUG1("%s--Loading added devices",__FUNCTION__);
+ /* Add hid descriptors for already bonded hid devices*/
+ btif_storage_load_bonded_hid_info();
+ }
+ else {
+ btif_hh_cb.status = BTIF_HH_DISABLED;
+ BTIF_TRACE_WARNING1("BTA_HH_ENABLE_EVT: Error, HH enabling failed, status = %d", p_data->status);
+ }
+ break;
+
+ case BTA_HH_DISABLE_EVT:
+ btif_hh_cb.status = BTIF_HH_DISABLED;
+ if (p_data->status == BTA_HH_OK) {
+ int i;
+ //Clear the control block
+ memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
+ for (i = 0; i < BTIF_HH_MAX_HID; i++){
+ btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
+ }
+ }
+ else
+ BTIF_TRACE_WARNING1("BTA_HH_DISABLE_EVT: Error, HH disabling failed, status = %d", p_data->status);
+ break;
+
+ case BTA_HH_OPEN_EVT:
+ BTIF_TRACE_WARNING3("%s: BTA_HH_OPN_EVT: handle=%d, status =%d",__FUNCTION__, p_data->conn.handle, p_data->conn.status);
+ if (p_data->conn.status == BTA_HH_OK) {
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING1("BTA_HH_OPEN_EVT: Error, cannot find device with handle %d", p_data->conn.handle);
+ btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
+ // The connect request must come from device side and exceeded the connected
+ // HID device number.
+ BTA_HhClose(p_data->conn.handle);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, (bt_bdaddr_t*) &p_data->conn.bda,BTHH_CONN_STATE_DISCONNECTED);
+ }
+ else if (p_dev->fd < 0) {
+ BTIF_TRACE_WARNING0("BTA_HH_OPEN_EVT: Error, failed to find the uhid driver...");
+ memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
+ //remove the connection and then try again to reconnect from the mouse side to recover
+ btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
+ BTA_HhClose(p_data->conn.handle);
+ }
+ else {
+ BTIF_TRACE_WARNING1("BTA_HH_OPEN_EVT: Found device...Getting dscp info for handle ... %d",p_data->conn.handle);
+ memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
+ btif_hh_cb.status = BTIF_HH_DEV_CONNECTED;
+ BTA_HhSetIdle(p_data->conn.handle, 0);
+ btif_hh_cb.p_curr_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+ BTA_HhGetDscpInfo(p_data->conn.handle);
+ p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->bd_addr), p_dev->dev_status);
+ }
+ }
+ else {
+ bt_bdaddr_t *bdaddr = (bt_bdaddr_t*)p_data->conn.bda;
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, (bt_bdaddr_t*) &p_data->conn.bda,BTHH_CONN_STATE_DISCONNECTED);
+ btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
+ }
+ break;
+ case BTA_HH_CLOSE_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_CLOSE_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ if (p_dev != NULL) {
+ BTIF_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
+ if (p_dev->fd >= 0){
+ UINT8 hidreport[9];
+ memset(hidreport,0,9);
+ hidreport[0]=1;
+ bta_hh_co_write(p_dev->fd , hidreport, sizeof(hidreport));
+ }
+ btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
+ p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->bd_addr), p_dev->dev_status);
+ BTIF_TRACE_DEBUG2("%s: Closing uhid fd = %d", __FUNCTION__, p_dev->fd);
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+ else {
+ BTIF_TRACE_WARNING1("Error: cannot find device with handle %d", p_data->dev_status.handle);
+ }
+ break;
+ case BTA_HH_GET_RPT_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_GET_RPT_EVT: status = %d, handle = %d",
+ p_data->hs_data.status, p_data->hs_data.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+ HAL_CBACK(bt_hh_callbacks, get_report_cb,(bt_bdaddr_t*) &(p_dev->bd_addr), (bthh_status_t) p_data->hs_data.status,
+ (uint8_t*) p_data->hs_data.rsp_data.p_rpt_data, BT_HDR_SIZE);
+ break;
+
+ case BTA_HH_SET_RPT_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_SET_RPT_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ if (p_dev != NULL && p_dev->p_buf != NULL) {
+ BTIF_TRACE_DEBUG0("Freeing buffer..." );
+ GKI_freebuf(p_dev->p_buf);
+ p_dev->p_buf = NULL;
+ }
+ break;
+
+ case BTA_HH_GET_PROTO_EVT:
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ BTIF_TRACE_WARNING4("BTA_HH_GET_PROTO_EVT: status = %d, handle = %d, proto = [%d], %s",
+ p_data->hs_data.status, p_data->hs_data.handle,
+ p_data->hs_data.rsp_data.proto_mode,
+ (p_data->hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE) ? "Report Mode" :
+ (p_data->hs_data.rsp_data.proto_mode == BTA_HH_PROTO_BOOT_MODE) ? "Boot Mode" : "Unsupported");
+ HAL_CBACK(bt_hh_callbacks, protocol_mode_cb,(bt_bdaddr_t*) &(p_dev->bd_addr), (bthh_status_t)p_data->hs_data.status,
+ (bthh_protocol_mode_t) p_data->hs_data.rsp_data.proto_mode);
+ break;
+
+ case BTA_HH_SET_PROTO_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_SET_PROTO_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ break;
+
+ case BTA_HH_GET_IDLE_EVT:
+ BTIF_TRACE_DEBUG3("BTA_HH_GET_IDLE_EVT: handle = %d, status = %d, rate = %d",
+ p_data->hs_data.handle, p_data->hs_data.status,
+ p_data->hs_data.rsp_data.idle_rate);
+ break;
+
+ case BTA_HH_SET_IDLE_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_SET_IDLE_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ break;
+
+ case BTA_HH_GET_DSCP_EVT:
+ BTIF_TRACE_WARNING2("BTA_HH_GET_DSCP_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ len = p_data->dscp_info.descriptor.dl_len;
+ BTIF_TRACE_DEBUG1("BTA_HH_GET_DSCP_EVT: len = %d", len);
+ p_dev = btif_hh_cb.p_curr_dev;
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR0("BTA_HH_GET_DSCP_EVT: No HID device is currently connected");
+ return;
+ }
+ if (p_dev->fd < 0) {
+ ALOGE("BTA_HH_GET_DSCP_EVT: Error, failed to find the uhid driver...");
+ return;
+ }
+ {
+ char *cached_name = NULL;
+ char name[] = "Broadcom Bluetooth HID";
+ if (cached_name == NULL) {
+ cached_name = name;
+ }
+
+ BTIF_TRACE_WARNING2("%s: name = %s", __FUNCTION__, cached_name);
+ bta_hh_co_send_hid_info(p_dev, cached_name,
+ p_data->dscp_info.vendor_id, p_data->dscp_info.product_id,
+ p_data->dscp_info.version, p_data->dscp_info.ctry_code,
+ len, p_data->dscp_info.descriptor.dsc_list);
+ if (btif_hh_add_added_dev(p_dev->bd_addr, p_dev->attr_mask)) {
+ BD_ADDR bda;
+ bdcpy(bda, p_dev->bd_addr.address);
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+ bt_status_t ret;
+ bdcpy(bda, p_dev->bd_addr.address);
+ btif_hh_copy_hid_info(&dscp_info, &p_data->dscp_info);
+ BTIF_TRACE_DEBUG6("BTA_HH_GET_DSCP_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+ p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
+ p_dev->bd_addr.address[3], p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+ BTA_HhAddDev(bda, p_dev->attr_mask,p_dev->sub_class,p_dev->app_id, dscp_info);
+ // write hid info to nvram
+ ret = btif_storage_add_hid_device_info(&(p_dev->bd_addr), p_dev->attr_mask,p_dev->sub_class,p_dev->app_id,
+ p_data->dscp_info.vendor_id, p_data->dscp_info.product_id,
+ p_data->dscp_info.version, p_data->dscp_info.ctry_code,
+ len, p_data->dscp_info.descriptor.dsc_list);
+
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing hid info failed", ret);
+ BTIF_TRACE_WARNING0("BTA_HH_GET_DSCP_EVT: Called add device");
+
+ //Free buffer created for dscp_info;
+ if (dscp_info.descriptor.dl_len >0 && dscp_info.descriptor.dsc_list != NULL)
+ {
+ GKI_freebuf(dscp_info.descriptor.dsc_list);
+ dscp_info.descriptor.dsc_list = NULL;
+ dscp_info.descriptor.dl_len=0;
+ }
+ }
+ else {
+ //Device already added.
+ BTIF_TRACE_WARNING1("%s: Device already added ",__FUNCTION__);
+ }
+ /*Sync HID Keyboard lockstates */
+ tmplen = sizeof(hid_kb_numlock_on_list)
+ / sizeof(tHID_KB_LIST);
+ for(i = 0; i< tmplen; i++)
+ {
+ if(p_data->dscp_info.vendor_id
+ == hid_kb_numlock_on_list[i].version_id &&
+ p_data->dscp_info.product_id
+ == hid_kb_numlock_on_list[i].product_id)
+ {
+ BTIF_TRACE_DEBUG3("%s() idx[%d] Enabling "\
+ "NUMLOCK for device :: %s", __FUNCTION__,
+ i, hid_kb_numlock_on_list[i].kb_name);
+ /* Enable NUMLOCK by default so that numeric
+ keys work from first keyboard connect */
+ set_keylockstate(BTIF_HH_KEYSTATE_MASK_NUMLOCK,
+ TRUE);
+ sync_lockstate_on_connect(p_dev);
+ /* End Sync HID Keyboard lockstates */
+ break;
+ }
+ }
+ }
+ break;
+
+ case BTA_HH_ADD_DEV_EVT:
+ BTIF_TRACE_WARNING2("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d",p_data->dev_info.status, p_data->dev_info.handle);
+ int i;
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(btif_hh_cb.added_devices[i].bd_addr.address, p_data->dev_info.bda, 6) == 0) {
+ if (p_data->dev_info.status == BTA_HH_OK) {
+ btif_hh_cb.added_devices[i].dev_handle = p_data->dev_info.handle;
+ }
+ else {
+ memset(btif_hh_cb.added_devices[i].bd_addr.address, 0, 6);
+ btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
+ }
+ break;
+ }
+ }
+ break;
+ case BTA_HH_RMV_DEV_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_RMV_DEV_EVT: status = %d, handle = %d",
+ p_data->dev_info.status, p_data->dev_info.handle);
+ BTIF_TRACE_DEBUG6("BTA_HH_RMV_DEV_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+ p_data->dev_info.bda[0], p_data->dev_info.bda[1], p_data->dev_info.bda[2],
+ p_data->dev_info.bda[3], p_data->dev_info.bda[4], p_data->dev_info.bda[5]);
+ break;
+
+
+ case BTA_HH_VC_UNPLUG_EVT:
+ BTIF_TRACE_DEBUG2("BTA_HH_VC_UNPLUG_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED;
+ if (p_dev != NULL) {
+ BTIF_TRACE_DEBUG6("BTA_HH_VC_UNPLUG_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+ p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
+ p_dev->bd_addr.address[3], p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+ p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+ BTIF_TRACE_DEBUG1("%s---Sending connection state change", __FUNCTION__);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->bd_addr), p_dev->dev_status);
+ BTIF_TRACE_DEBUG1("%s---Removing HID mouse bond", __FUNCTION__);
+ BTA_DmRemoveDevice((UINT8 *)p_dev->bd_addr.address);
+ HAL_CBACK(bt_hh_callbacks, virtual_unplug_cb,&(p_dev->bd_addr),p_data->dev_status.status);
+ }
+ break;
+
+ case BTA_HH_API_ERR_EVT :
+ ALOGI("BTA_HH API_ERR");
+ break;
+
+
+
+ default:
+ BTIF_TRACE_WARNING2("%s: Unhandled event: %d", __FUNCTION__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bte_hh_evt
+**
+** Description Switches context from BTE to BTIF for all HH events
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH *p_data)
+{
+ bt_status_t status;
+ int param_len = 0;
+
+ if (BTA_HH_ENABLE_EVT == event)
+ param_len = sizeof(tBTA_HH_STATUS);
+ else if (BTA_HH_OPEN_EVT == event)
+ param_len = sizeof(tBTA_HH_CONN);
+ else if (BTA_HH_DISABLE_EVT == event)
+ param_len = sizeof(tBTA_HH_STATUS);
+ else if (BTA_HH_CLOSE_EVT == event)
+ param_len = sizeof(tBTA_HH_CBDATA);
+ else if (BTA_HH_GET_DSCP_EVT == event)
+ param_len = sizeof(tBTA_HH_DEV_DSCP_INFO);
+ else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_RPT_EVT == event)|| (BTA_HH_GET_IDLE_EVT == event))
+ param_len = sizeof(tBTA_HH_HSDATA);
+ else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) || (BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event))
+ param_len = sizeof(tBTA_HH_CBDATA);
+ else if ((BTA_HH_ADD_DEV_EVT == event) || (BTA_HH_RMV_DEV_EVT == event) )
+ param_len = sizeof(tBTA_HH_DEV_INFO);
+ else if (BTA_HH_API_ERR_EVT == event)
+ param_len = 0;
+ /* switch context to btif task context (copy full union size for convenience) */
+ status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_handle_evt
+**
+** Description Switches context for immediate callback
+**
+** Returns void
+**
+*******************************************************************************/
+
+static void btif_hh_handle_evt(UINT16 event, char *p_param)
+{
+ bt_bdaddr_t *bd_addr = (bt_bdaddr_t*)p_param;
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ int ret;
+ switch(event)
+ {
+ case BTIF_HH_CONNECT_REQ_EVT:
+ {
+ ret = btif_hh_connect(bd_addr);
+ if(ret == BT_STATUS_SUCCESS)
+ {
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,bd_addr,BTHH_CONN_STATE_CONNECTING);
+ }
+ else
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,bd_addr,BTHH_CONN_STATE_DISCONNECTED);
+ }
+ break;
+
+ case BTIF_HH_DISCONNECT_REQ_EVT:
+ {
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ btif_hh_disconnect(bd_addr);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,bd_addr,BTHH_CONN_STATE_DISCONNECTING);
+ }
+ break;
+
+ case BTIF_HH_VUP_REQ_EVT:
+ {
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ ret = btif_hh_virtual_unplug(bd_addr);
+ }
+ break;
+
+ default:
+ {
+ BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
+ }
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hh_init
+**
+** Description initializes the hh interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init( bthh_callbacks_t* callbacks )
+{
+ UINT32 i;
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+
+ bt_hh_callbacks = callbacks;
+ memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
+ for (i = 0; i < BTIF_HH_MAX_HID; i++){
+ btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
+ }
+ /* Invoke the enable service API to the core to set the appropriate service_id */
+ btif_enable_service(BTA_HID_SERVICE_ID);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function connect
+**
+** Description connect to hid device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect( bt_bdaddr_t *bd_addr)
+{
+ if(btif_hh_cb.status != BTIF_HH_DEV_CONNECTING)
+ {
+ btif_transfer_context(btif_hh_handle_evt, BTIF_HH_CONNECT_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+ }
+ else
+ return BT_STATUS_BUSY;
+}
+
+/*******************************************************************************
+**
+** Function disconnect
+**
+** Description disconnect from hid device
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t disconnect( bt_bdaddr_t *bd_addr )
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_WARNING2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL)
+ {
+ return btif_transfer_context(btif_hh_handle_evt, BTIF_HH_DISCONNECT_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ }
+ else
+ {
+ BTIF_TRACE_WARNING1("%s: Error, device not opened.", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+}
+
+/*******************************************************************************
+**
+** Function virtual_unplug
+**
+** Description Virtual UnPlug (VUP) the specified HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t virtual_unplug (bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ char bd_str[18];
+ sprintf(bd_str, "%02X:%02X:%02X:%02X:%02X:%02X",
+ bd_addr->address[0], bd_addr->address[1], bd_addr->address[2], bd_addr->address[3],
+ bd_addr->address[4], bd_addr->address[5]);
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+ p_dev = btif_hh_find_dev_by_bda(bd_addr);
+ if (!p_dev)
+ {
+ BTIF_TRACE_ERROR2("%s: Error, device %s not opened.", __FUNCTION__, bd_str);
+ return BT_STATUS_FAIL;
+ }
+ btif_transfer_context(btif_hh_handle_evt, BTIF_HH_VUP_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+}
+
+
+/*******************************************************************************
+**
+** Function set_info
+**
+** Description Set the HID device descriptor for the specified HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_info (bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info )
+{
+ CHECK_BTHH_INIT();
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ BTIF_TRACE_DEBUG6("%s: sub_class = 0x%02x, app_id = %d, vendor_id = 0x%04x, "
+ "product_id = 0x%04x, version= 0x%04x",
+ __FUNCTION__, hid_info.sub_class,
+ hid_info.app_id, hid_info.vendor_id, hid_info.product_id,
+ hid_info.version);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED)
+ {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ dscp_info.vendor_id = hid_info.vendor_id;
+ dscp_info.product_id = hid_info.product_id;
+ dscp_info.version = hid_info.version;
+ dscp_info.ctry_code = hid_info.ctry_code;
+
+ dscp_info.descriptor.dl_len = hid_info.dl_len;
+ dscp_info.descriptor.dsc_list = (UINT8 *) GKI_getbuf(dscp_info.descriptor.dl_len);
+ if (dscp_info.descriptor.dsc_list == NULL)
+ {
+ ALOGE("%s: Failed to allocate DSCP for CB", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+ memcpy(dscp_info.descriptor.dsc_list, &(hid_info.dsc_list), hid_info.dl_len);
+
+ if (btif_hh_add_added_dev(*bd_addr, hid_info.attr_mask))
+ {
+ BTA_HhAddDev(*bda, hid_info.attr_mask, hid_info.sub_class,
+ hid_info.app_id, dscp_info);
+ }
+
+ GKI_freebuf(dscp_info.descriptor.dsc_list);
+
+ return BT_STATUS_SUCCESS;
+}
+/*******************************************************************************
+**
+** Function get_idle_time
+**
+** Description Get the HID idle time
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t get_idle_time(bt_bdaddr_t *bd_addr)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG6(" addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL) {
+ //BTA_HhGetIdle(p_dev->dev_handle);
+ }
+ else {
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function set_idle_time
+**
+** Description Set the HID idle time
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_idle_time (bt_bdaddr_t *bd_addr, uint8_t idle_time)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING6(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ //BTA_HhSetIdle(p_dev->dev_handle, idle_time);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function get_protocol
+**
+** Description Get the HID proto mode.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t get_protocol (bt_bdaddr_t *bd_addr, bthh_protocol_mode_t protocolMode)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG6(" addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL) {
+ BTA_HhGetProtoMode(p_dev->dev_handle);
+ }
+ else {
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function set_protocol
+**
+** Description Set the HID proto mode.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_protocol (bt_bdaddr_t *bd_addr, bthh_protocol_mode_t protocolMode)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ UINT8 proto_mode = protocolMode;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG2("%s:proto_mode = %d", __FUNCTION__,protocolMode);
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING6(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else if (protocolMode != BTA_HH_PROTO_RPT_MODE && protocolMode != BTA_HH_PROTO_BOOT_MODE) {
+ BTIF_TRACE_WARNING2("s: Error, device proto_mode = %d.", __FUNCTION__, proto_mode);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ BTA_HhSetProtoMode(p_dev->dev_handle, protocolMode);
+ }
+
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function get_report
+**
+** Description Send a GET_REPORT to HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t get_report (bt_bdaddr_t *bd_addr, bthh_report_type_t reportType, uint8_t reportId, int bufferSize)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG4("%s:proto_mode = %dr_type = %d, rpt_id = %d, buf_size = %d", __FUNCTION__,
+ reportType, reportId, bufferSize);
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR6("%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else if ( ((int) reportType) <= BTA_HH_RPTT_RESRV || ((int) reportType) > BTA_HH_RPTT_FEATURE) {
+ BTIF_TRACE_ERROR6(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ BTA_HhGetReport(p_dev->dev_handle, reportType,
+ reportId, bufferSize);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function set_report
+**
+** Description Send a SET_REPORT to HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t set_report (bt_bdaddr_t *bd_addr, bthh_report_type_t reportType, char* report)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG2("%s:reportType = %d", __FUNCTION__,reportType);
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR6("%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else if ( ( (int) reportType) <= BTA_HH_RPTT_RESRV || ( (int) reportType) > BTA_HH_RPTT_FEATURE) {
+ BTIF_TRACE_ERROR6(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+ else {
+ int hex_bytes_filled;
+ UINT8 hexbuf[200];
+ UINT16 len = (strlen(report) + 1) / 2;
+
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ }
+ p_dev->p_buf = GKI_getbuf((UINT16) (len + BTA_HH_MIN_OFFSET + sizeof(BT_HDR)));
+ if (p_dev->p_buf == NULL) {
+ BTIF_TRACE_ERROR2("%s: Error, failed to allocate RPT buffer, len = %d", __FUNCTION__, len);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev->p_buf->len = len;
+ p_dev->p_buf->offset = BTA_HH_MIN_OFFSET;
+
+ /* Build a SetReport data buffer */
+ memset(hexbuf, 0, 200);
+ //TODO
+ hex_bytes_filled = ascii_2_hex(report, len, hexbuf);
+ ALOGI("Hex bytes filled, hex value: %d", hex_bytes_filled);
+
+ if (hex_bytes_filled) {
+ UINT8* pbuf_data;
+ pbuf_data = (UINT8*) (p_dev->p_buf + 1) + p_dev->p_buf->offset;
+ memcpy(pbuf_data, hexbuf, hex_bytes_filled);
+ BTA_HhSetReport(p_dev->dev_handle, reportType, p_dev->p_buf);
+ }
+ return BT_STATUS_SUCCESS;
+ }
+
+
+}
+
+/*******************************************************************************
+**
+** Function send_data
+**
+** Description Send a SEND_DATA to HID device.
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t send_data (bt_bdaddr_t *bd_addr, char* data)
+{
+ CHECK_BTHH_INIT();
+ btif_hh_device_t *p_dev;
+ BD_ADDR* bda = (BD_ADDR*) bd_addr;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ BTIF_TRACE_DEBUG6("addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR2("%s: Error, HH status = %d", __FUNCTION__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR6("%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+
+ else {
+ int hex_bytes_filled;
+ UINT8 hexbuf[200];
+ UINT16 len = (strlen(data) + 1) / 2;
+
+ if (p_dev->p_buf != NULL) {
+ GKI_freebuf(p_dev->p_buf);
+ }
+ p_dev->p_buf = GKI_getbuf((UINT16) (len + BTA_HH_MIN_OFFSET + sizeof(BT_HDR)));
+ if (p_dev->p_buf == NULL) {
+ BTIF_TRACE_ERROR2("%s: Error, failed to allocate RPT buffer, len = %d", __FUNCTION__, len);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev->p_buf->len = len;
+ p_dev->p_buf->offset = BTA_HH_MIN_OFFSET;
+
+ /* Build a SetReport data buffer */
+ memset(hexbuf, 0, 200);
+ hex_bytes_filled = ascii_2_hex(data, len, hexbuf);
+ BTIF_TRACE_ERROR2("Hex bytes filled, hex value: %d, %d", hex_bytes_filled, len);
+
+ if (hex_bytes_filled) {
+ UINT8* pbuf_data;
+ pbuf_data = (UINT8*) (p_dev->p_buf + 1) + p_dev->p_buf->offset;
+ memcpy(pbuf_data, hexbuf, hex_bytes_filled);
+ BTA_HhSendData(p_dev->dev_handle, *bda, p_dev->p_buf);
+ return BT_STATUS_SUCCESS;
+ }
+
+ }
+ return BT_STATUS_FAIL;
+}
+
+
+/*******************************************************************************
+**
+** Function cleanup
+**
+** Description Closes the HH interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static void cleanup( void )
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ btif_hh_device_t *p_dev;
+ int i;
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_WARNING2("%s: HH disabling or disabled already, status = %d", __FUNCTION__, btif_hh_cb.status);
+ return;
+ }
+ btif_hh_cb.status = BTIF_HH_DISABLING;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ p_dev = &btif_hh_cb.devices[i];
+ if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->fd >= 0) {
+ BTIF_TRACE_DEBUG2("%s: Closing uhid fd = %d", __FUNCTION__, p_dev->fd);
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+ }
+
+ if (bt_hh_callbacks)
+ {
+ btif_disable_service(BTA_HID_SERVICE_ID);
+ bt_hh_callbacks = NULL;
+ }
+
+}
+
+static const bthh_interface_t bthhInterface = {
+ sizeof(bt_interface_t),
+ init,
+ connect,
+ disconnect,
+ virtual_unplug,
+ set_info,
+ get_protocol,
+ set_protocol,
+// get_idle_time,
+// set_idle_time,
+ get_report,
+ set_report,
+ send_data,
+ cleanup,
+};
+
+/*******************************************************************************
+**
+** Function btif_hh_execute_service
+**
+** Description Initializes/Shuts down the service
+**
+** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_hh_execute_service(BOOLEAN b_enable)
+{
+ if (b_enable)
+ {
+ /* Enable and register with BTA-HH */
+ BTA_HhEnable(BTA_SEC_NONE, FALSE, bte_hh_evt);
+ }
+ else {
+ /* Disable HH */
+ BTA_HhDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_hh_get_interface
+**
+** Description Get the hh callback interface
+**
+** Returns bthh_interface_t
+**
+*******************************************************************************/
+const bthh_interface_t *btif_hh_get_interface()
+{
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ return &bthhInterface;
+}
diff --git a/btif/src/btif_hl.c b/btif/src/btif_hl.c
new file mode 100644
index 0000000..e6c3fb7
--- /dev/null
+++ b/btif/src/btif_hl.c
@@ -0,0 +1,5224 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hl.c
+ *
+ * Description: Health Device Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#define LOG_TAG "BTIF_HL"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <cutils/sockets.h>
+#include <cutils/log.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hl.h>
+
+#include "btif_common.h"
+#include "btif_util.h"
+#include "gki.h"
+#include "bd.h"
+#include "bta_api.h"
+#include "bta_hl_api.h"
+#include "mca_api.h"
+#include "btif_hl.h"
+#include "btif_storage.h"
+#include "btu.h"
+
+extern int btif_hl_update_maxfd( int max_org_s);
+extern void btif_hl_select_monitor_callback( fd_set *p_cur_set, fd_set *p_org_set );
+extern void btif_hl_select_wakeup_callback( fd_set *p_org_set , int wakeup_signal );
+extern int btif_hl_update_maxfd( int max_org_s);
+extern void btif_hl_select_monitor_callback( fd_set *p_cur_set, fd_set *p_org_set );
+extern void btif_hl_select_wakeup_callback( fd_set *p_org_set , int wakeup_signal );
+extern void btif_hl_soc_thread_init(void);
+extern void btif_hl_release_mcl_sockets(UINT8 app_idx, UINT8 mcl_idx);
+extern BOOLEAN btif_hl_create_socket(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx);
+extern void btif_hl_release_socket(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx);
+
+btif_hl_cb_t btif_hl_cb;
+btif_hl_cb_t *p_btif_hl_cb = &btif_hl_cb;
+btif_hl_nv_cb_t *p_ncb = &btif_hl_cb.ncb;
+/************************************************************************************
+** Static variables
+************************************************************************************/
+static bthl_callbacks_t bt_hl_callbacks_cb;
+static bthl_callbacks_t *bt_hl_callbacks=NULL;
+
+/* signal socketpair to wake up select loop */
+
+const int btif_hl_signal_select_wakeup = 1;
+const int btif_hl_signal_select_exit = 2;
+const int btif_hl_signal_select_close_connected = 3;
+
+static int listen_s = -1;
+static int connected_s = -1;
+static int select_thread_id = -1;
+static int signal_fds[2];
+static BUFFER_Q soc_queue;
+
+static inline int btif_hl_select_wakeup(void);
+static inline int btif_hl_select_exit(void);
+static inline int btif_hl_select_close_connected(void);
+static inline int btif_hl_close_select_thread(void);
+static UINT8 btif_hl_get_next_app_id(void);
+static int btif_hl_get_next_channel_id(UINT8 app_id);
+static void btif_hl_init_next_app_id(void);
+static void btif_hl_init_next_channel_id(void);
+static void btif_hl_ctrl_cback(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL *p_data);
+static void btif_hl_set_state(btif_hl_state_t state);
+static btif_hl_state_t btif_hl_get_state(void);
+static void btif_hl_cback(tBTA_HL_EVT event, tBTA_HL *p_data);
+static void btif_hl_proc_cb_evt(UINT16 event, char* p_param);
+
+#define CHECK_CALL_CBACK(P_CB, P_CBACK, ...)\
+ if (P_CB && P_CB->P_CBACK) { \
+ P_CB->P_CBACK(__VA_ARGS__); \
+ } \
+ else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ }
+
+
+#define BTIF_HL_CALL_CBACK(P_CB, P_CBACK, ...)\
+ if((p_btif_hl_cb->state != BTIF_HL_STATE_DISABLING) &&\
+ (p_btif_hl_cb->state != BTIF_HL_STATE_DISABLED)) \
+ { \
+ if (P_CB && P_CB->P_CBACK) { \
+ P_CB->P_CBACK(__VA_ARGS__); \
+ } \
+ else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ } \
+ }
+
+
+#define CHECK_BTHL_INIT() if (bt_hl_callbacks == NULL)\
+ {\
+ BTIF_TRACE_WARNING1("BTHL: %s: BTHL not initialized", __FUNCTION__);\
+ return BT_STATUS_NOT_READY;\
+ }\
+ else\
+ {\
+ BTIF_TRACE_EVENT1("BTHL: %s", __FUNCTION__);\
+ }
+
+
+static const btif_hl_data_type_cfg_t data_type_table[] = {
+ /* Data Specilization Ntx Nrx (from Bluetooth SIG's HDP whitepaper)*/
+ {BTIF_HL_DATA_TYPE_PULSE_OXIMETER, 9216, 256},
+ {BTIF_HL_DATA_TYPE_BLOOD_PRESSURE_MON, 896, 224},
+ {BTIF_HL_DATA_TYPE_BODY_THERMOMETER, 896, 224},
+ {BTIF_HL_DATA_TYPE_BODY_WEIGHT_SCALE, 896, 224},
+ {BTIF_HL_DATA_TYPE_GLUCOSE_METER, 896, 224},
+ {BTIF_HL_DATA_TYPE_STEP_COUNTER, 6624, 224}
+};
+
+#define BTIF_HL_DATA_TABLE_SIZE (sizeof(data_type_table) / sizeof(btif_hl_data_type_cfg_t))
+#define BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE 10240 /* use this size if the data type is not
+ defined in the table; for future proof */
+#define BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE 512 /* use this size if the data type is not
+ defined in the table; for future proof */
+
+#define BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE 1024
+
+/************************************************************************************
+** Static utility functions
+************************************************************************************/
+
+#define BTIF_IF_GET_NAME 16
+void btif_hl_display_calling_process_name(void)
+{
+ char name[16];
+ prctl(BTIF_IF_GET_NAME, name, 0, 0, 0);
+ BTIF_TRACE_DEBUG1("Process name (%s)", name);
+}
+#define BTIF_TIMEOUT_CCH_NO_DCH_SECS 10
+/*******************************************************************************
+**
+** Function btif_hl_if_channel_setup_pending
+**
+** Description check whether channel id is in setup pending state or not
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_if_channel_setup_pending(int channel_id, UINT8 *p_app_idx, UINT8 *p_mcl_idx)
+{
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ UINT8 i, j;
+ BOOLEAN found=FALSE;
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ p_acb =BTIF_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use)
+ {
+ for (j=0; j< BTA_HL_NUM_MCLS; j++)
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, j);
+ if (p_mcb->in_use &&
+ p_mcb->is_connected && p_mcb->pcb.channel_id == channel_id )
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ break;
+ }
+ }
+ }
+ if (found)
+ break;
+ }
+ BTIF_TRACE_DEBUG5("%s found=%d channel_id=0x%08x",
+ __FUNCTION__, found, channel_id, *p_app_idx, *p_mcl_idx);
+ return found;
+
+}
+/*******************************************************************************
+**
+** Function btif_hl_num_dchs_in_use
+**
+** Description find number of DCHs in use
+**
+** Returns UINT8
+*******************************************************************************/
+UINT8 btif_hl_num_dchs_in_use(UINT8 app_idx,UINT8 mcl_idx){
+
+ btif_hl_mcl_cb_t *p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ UINT8 i;
+ UINT8 cnt=0;
+
+ for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
+ {
+ if (p_mcb->mdl[i].in_use)
+ cnt++;
+ }
+ BTIF_TRACE_DEBUG2("%s dch in use count=%d", __FUNCTION__, cnt);
+ return cnt;
+}
+/*******************************************************************************
+**
+** Function btif_hl_tmr_hdlr
+**
+** Description Process timer timeout
+**
+** Returns void
+*******************************************************************************/
+void btif_hl_tmr_hdlr(TIMER_LIST_ENT *tle)
+{
+ btif_hl_mcl_cb_t *p_mcb;
+ UINT8 i,j;
+ BTIF_TRACE_DEBUG2("%s timer_in_use=%d", __FUNCTION__, tle->in_use );
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ for (j=0; j< BTA_HL_NUM_MCLS; j++)
+ {
+ p_mcb =BTIF_HL_GET_MCL_CB_PTR(i,j);
+
+ if (p_mcb->cch_timer_active)
+ {
+ BTIF_TRACE_DEBUG3("%app_idx=%d, mcl_idx=%d mcl-connected=%d",
+ i, j, p_mcb->is_connected);
+ p_mcb->cch_timer_active = FALSE;
+ if (p_mcb->is_connected)
+ {
+ BTIF_TRACE_DEBUG3("Idle timeout Close CCH app_idx=%d mcl_idx=%d mcl_handle=%d",
+ i ,j, p_mcb->mcl_handle);
+ BTA_HlCchClose(p_mcb->mcl_handle);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG2("CCH idle timeout But CCH not connected app_idx=%d mcl_idx=%d ",i,j);
+ }
+ }
+ }
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_stop_cch_timer
+**
+** Description stop CCH timer
+**
+** Returns void
+*******************************************************************************/
+void btif_hl_stop_cch_timer(UINT8 app_idx, UINT8 mcl_idx)
+{
+ btif_hl_mcl_cb_t *p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG4("%s app_idx=%d, mcl_idx=%d timer_in_use=%d",
+ __FUNCTION__,app_idx, mcl_idx, p_mcb->cch_timer.in_use);
+
+ p_mcb->cch_timer_active = FALSE;
+ if (p_mcb->cch_timer.in_use)
+ {
+ BTIF_TRACE_DEBUG0("stop CCH timer ");
+ btu_stop_timer(&p_mcb->cch_timer);
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_start_cch_timer
+**
+** Description start CCH timer
+**
+** Returns void
+*******************************************************************************/
+void btif_hl_start_cch_timer(UINT8 app_idx, UINT8 mcl_idx)
+{
+ btif_hl_mcl_cb_t *p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG5("%s app_idx=%d, mcl_idx=%d timer_active=%d timer_in_use=%d",
+ __FUNCTION__,app_idx, mcl_idx,
+ p_mcb->cch_timer_active, p_mcb->cch_timer.in_use);
+
+ p_mcb->cch_timer_active = TRUE;
+ if (!p_mcb->cch_timer.in_use)
+ {
+ BTIF_TRACE_DEBUG0("Start CCH timer ");
+ memset(&p_mcb->cch_timer, 0, sizeof(TIMER_LIST_ENT));
+ p_mcb->cch_timer.param = (UINT32)btif_hl_tmr_hdlr;
+ btu_start_timer(&p_mcb->cch_timer, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_CCH_NO_DCH_SECS);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("Restart CCH timer ");
+ btu_stop_timer(&p_mcb->cch_timer);
+ btu_start_timer(&p_mcb->cch_timer, BTU_TTYPE_USER_FUNC,
+ BTIF_TIMEOUT_CCH_NO_DCH_SECS);
+ }
+
+}
+/*******************************************************************************
+**
+** Function btif_hl_find_mdl_idx
+**
+** Description Find the MDL index using MDL ID
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_find_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, UINT16 mdl_id,
+ UINT8 *p_mdl_idx)
+{
+ btif_hl_mcl_cb_t *p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
+ {
+ if (p_mcb->mdl[i].in_use &&
+ (mdl_id !=0) &&
+ (p_mcb->mdl[i].mdl_id== mdl_id))
+ {
+ found = TRUE;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG4("%s found=%d mdl_id=%d mdl_idx=%d ",
+ __FUNCTION__,found, mdl_id, i);
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_get_buf
+**
+** Description get buffer
+**
+** Returns void
+**
+*******************************************************************************/
+void * btif_hl_get_buf(UINT16 size)
+{
+ void *p_new;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ BTIF_TRACE_DEBUG2("ret size=%d GKI_MAX_BUF_SIZE=%d",size, 6000);
+
+ if (size < 6000)
+ {
+ p_new = GKI_getbuf(size);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("btif_hl_get_buf use HL large data pool");
+ p_new = GKI_getpoolbuf(4);
+ }
+
+ return p_new;
+}
+/*******************************************************************************
+**
+** Function btif_hl_free_buf
+**
+** Description free buffer
+**
+** Return void
+**
+*******************************************************************************/
+void btif_hl_free_buf(void **p)
+{
+ if (*p != NULL)
+ {
+ BTIF_TRACE_DEBUG1("%s OK", __FUNCTION__ );
+ GKI_freebuf(*p);
+ *p = NULL;
+ }
+ else
+ BTIF_TRACE_ERROR1("%s NULL pointer",__FUNCTION__ );
+}
+/*******************************************************************************
+**
+** Function btif_hl_is_the_first_reliable_existed
+**
+** Description This function checks whether the first reliable DCH channel
+** has been setup on the MCL or not
+**
+** Returns BOOLEAN - TRUE exist
+** FALSE does not exist
+**
+*******************************************************************************/
+BOOLEAN btif_hl_is_the_first_reliable_existed(UINT8 app_idx, UINT8 mcl_idx )
+{
+ btif_hl_mcl_cb_t *p_mcb =BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN is_existed =FALSE;
+ UINT8 i ;
+
+ for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++)
+ {
+ if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable)
+ {
+ is_existed = TRUE;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG1("bta_hl_is_the_first_reliable_existed is_existed=%d ",is_existed );
+ return is_existed;
+}
+/*******************************************************************************
+**
+** Function btif_hl_clean_delete_mdl
+**
+** Description Cleanup the delete mdl control block
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_clean_delete_mdl(btif_hl_delete_mdl_t *p_cb)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__ );
+ memset(p_cb, 0 , sizeof(btif_hl_delete_mdl_t));
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_clean_pcb
+**
+** Description Cleanup the pending chan control block
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_clean_pcb(btif_hl_pending_chan_cb_t *p_pcb)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__ );
+ memset(p_pcb, 0 , sizeof(btif_hl_pending_chan_cb_t));
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_clean_mdl_cb
+**
+** Description Cleanup the MDL control block
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_clean_mdl_cb(btif_hl_mdl_cb_t *p_dcb)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__ );
+ btif_hl_free_buf((void **) &p_dcb->p_rx_pkt);
+ btif_hl_free_buf((void **) &p_dcb->p_tx_pkt);
+ memset(p_dcb, 0 , sizeof(btif_hl_mdl_cb_t));
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_reset_mcb
+**
+** Description Reset MCL control block
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static void btif_hl_clean_mcl_cb(UINT8 app_idx, UINT8 mcl_idx)
+{
+ btif_hl_mcl_cb_t *p_mcb;
+ BTIF_TRACE_DEBUG3("%s app_idx=%d, mcl_idx=%d", __FUNCTION__,app_idx, mcl_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_find_sdp_idx_using_mdep_filter
+**
+** Description This function finds the SDP record index using MDEP filter parameters
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static void btif_hl_reset_mdep_filter(UINT8 app_idx)
+{
+ btif_hl_app_cb_t *p_acb =BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->filter.num_elems = 0;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_sdp_idx_using_mdep_filter
+**
+** Description This function finds the SDP record index using MDEP filter parameters
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_find_sdp_idx_using_mdep_filter(UINT8 app_idx, UINT8 mcl_idx, UINT8 *p_sdp_idx)
+{
+ btif_hl_app_cb_t *p_acb =BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_mcl_cb_t *p_mcb =BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ UINT8 i, j, num_recs,num_elems, num_mdeps, mdep_cnt, mdep_idx;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+ UINT16 data_type;
+ tBTA_HL_SDP_MDEP_CFG *p_mdep;
+ BOOLEAN found = FALSE;
+ BOOLEAN elem_found;
+
+ num_recs = p_mcb->sdp.num_recs;
+ num_elems = p_acb->filter.num_elems;
+ if (!num_elems)
+ {
+ *p_sdp_idx = 0;
+ found = TRUE;
+ return found;
+ }
+
+ for (i=0; i<num_recs; i++)
+ {
+ num_mdeps = p_mcb->sdp.sdp_rec[i].num_mdeps;
+ for (j=0; j<num_elems; j++ )
+ {
+ data_type = p_acb->filter.elem[j].data_type;
+ peer_mdep_role = p_acb->filter.elem[j].peer_mdep_role;
+ elem_found = FALSE;
+ mdep_cnt =0;
+ mdep_idx=0;
+ while (!elem_found && mdep_idx < num_mdeps )
+ {
+ p_mdep = &(p_mcb->sdp.sdp_rec[i].mdep_cfg[mdep_idx]);
+ if ( (p_mdep->data_type == data_type) &&
+ (p_mdep->mdep_role == peer_mdep_role) )
+ {
+ elem_found = TRUE;
+ }
+ else
+ {
+ mdep_idx++;
+ }
+ }
+
+ if (!elem_found)
+ {
+ found = FALSE;
+ break;
+ }
+ else
+ {
+ found = TRUE;
+ }
+ }
+
+ if (found)
+ {
+ *p_sdp_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG3("%s found=%d sdp_idx=%d",__FUNCTION__ , found, *p_sdp_idx);
+
+ btif_hl_reset_mdep_filter(app_idx);
+
+ return found;
+}
+/*******************************************************************************
+**
+** Function btif_hl_is_reconnect_possible
+**
+** Description check reconnect is possible or not
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_is_reconnect_possible(UINT8 app_idx, UINT8 mcl_idx, int mdep_cfg_idx,
+ tBTA_HL_DCH_OPEN_PARAM *p_dch_open_api, tBTA_HL_MDL_ID *p_mdl_id)
+{
+ btif_hl_app_cb_t *p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_mcl_cb_t *p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_DCH_CFG local_cfg = p_dch_open_api->local_cfg;
+ tBTA_HL_DCH_MODE dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ BOOLEAN use_mdl_dch_mode=FALSE;
+ btif_hl_mdl_cfg_t *p_mdl;
+ btif_hl_mdl_cfg_t *p_mdl1;
+ UINT8 i, j;
+ BOOLEAN is_reconnect_ok=FALSE;
+ BOOLEAN stream_mode_avail=FALSE;
+ UINT16 data_type = p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.data_cfg[0].data_type;
+ tBTA_HL_MDEP_ID peer_mdep_id = p_dch_open_api->peer_mdep_id;
+ UINT8 mdl_idx;
+
+
+ BTIF_TRACE_DEBUG4("%s app_idx=%d mcl_idx=%d mdep_cfg_idx=%d",
+ __FUNCTION__, app_idx, mcl_idx, mdep_cfg_idx );
+ switch (local_cfg)
+ {
+ case BTA_HL_DCH_CFG_NO_PREF:
+ if (!btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx))
+ {
+ dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ }
+ else
+ {
+ use_mdl_dch_mode = TRUE;
+ }
+ break;
+ case BTA_HL_DCH_CFG_RELIABLE:
+ dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ break;
+ case BTA_HL_DCH_CFG_STREAMING:
+ dch_mode = BTA_HL_DCH_MODE_STREAMING;
+ break;
+ default:
+ BTIF_TRACE_ERROR1("Invalid local_cfg=%d",local_cfg );
+ return is_reconnect_ok;
+ break;
+
+ }
+
+ BTIF_TRACE_DEBUG3("local_cfg=%d use_mdl_dch_mode=%d dch_mode=%d ",
+ local_cfg, use_mdl_dch_mode, dch_mode );
+
+ for (i=0, p_mdl=&p_acb->mdl_cfg[0] ; i< BTA_HL_NUM_MDL_CFGS; i++, p_mdl++ )
+ {
+ if (p_mdl->base.active &&
+ p_mdl->extra.data_type ==data_type &&
+ (p_mdl->extra.peer_mdep_id != BTA_HL_INVALID_MDEP_ID && p_mdl->extra.peer_mdep_id == peer_mdep_id) &&
+ memcpy(p_mdl->base.peer_bd_addr, p_mcb->bd_addr,sizeof(BD_ADDR) ) &&
+ p_mdl->base.mdl_id &&
+ !btif_hl_find_mdl_idx(app_idx, mcl_idx,p_mdl->base.mdl_id, &mdl_idx))
+ {
+ BTIF_TRACE_DEBUG3("i=%d Matched active=%d mdl_id =%d",
+ i, p_mdl->base.active, p_mdl->base.mdl_id);
+ if (!use_mdl_dch_mode)
+ {
+ if (p_mdl->base.dch_mode == dch_mode)
+ {
+ is_reconnect_ok = TRUE;
+ *p_mdl_id = p_mdl->base.mdl_id;
+ BTIF_TRACE_DEBUG2("reconnect is possible dch_mode=%d mdl_id=%d", dch_mode, p_mdl->base.mdl_id );
+ break;
+ }
+ }
+ else
+ {
+ is_reconnect_ok = TRUE;
+ for (j=i, p_mdl1=&p_acb->mdl_cfg[i]; j< BTA_HL_NUM_MDL_CFGS; j++, p_mdl1++)
+ {
+ if (p_mdl1->base.active &&
+ p_mdl1->extra.data_type == data_type &&
+ (p_mdl1->extra.peer_mdep_id != BTA_HL_INVALID_MDEP_ID && p_mdl1->extra.peer_mdep_id == peer_mdep_id) &&
+ memcpy(p_mdl1->base.peer_bd_addr, p_mcb->bd_addr,sizeof(BD_ADDR)) &&
+ p_mdl1->base.dch_mode == BTA_HL_DCH_MODE_STREAMING)
+ {
+ stream_mode_avail = TRUE;
+ BTIF_TRACE_DEBUG1("found streaming mode mdl index=%d", j);
+ break;
+ }
+ }
+
+ if (stream_mode_avail)
+ {
+ dch_mode = BTA_HL_DCH_MODE_STREAMING;
+ *p_mdl_id = p_mdl1->base.mdl_id;
+ BTIF_TRACE_DEBUG2("reconnect is ok index=%d dch_mode=streaming mdl_id=%d", j, *p_mdl_id);
+ break;
+ }
+ else
+ {
+ dch_mode= p_mdl->base.dch_mode;
+ *p_mdl_id = p_mdl->base.mdl_id;
+ BTIF_TRACE_DEBUG3("reconnect is ok index=%d dch_mode=%d mdl_id=%d", i, p_mdl->base.dch_mode, *p_mdl_id);
+ break;
+
+ }
+ }
+
+ }
+
+ }
+
+ BTIF_TRACE_DEBUG3("is_reconnect_ok dch_mode=%d mdl_id=%d",is_reconnect_ok, dch_mode, *p_mdl_id);
+ return is_reconnect_ok;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_dch_open
+**
+** Description Process DCH open request using the DCH Open API parameters
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_dch_open(UINT8 app_id, BD_ADDR bd_addr,
+ tBTA_HL_DCH_OPEN_PARAM *p_dch_open_api,
+ int mdep_cfg_idx,
+ btif_hl_pend_dch_op_t op, int *channel_id){
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_pending_chan_cb_t *p_pcb;
+ UINT8 app_idx, mcl_idx;
+ BOOLEAN status = FALSE;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_DCH_RECONNECT_PARAM reconnect_param;
+
+ BTIF_TRACE_DEBUG2("%s app_id=%d ",
+ __FUNCTION__, app_id );
+ BTIF_TRACE_DEBUG6("DB [%02x:%02x:%02x:%02x:%02x:%02x]",
+ bd_addr[0], bd_addr[1],bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+ if (btif_hl_find_mcl_idx(app_idx, bd_addr , &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ if (!p_pcb->in_use)
+ {
+ p_mcb->req_ctrl_psm = p_dch_open_api->ctrl_psm;
+
+ p_pcb->in_use = TRUE;
+ *channel_id =
+ p_pcb->channel_id = (int) btif_hl_get_next_channel_id(app_id);
+ p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING;
+ p_pcb->mdep_cfg_idx = mdep_cfg_idx;
+ p_pcb->op = op;
+
+ if (p_mcb->sdp.num_recs)
+ {
+ if (p_mcb->valid_sdp_idx)
+ {
+ p_dch_open_api->ctrl_psm = p_mcb->ctrl_psm;
+ }
+
+ if (!btif_hl_is_reconnect_possible(app_idx, mcl_idx, mdep_cfg_idx, p_dch_open_api, &mdl_id ))
+ {
+
+ BTIF_TRACE_DEBUG0("Issue DCH open" );
+ BTA_HlDchOpen(p_mcb->mcl_handle, p_dch_open_api);
+ }
+ else
+ {
+ reconnect_param.ctrl_psm = p_mcb->ctrl_psm;
+ reconnect_param.mdl_id = mdl_id;;
+ BTIF_TRACE_DEBUG2("Issue Reconnect ctrl_psm=0x%x mdl_id=0x%x",reconnect_param.ctrl_psm, reconnect_param.mdl_id );
+ BTA_HlDchReconnect(p_mcb->mcl_handle, &reconnect_param);
+ }
+
+ status = TRUE;
+ }
+ else
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_DCH_OPEN;
+ BTA_HlSdpQuery(p_acb->app_handle, bd_addr);
+ status = TRUE;
+ }
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG1("status=%d ", status);
+ return status;
+}
+/*******************************************************************************
+**
+** Function btif_hl_copy_bda
+**
+** Description copy bt_bdaddr_t to BD_ADDR format
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_copy_bda(bt_bdaddr_t *bd_addr, BD_ADDR bda){
+ UINT8 i;
+ for (i=0; i<6; i++)
+ {
+ bd_addr->address[i] = bda[i] ;
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_copy_bda
+**
+** Description display bt_bdaddr_t
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+void btif_hl_display_bt_bda(bt_bdaddr_t *bd_addr){
+ BTIF_TRACE_DEBUG6("DB [%02x:%02x:%02x:%02x:%02x:%02x]",
+ bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
+ bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_dch_abort
+**
+** Description Process DCH abort request
+**
+** Returns Nothing
+**
+*******************************************************************************/
+void btif_hl_dch_abort(UINT8 app_idx, UINT8 mcl_idx){
+ btif_hl_mcl_cb_t *p_mcb;
+
+ BTIF_TRACE_DEBUG3("%s app_idx=%d mcl_idx=%d",__FUNCTION__, app_idx, mcl_idx );
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->is_connected)
+ {
+ BTA_HlDchAbort(p_mcb->mcl_handle);
+ }
+ else
+ {
+ p_mcb->pcb.abort_pending = TRUE;
+ }
+
+}
+/*******************************************************************************
+**
+** Function btif_hl_cch_open
+**
+** Description Process CCH open request
+**
+** Returns Nothing
+**
+*******************************************************************************/
+BOOLEAN btif_hl_cch_open(UINT8 app_id, BD_ADDR bd_addr, UINT16 ctrl_psm,
+ int mdep_cfg_idx,
+ btif_hl_pend_dch_op_t op, int *channel_id){
+
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_pending_chan_cb_t *p_pcb;
+ UINT8 app_idx, mcl_idx, chan_idx;
+ BOOLEAN status = TRUE;
+
+ BTIF_TRACE_DEBUG5("%s app_id=%d ctrl_psm=%d mdep_cfg_idx=%d op=%d",
+ __FUNCTION__, app_id, ctrl_psm, mdep_cfg_idx, op);
+ BTIF_TRACE_DEBUG6("DB [%02x:%02x:%02x:%02x:%02x:%02x]",
+ bd_addr[0], bd_addr[1],bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ if (!btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx))
+ {
+ if (btif_hl_find_avail_mcl_idx(app_idx, &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ memset(p_mcb,0, sizeof(btif_hl_mcl_cb_t));
+ p_mcb->in_use = TRUE;
+ bdcpy(p_mcb->bd_addr, bd_addr);
+
+ if (!ctrl_psm)
+ {
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_MDEP_FILTERING;
+ }
+ else
+ {
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_MATCHED_CTRL_PSM;
+ p_mcb->req_ctrl_psm = ctrl_psm;
+ }
+
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ p_pcb->in_use = TRUE;
+ p_pcb->mdep_cfg_idx = mdep_cfg_idx;
+ memcpy(p_pcb->bd_addr, bd_addr, sizeof(BD_ADDR));
+ p_pcb->op = op;
+
+ switch (op)
+ {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ *channel_id =
+ p_pcb->channel_id = (int) btif_hl_get_next_channel_id(app_id);
+ p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING;
+ break;
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ p_pcb->channel_id = p_acb->delete_mdl.channel_id;
+ p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_DESTROYED_PENDING;
+ break;
+ default:
+ break;
+ }
+ BTA_HlSdpQuery(p_acb->app_handle, bd_addr);
+ }
+ else
+ {
+ status = FALSE;
+ BTIF_TRACE_ERROR0("Open CCH request discarded- No mcl cb");
+ }
+ }
+ else
+ {
+ status = FALSE;
+ BTIF_TRACE_ERROR0("Open CCH request discarded- already in USE");
+ }
+ }
+ else
+ {
+ status = FALSE;
+ BTIF_TRACE_ERROR1("Invalid app_id=%d", app_id);
+ }
+
+ if (channel_id)
+ {
+ BTIF_TRACE_DEBUG2("status=%d channel_id=0x%08x", status, *channel_id);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG1("status=%d ", status);
+ }
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_find_mdl_idx_using_handle
+**
+** Description Find the MDL index using channel id
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_mdl_cfg_idx_using_channel_id(int channel_id,
+ UINT8 *p_app_idx,
+ UINT8 *p_mdl_cfg_idx){
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mdl_cfg_t *p_mdl;
+ BOOLEAN found=FALSE;
+ UINT8 i,j;
+ int mdl_cfg_channel_id;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ p_acb =BTIF_HL_GET_APP_CB_PTR(i);
+ for (j=0; j< BTA_HL_NUM_MDL_CFGS; j++)
+ {
+ p_mdl =BTIF_HL_GET_MDL_CFG_PTR(i,j);
+ mdl_cfg_channel_id = *(BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(i,j));
+ if (p_acb->in_use &&
+ p_mdl->base.active &&
+ (mdl_cfg_channel_id == channel_id))
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ *p_mdl_cfg_idx =j;
+ break;
+ }
+ }
+ }
+
+ BTIF_TRACE_EVENT5("%s found=%d channel_id=0x%08x, app_idx=%d mdl_cfg_idx=%d ",
+ __FUNCTION__,found,channel_id, i,j );
+ return found;
+}
+/*******************************************************************************
+**
+** Function btif_hl_find_mdl_idx_using_handle
+**
+** Description Find the MDL index using channel id
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_mdl_idx_using_channel_id(int channel_id,
+ UINT8 *p_app_idx,UINT8 *p_mcl_idx,
+ UINT8 *p_mdl_idx){
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_mdl_cb_t *p_dcb;
+ BOOLEAN found=FALSE;
+ UINT8 i,j,k;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ p_acb =BTIF_HL_GET_APP_CB_PTR(i);
+ for (j=0; j< BTA_HL_NUM_MCLS; j++)
+ {
+ p_mcb =BTIF_HL_GET_MCL_CB_PTR(i,j);
+ for (k=0; k< BTA_HL_NUM_MDLS_PER_MCL; k++)
+ {
+ p_dcb =BTIF_HL_GET_MDL_CB_PTR(i,j,k);
+ if (p_acb->in_use &&
+ p_mcb->in_use &&
+ p_dcb->in_use &&
+ (p_dcb->channel_id == channel_id))
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ *p_mcl_idx =j;
+ *p_mdl_idx = k;
+ break;
+ }
+ }
+ }
+ }
+ BTIF_TRACE_DEBUG5("%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d ",
+ __FUNCTION__,found,i,j,k );
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_channel_id_using_mdl_id
+**
+** Description Find channel id using mdl_id'
+**
+** Returns BOOLEAN
+*********************************************************************************/
+BOOLEAN btif_hl_find_channel_id_using_mdl_id(UINT8 app_idx, tBTA_HL_MDL_ID mdl_id,
+ int *p_channel_id){
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mdl_cfg_t *p_mdl;
+ BOOLEAN found=FALSE;
+ UINT8 j=0;
+ int mdl_cfg_channel_id;
+ p_acb =BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb && p_acb->in_use)
+ {
+ for (j=0; j< BTA_HL_NUM_MDL_CFGS; j++)
+ {
+ p_mdl =BTIF_HL_GET_MDL_CFG_PTR(app_idx,j);
+ mdl_cfg_channel_id = *(BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx,j));
+ if ( p_mdl->base.active && (p_mdl->base.mdl_id == mdl_id))
+ {
+ found = TRUE;
+ *p_channel_id = mdl_cfg_channel_id;
+ break;
+ }
+ }
+ }
+ BTIF_TRACE_EVENT6("%s found=%d channel_id=0x%08x, mdl_id=0x%x app_idx=%d mdl_cfg_idx=%d ",
+ __FUNCTION__,found,*p_channel_id,mdl_id, app_idx,j );
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_find_mdl_idx_using_handle
+**
+** Description Find the MDL index using handle
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+ UINT8 *p_app_idx,UINT8 *p_mcl_idx,
+ UINT8 *p_mdl_idx){
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_mdl_cb_t *p_dcb;
+ BOOLEAN found=FALSE;
+ UINT8 i,j,k;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ p_acb =BTIF_HL_GET_APP_CB_PTR(i);
+ for (j=0; j< BTA_HL_NUM_MCLS; j++)
+ {
+ p_mcb =BTIF_HL_GET_MCL_CB_PTR(i,j);
+ for (k=0; k< BTA_HL_NUM_MDLS_PER_MCL; k++)
+ {
+ p_dcb =BTIF_HL_GET_MDL_CB_PTR(i,j,k);
+ if (p_acb->in_use &&
+ p_mcb->in_use &&
+ p_dcb->in_use &&
+ (p_dcb->mdl_handle == mdl_handle))
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ *p_mcl_idx =j;
+ *p_mdl_idx = k;
+ break;
+ }
+ }
+ }
+ }
+
+
+ BTIF_TRACE_EVENT5("%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d ",
+ __FUNCTION__,found,i,j,k );
+ return found;
+}
+/*******************************************************************************
+**
+** Function btif_hl_find_peer_mdep_id
+**
+** Description Find the peer MDEP ID from the received SPD records
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_find_peer_mdep_id(UINT8 app_id, BD_ADDR bd_addr,
+ tBTA_HL_MDEP_ROLE local_mdep_role,
+ UINT16 data_type,
+ tBTA_HL_MDEP_ID *p_peer_mdep_id){
+ UINT8 app_idx, mcl_idx;
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ tBTA_HL_SDP_REC *p_rec;
+ UINT8 i, num_mdeps;
+ BOOLEAN found = FALSE;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+
+
+ BTIF_TRACE_DEBUG4("%s app_id=%d local_mdep_role=%d, data_type=%d",
+ __FUNCTION__, app_id, local_mdep_role, data_type);
+
+ BTIF_TRACE_DEBUG6("DB [%02x:%02x:%02x:%02x:%02x:%02x]",
+ bd_addr[0], bd_addr[1],
+ bd_addr[2], bd_addr[3],
+ bd_addr[4], bd_addr[5]);
+
+
+ BTIF_TRACE_DEBUG1("local_mdep_role=%d", local_mdep_role);
+ BTIF_TRACE_DEBUG1("data_type=%d", data_type);
+
+ if (local_mdep_role == BTA_HL_MDEP_ROLE_SINK)
+ peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ else
+ peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+
+ if (btif_hl_find_app_idx(app_id, &app_idx) )
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx))
+ {
+ p_mcb =BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ BTIF_TRACE_DEBUG2("app_idx=%d mcl_idx=%d",app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG2("valid_spd_idx=%d sdp_idx=%d",p_mcb->valid_sdp_idx, p_mcb->sdp_idx);
+ if (p_mcb->valid_sdp_idx)
+ {
+ p_rec = &p_mcb->sdp.sdp_rec[p_mcb->sdp_idx];
+ num_mdeps = p_rec->num_mdeps;
+ BTIF_TRACE_DEBUG1("num_mdeps=%d", num_mdeps);
+
+ for (i=0; i< num_mdeps; i++)
+ {
+ BTIF_TRACE_DEBUG2("p_rec->mdep_cfg[%d].mdep_role=%d",i, p_rec->mdep_cfg[i].mdep_role);
+ BTIF_TRACE_DEBUG2("p_rec->mdep_cfg[%d].data_type =%d",i, p_rec->mdep_cfg[i].data_type );
+ if ((p_rec->mdep_cfg[i].mdep_role == peer_mdep_role) &&
+ (p_rec->mdep_cfg[i].data_type == data_type))
+ {
+ found = TRUE;
+ *p_peer_mdep_id = p_rec->mdep_cfg[i].mdep_id;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG2("found =%d *p_peer_mdep_id=%d", found, *p_peer_mdep_id);
+
+ return found;
+}
+/*******************************************************************************
+**
+** Function btif_hl_find_local_mdep_id
+**
+** Description Find the local MDEP ID from the MDEP configuration
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_find_local_mdep_id(UINT8 app_id,
+ tBTA_HL_MDEP_ROLE local_mdep_role,
+ UINT16 mdep_data_type,
+ tBTA_HL_MDEP_ID *p_local_mdep_id){
+ UINT8 app_idx;
+ btif_hl_app_cb_t *p_acb;
+ UINT8 i,j;
+ BOOLEAN found = FALSE;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx) )
+ {
+ p_acb =BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ for (i=0; i< p_acb->sup_feature.num_of_mdeps; i++)
+ {
+ if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role == local_mdep_role )
+ {
+ for (j=0; j< p_acb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types; j++)
+ {
+ if ( p_acb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type == mdep_data_type)
+ {
+ found = TRUE;
+ *p_local_mdep_id = p_acb->sup_feature.mdep[i].mdep_id;
+ return found;
+ }
+ }
+ }
+ }
+
+
+ }
+ BTIF_TRACE_DEBUG2("found=%d local mdep id=%d", found, *p_local_mdep_id );
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_mdep_cfg_idx
+**
+** Description Find the MDEP configuration index using local MDEP_ID
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_find_mdep_cfg_idx(UINT8 app_idx, tBTA_HL_MDEP_ID local_mdep_id,
+ UINT8 *p_mdep_cfg_idx){
+ btif_hl_app_cb_t *p_acb =BTIF_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_SUP_FEATURE *p_sup_feature= &p_acb->sup_feature;
+ BOOLEAN found =FALSE;
+ UINT8 i;
+
+ for (i=0; i< p_sup_feature->num_of_mdeps; i++)
+ {
+ if ( p_sup_feature->mdep[i].mdep_id == local_mdep_id)
+ {
+ found = TRUE;
+ *p_mdep_cfg_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG4("%s found=%d mdep_idx=%d local_mdep_id=%d ",
+ __FUNCTION__, found,i, local_mdep_id );
+ return found;
+}
+
+
+
+/*******************************************************************************
+**
+** Function btif_hl_find_mcl_idx
+**
+** Description Find the MCL index using BD address
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_mcl_idx(UINT8 app_idx, BD_ADDR p_bd_addr, UINT8 *p_mcl_idx){
+ BOOLEAN found=FALSE;
+ UINT8 i;
+ btif_hl_app_cb_t *p_acb =BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_mcl_cb_t *p_mcb;
+
+ for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, i);
+ if (p_mcb->in_use &&
+ (!memcmp (p_mcb->bd_addr, p_bd_addr, BD_ADDR_LEN)))
+ {
+ found = TRUE;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+
+
+ BTIF_TRACE_DEBUG3("%s found=%d idx=%d",__FUNCTION__, found, i);
+ return found;
+}
+/*******************************************************************************
+**
+** Function btif_hl_init
+**
+** Description HL initialization function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_init(void){
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ memset(p_btif_hl_cb, 0, sizeof(btif_hl_cb_t));
+ btif_hl_init_next_app_id();
+ btif_hl_init_next_channel_id();
+}
+/*******************************************************************************
+**
+** Function btif_hl_disable
+**
+** Description Disable initialization function.
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_disable(void){
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if ((p_btif_hl_cb->state != BTIF_HL_STATE_DISABLING) &&
+ (p_btif_hl_cb->state != BTIF_HL_STATE_DISABLED))
+ {
+ btif_hl_set_state(BTIF_HL_STATE_DISABLING);
+ BTA_HlDisable();
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_is_no_active_app
+**
+** Description Find whether or not any APP is still in use
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_is_no_active_app(void){
+ BOOLEAN no_active_app = TRUE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ if (btif_hl_cb.acb[i].in_use)
+ {
+ no_active_app = FALSE;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG2("%s no_active_app=%d ", __FUNCTION__, no_active_app );
+ return no_active_app;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_free_app_idx
+**
+** Description free an application control block
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_free_app_idx(UINT8 app_idx){
+
+ if ((app_idx < BTA_HL_NUM_APPS) && btif_hl_cb.acb[app_idx].in_use )
+ {
+ btif_hl_cb.acb[app_idx].in_use = FALSE;
+ memset (&btif_hl_cb.acb[app_idx], 0, sizeof(btif_hl_app_cb_t));
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_set_state
+**
+** Description set HL state
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_set_state(btif_hl_state_t state){
+ BTIF_TRACE_DEBUG2("btif_hl_set_state: %d ---> %d ", p_btif_hl_cb->state, state);
+ p_btif_hl_cb->state = state;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_set_state
+**
+** Description get HL state
+**
+** Returns btif_hl_state_t
+**
+*******************************************************************************/
+
+static btif_hl_state_t btif_hl_get_state(void){
+ BTIF_TRACE_DEBUG1("btif_hl_get_state: %d ", p_btif_hl_cb->state);
+ return p_btif_hl_cb->state;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_data_type_idx
+**
+** Description Find the index in the data type table
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_find_data_type_idx(UINT16 data_type, UINT8 *p_idx){
+ BOOLEAN found = FALSE;
+ UINT8 i;
+
+ for (i=0; i< BTIF_HL_DATA_TABLE_SIZE; i++ )
+ {
+ if (data_type_table[i].data_type == data_type)
+ {
+ found = TRUE;
+ *p_idx= i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG4("%s found=%d, data_type=0x%x idx=%d", __FUNCTION__, found, data_type, i);
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_get_max_tx_apdu_size
+**
+** Description Find the maximum TX APDU size for the specified data type and
+** MDEP role
+**
+** Returns UINT16
+**
+*******************************************************************************/
+UINT16 btif_hl_get_max_tx_apdu_size(tBTA_HL_MDEP_ROLE mdep_role,
+ UINT16 data_type ){
+ UINT8 idx;
+ UINT16 max_tx_apdu_size =0;
+
+ if (btif_hl_find_data_type_idx(data_type, &idx))
+ {
+ if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+ {
+ max_tx_apdu_size = data_type_table[idx].max_tx_apdu_size;
+ }
+ else
+ {
+ max_tx_apdu_size = data_type_table[idx].max_rx_apdu_size;
+ }
+ }
+ else
+ {
+ if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+ {
+ max_tx_apdu_size = BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE;
+ }
+ else
+ {
+ max_tx_apdu_size = BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE;
+ }
+
+
+ }
+
+ BTIF_TRACE_DEBUG4("%s mdep_role=%d data_type=0x%4x size=%d",
+ __FUNCTION__, mdep_role, data_type, max_tx_apdu_size);
+ return max_tx_apdu_size;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_get_max_rx_apdu_size
+**
+** Description Find the maximum RX APDU size for the specified data type and
+** MDEP role
+**
+** Returns UINT16
+**
+*******************************************************************************/
+UINT16 btif_hl_get_max_rx_apdu_size(tBTA_HL_MDEP_ROLE mdep_role,
+ UINT16 data_type ){
+ UINT8 idx;
+ UINT16 max_rx_apdu_size =0;
+
+ if (btif_hl_find_data_type_idx(data_type, &idx))
+ {
+ if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+ {
+ max_rx_apdu_size = data_type_table[idx].max_rx_apdu_size;
+ }
+ else
+ {
+ max_rx_apdu_size = data_type_table[idx].max_tx_apdu_size;
+ }
+ }
+ else
+ {
+ if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+ {
+ max_rx_apdu_size = BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE;
+ }
+ else
+ {
+ max_rx_apdu_size = BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE;
+ }
+ }
+
+
+ BTIF_TRACE_DEBUG4("%s mdep_role=%d data_type=0x%4x size=%d",
+ __FUNCTION__, mdep_role, data_type, max_rx_apdu_size);
+
+ return max_rx_apdu_size;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_if_channel_setup_pending
+**
+** Description
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+static BOOLEAN btif_hl_get_bta_mdep_role(bthl_mdep_role_t mdep, tBTA_HL_MDEP_ROLE *p){
+ BOOLEAN status = TRUE;
+ switch (mdep)
+ {
+ case BTHL_MDEP_ROLE_SOURCE:
+ *p = BTA_HL_MDEP_ROLE_SOURCE;
+ break;
+ case BTHL_MDEP_ROLE_SINK:
+ *p = BTA_HL_MDEP_ROLE_SINK;
+ break;
+ default:
+ status = FALSE;
+ break;
+ }
+
+ BTIF_TRACE_DEBUG4("%s status=%d bta_mdep_role=%d (%d:btif)",
+ __FUNCTION__, status, *p, mdep);
+ return status;
+}
+/*******************************************************************************
+**
+** Function btif_hl_get_bta_channel_type
+**
+** Description convert bthl channel type to BTA DCH channel type
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+
+static BOOLEAN btif_hl_get_bta_channel_type(bthl_channel_type_t channel_type, tBTA_HL_DCH_CFG *p){
+ BOOLEAN status = TRUE;
+ switch (channel_type)
+ {
+ case BTHL_CHANNEL_TYPE_RELIABLE:
+ *p = BTA_HL_DCH_CFG_RELIABLE;
+ break;
+ case BTHL_CHANNEL_TYPE_STREAMING:
+ *p = BTA_HL_DCH_CFG_STREAMING;
+ break;
+ case BTHL_CHANNEL_TYPE_ANY:
+ *p = BTA_HL_DCH_CFG_NO_PREF;
+ break;
+ default:
+ status = FALSE;
+ break;
+ }
+ BTIF_TRACE_DEBUG3("%s status = %d BTA DCH CFG=%d (1-rel 2-strm",
+ __FUNCTION__, status, *p);
+ return status;
+}
+/*******************************************************************************
+**
+** Function btif_hl_get_next_app_id
+**
+** Description get next applcation id
+**
+** Returns UINT8
+**
+*******************************************************************************/
+
+static UINT8 btif_hl_get_next_app_id(){
+ UINT8 next_app_id = btif_hl_cb.next_app_id;
+
+ btif_hl_cb.next_app_id++;
+ return next_app_id;
+}
+/*******************************************************************************
+**
+** Function btif_hl_get_next_channel_id
+**
+** Description get next channel id
+**
+** Returns int
+**
+*******************************************************************************/
+static int btif_hl_get_next_channel_id(UINT8 app_id){
+ UINT16 next_channel_id = btif_hl_cb.next_channel_id;
+ int channel_id;
+ btif_hl_cb.next_channel_id++;
+ channel_id = (app_id << 16) + next_channel_id;
+ BTIF_TRACE_DEBUG4("%s channel_id=0x%08x, app_id=0x%02x next_channel_id=0x%04x", __FUNCTION__,
+ channel_id, app_id, next_channel_id);
+ return channel_id;
+}
+/*******************************************************************************
+**
+** Function btif_hl_get_app_id
+**
+** Description get the applicaiton id associated with the channel id
+**
+** Returns UINT8
+**
+*******************************************************************************/
+
+static UINT8 btif_hl_get_app_id(int channel_id){
+ UINT8 app_id =(UINT8) (channel_id >> 16);
+ BTIF_TRACE_DEBUG3("%s channel_id=0x%08x, app_id=0x%02x ", __FUNCTION__,channel_id, app_id);
+ return app_id;
+}
+/*******************************************************************************
+**
+** Function btif_hl_init_next_app_id
+**
+** Description initialize the application id
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_init_next_app_id(void){
+ btif_hl_cb.next_app_id = 1;
+}
+/*******************************************************************************
+**
+** Function btif_hl_init_next_channel_id
+**
+** Description initialize the channel id
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_init_next_channel_id(void){
+ btif_hl_cb.next_channel_id = 1;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_save_mdl_cfg
+**
+** Description Save the MDL configuration
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_save_mdl_cfg(UINT8 app_id, UINT8 item_idx,
+ tBTA_HL_MDL_CFG *p_mdl_cfg){
+ btif_hl_mdl_cfg_t *p_mdl=NULL;
+ BOOLEAN success = FALSE;
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ UINT8 app_idx, mcl_idx, mdl_idx, len;
+ bt_status_t bt_status;
+ btif_hl_evt_cb_t evt_param;
+ int *p_channel_id;
+
+ BTIF_TRACE_DEBUG6("%s app_ids=%d item_idx=%d, local_mdep_id=%d mdl_id=0x%x dch_mode=%d",
+ __FUNCTION__, app_id, item_idx, p_mdl_cfg->local_mdep_id,
+ p_mdl_cfg->mdl_id, p_mdl_cfg->dch_mode );
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx);
+ p_channel_id = BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, item_idx);
+ if (p_mdl)
+ {
+ memcpy(&p_mdl->base, p_mdl_cfg, sizeof(tBTA_HL_MDL_CFG));
+ if (btif_hl_find_mcl_idx(app_idx, p_mdl->base.peer_bd_addr , &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->pcb.in_use)
+ *p_channel_id = p_mcb->pcb.channel_id;
+ else
+ *p_channel_id = btif_hl_get_next_channel_id(p_acb->app_id);
+ p_mdl->extra.mdep_cfg_idx = p_mcb->pcb.mdep_cfg_idx;
+ p_mdl->extra.data_type = p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx].mdep_cfg.data_cfg[0].data_type;
+
+ if (!btif_hl_find_peer_mdep_id(p_acb->app_id, p_mcb->bd_addr,
+ p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx].mdep_cfg.mdep_role,
+ p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx].mdep_cfg.data_cfg[0].data_type,
+ &p_mdl->extra.peer_mdep_id))
+ {
+ p_mdl->extra.peer_mdep_id = BTA_HL_INVALID_MDEP_ID;
+ }
+ BTIF_TRACE_DEBUG4("%s app_idx=%d item_idx=%d mld_id=0x%x",
+ __FUNCTION__, app_idx, item_idx, p_mdl->base.mdl_id);
+ evt_param.update_mdl.app_idx = app_idx;
+ len = sizeof(btif_hl_update_mdl_t);
+ BTIF_TRACE_DEBUG1("send BTIF_HL_UPDATE_MDL event app_idx=%d ",app_idx);
+ if ((bt_status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_UPDATE_MDL,
+ (char*) &evt_param, len, NULL)) == BT_STATUS_SUCCESS)
+ {
+ success = TRUE;
+ }
+ ASSERTC(bt_status == BT_STATUS_SUCCESS, "context transfer failed", bt_status);
+ }
+ }
+ }
+ BTIF_TRACE_DEBUG2("%s success=%d ",__FUNCTION__, success );
+
+ return success;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_delete_mdl_cfg
+**
+** Description Delete the MDL configuration
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_delete_mdl_cfg(UINT8 app_id, UINT8 item_idx){
+ btif_hl_mdl_cfg_t *p_mdl=NULL;
+ BOOLEAN success = FALSE;
+ btif_hl_app_cb_t *p_acb;
+ UINT8 app_idx, len;
+ bt_status_t bt_status;
+ btif_hl_evt_cb_t evt_param;
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx);
+ if (p_mdl)
+ {
+ memset(p_mdl, 0, sizeof(btif_hl_mdl_cfg_t));
+ evt_param.update_mdl.app_idx = app_idx;
+ len = sizeof(btif_hl_update_mdl_t);
+ BTIF_TRACE_DEBUG1("send BTIF_HL_UPDATE_MDL event app_idx=%d ",app_idx);
+ if ((bt_status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_UPDATE_MDL,
+ (char*) &evt_param, len, NULL)) == BT_STATUS_SUCCESS)
+ {
+ success = TRUE;
+ }
+ ASSERTC(bt_status == BT_STATUS_SUCCESS, "context transfer failed", bt_status);
+ }
+ }
+
+ BTIF_TRACE_DEBUG2("%s success=%d ",__FUNCTION__, success );
+ return success;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_app_idx_using_handle
+**
+** Description Find the applicaiton index using handle
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+ UINT8 *p_app_idx){
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ if (btif_hl_cb.acb[i].in_use &&
+ (btif_hl_cb.acb[i].app_handle == app_handle))
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_EVENT4("%s status=%d handle=%d app_idx=%d ",
+ __FUNCTION__, found, app_handle , i);
+
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_mcl_idx_using_handle
+**
+** Description Find the MCL index using handle
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_mcl_idx_using_handle( tBTA_HL_MCL_HANDLE mcl_handle,
+ UINT8 *p_app_idx, UINT8 *p_mcl_idx){
+ btif_hl_app_cb_t *p_acb;
+ BOOLEAN found=FALSE;
+ UINT8 i,j;
+
+ for (i=0; i<BTA_HL_NUM_APPS; i++)
+ {
+ p_acb =BTIF_HL_GET_APP_CB_PTR(i);
+ for (j=0; j < BTA_HL_NUM_MCLS ; j++)
+ {
+ if (p_acb->mcb[j].in_use &&
+ (p_acb->mcb[j].mcl_handle == mcl_handle))
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ break;
+ }
+ }
+ }
+ BTIF_TRACE_DEBUG4("%s found=%d app_idx=%d mcl_idx=%d",__FUNCTION__,
+ found, i, j);
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_app_idx
+**
+** Description Find the application index using application ID
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_app_idx(UINT8 app_id, UINT8 *p_app_idx){
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+
+ if (btif_hl_cb.acb[i].in_use &&
+ (btif_hl_cb.acb[i].app_id == app_id))
+ {
+ found = TRUE;
+ *p_app_idx = i;
+ break;
+ }
+ }
+ BTIF_TRACE_DEBUG3("%s found=%d app_idx=%d", __FUNCTION__, found, i );
+
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_find_avail_mdl_idx
+**
+** Description Find a not in-use MDL index
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_avail_mdl_idx(UINT8 app_idx, UINT8 mcl_idx,
+ UINT8 *p_mdl_idx){
+ btif_hl_mcl_cb_t *p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
+ {
+ if (!p_mcb->mdl[i].in_use)
+ {
+ btif_hl_clean_mdl_cb(&p_mcb->mdl[i]);
+ found = TRUE;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG3("%s found=%d idx=%d",__FUNCTION__, found, i);
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_avail_mcl_idx
+**
+** Description Find a not in-use MDL index
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_avail_mcl_idx(UINT8 app_idx, UINT8 *p_mcl_idx){
+ BOOLEAN found=FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_MCLS ; i ++)
+ {
+ if (!btif_hl_cb.acb[app_idx].mcb[i].in_use)
+ {
+ found = TRUE;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+ BTIF_TRACE_DEBUG3("%s found=%d app_idx=%d", __FUNCTION__, found, i);
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_avail_app_idx
+**
+** Description Find a not in-use APP index
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_find_avail_app_idx(UINT8 *p_idx){
+ BOOLEAN found = FALSE;
+ UINT8 i;
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ if (!btif_hl_cb.acb[i].in_use)
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG3("%s found=%d app_idx=%d", __FUNCTION__, found, i);
+ return found;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_dereg_cfm
+**
+** Description Process the de-registration confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_dereg_cfm(tBTA_HL *p_data)
+
+{
+ btif_hl_app_cb_t *p_acb;
+ UINT8 app_idx;
+ int app_id = 0;
+ bthl_app_reg_state_t state = BTHL_APP_REG_STATE_DEREG_SUCCESS;
+ BTIF_TRACE_DEBUG3("%s de-reg status=%d app_handle=%d", __FUNCTION__, p_data->dereg_cfm.status, p_data->dereg_cfm.app_handle);
+
+ if (btif_hl_find_app_idx_using_handle(p_data->dereg_cfm.app_handle, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ app_id = (int) p_acb->app_id;
+ if (p_data->dereg_cfm.status == BTA_HL_STATUS_OK)
+ memset(p_acb, 0,sizeof(btif_hl_app_cb_t));
+ else
+ state = BTHL_APP_REG_STATE_DEREG_FAILED;
+
+ BTIF_TRACE_DEBUG2("call reg state callback app_id=%d state=%d", app_id, state);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, app_reg_state_cb, app_id, state );
+
+ if (btif_hl_is_no_active_app())
+ {
+ btif_hl_disable();
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_find_non_ative_app_nv_idx
+**
+** Description find a non-active applicaiton NV index
+**
+** Returns BOOLEAN TRUE-found
+**
+*******************************************************************************/
+
+BOOLEAN btif_hl_find_non_ative_app_nv_idx(UINT8 *p_idx){
+ BOOLEAN found = FALSE;
+ UINT8 i, cur_nv_idx=0;
+ UINT16 cur_use_freq =0xFFFF;
+ btif_hl_app_data_t *p_data;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (!GKI_queue_is_empty(&p_ncb->app_queue))
+ {
+ p_data = (btif_hl_app_data_t *)GKI_getfirst((void *)&p_ncb->app_queue);
+ while (p_data != NULL)
+ {
+ if (!p_data->active)
+ {
+ found = TRUE;
+ /* find least used app_nv_idx */
+ if (cur_use_freq >= p_ncb->app_cb.app[p_data->app_nv_idx].use_freq)
+ {
+ cur_use_freq = p_ncb->app_cb.app[p_data->app_nv_idx].use_freq;
+ *p_idx = p_data->app_nv_idx;
+ }
+ }
+ p_data = (btif_hl_app_data_t *)GKI_getnext((void *)p_data);
+ }
+ }
+
+
+ BTIF_TRACE_DEBUG2(" found=%d idx=%d", found , *p_idx);
+ return found;
+}
+/*******************************************************************************
+**
+** Function btif_hl_find_avail_app_nv_idx
+**
+** Description find a not in use applicaiton NV index
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_find_avail_app_nv_idx(UINT8 *p_idx){
+ BOOLEAN found = FALSE;
+ UINT8 i, first_idx;
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ for (i=0;i<BTIF_HL_NV_MAX_APPS; i++)
+ {
+ if (!p_ncb->app_cb.app[i].in_use)
+ {
+ found = TRUE;
+ *p_idx = i;
+ break;
+ }
+ }
+
+ if (!found )
+ btif_hl_find_non_ative_app_nv_idx (p_idx);
+
+ BTIF_TRACE_DEBUG2(" found=%d idx=%d", found , *p_idx);
+ return found;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_save_app_data
+**
+** Description Save an applicaiton registration data into NV
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_save_app_data(UINT8 app_idx){
+ BOOLEAN status = FALSE;
+ btif_hl_app_cb_t *p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_app_data_t *p_data = GKI_getbuf((UINT16)sizeof( btif_hl_app_data_t));
+ btif_hl_nv_app_data_t *p_app;
+ UINT8 app_nv_idx;
+ bt_status_t bt_status;
+
+ BTIF_TRACE_DEBUG4("%s app_idx=%d p_acb=0x%x p_data=0x%x", __FUNCTION__, app_idx, p_acb, p_data);
+
+ if (p_acb && p_data && btif_hl_find_avail_app_nv_idx(&app_nv_idx))
+ {
+ BTIF_TRACE_DEBUG1("app_nv_idx=%d ",app_nv_idx );
+ p_app = &p_data->app_data;
+
+ memcpy(p_app->application_name, p_acb->application_name, (BTIF_HL_APPLICATION_NAME_LEN +1) );
+ memcpy(p_app->provider_name, p_acb->provider_name, (BTA_PROVIDER_NAME_LEN +1) );
+ memcpy(p_app->srv_name, p_acb->srv_name, (BTA_SERVICE_NAME_LEN +1) );
+ memcpy(p_app->srv_desp, p_acb->srv_desp, (BTA_SERVICE_DESP_LEN +1) );
+ memcpy(p_app->channel_type, p_acb->channel_type, (sizeof(tBTA_HL_DCH_CFG)*BTA_HL_NUM_MDEPS));
+ memcpy((void *) &p_app->sup_feature, (void *) &p_acb->sup_feature, sizeof(tBTA_HL_SUP_FEATURE));
+
+
+ if ((bt_status = btif_storage_write_hl_app_data(app_nv_idx,(char *) p_app,
+ sizeof(btif_hl_nv_app_data_t)))== BT_STATUS_SUCCESS)
+ {
+ if ((bt_status = btif_storage_write_hl_mdl_data(app_nv_idx,(char *) &p_acb->mdl_cfg[0],
+ sizeof(btif_hl_nv_mdl_data_t)))== BT_STATUS_SUCCESS)
+ {
+ p_ncb->app_cb.app[app_nv_idx].in_use = TRUE;
+ p_ncb->app_cb.app[app_nv_idx].use_freq = 1;
+ if ((bt_status = btif_storage_write_hl_apps_cb((char *) &p_ncb->app_cb,
+ sizeof(btif_hl_nv_app_cb_t)))== BT_STATUS_SUCCESS)
+ {
+ status = TRUE;
+ p_data->active = TRUE;
+ p_acb->app_nv_idx =
+ p_data->app_nv_idx = app_nv_idx;
+ p_data->app_idx = app_idx;
+
+ BTIF_TRACE_DEBUG2("p_data active=TRUE app_nv_idx =%d app_idx=%d ",app_nv_idx, app_idx );
+ GKI_enqueue(&p_ncb->app_queue,p_data);
+
+
+ }
+ else
+ {
+ p_ncb->app_cb.app[app_nv_idx].in_use = FALSE;
+ }
+ }
+ }
+ }
+
+ if (!status)
+ btif_hl_free_buf((void **) &p_data);
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_reg_cfm
+**
+** Description Process the registration confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_reg_cfm(tBTA_HL *p_data){
+ btif_hl_app_cb_t *p_acb;
+ UINT8 app_idx;
+ bthl_app_reg_state_t state = BTHL_APP_REG_STATE_REG_SUCCESS;
+ bt_status_t bt_status;
+
+ BTIF_TRACE_DEBUG3("%s reg status=%d app_handle=%d", __FUNCTION__, p_data->reg_cfm.status, p_data->reg_cfm.app_handle);
+
+ if (btif_hl_find_app_idx(p_data->reg_cfm.app_id, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ if (p_data->reg_cfm.status == BTA_HL_STATUS_OK)
+ {
+ p_acb->app_handle = p_data->reg_cfm.app_handle;
+ BTIF_TRACE_DEBUG1("is_new_app=%d", p_acb->is_new_app);
+ if (p_acb->is_new_app)
+ {
+ p_acb->is_new_app = FALSE;
+ if (!btif_hl_save_app_data(app_idx))
+ {
+ ASSERTC(FALSE, "Unable to save app data app_idx=%d", app_idx);
+ state = BTHL_APP_REG_STATE_REG_FAILED;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG3("Increase the use freq app_idx=%d app_nv_idx=%d cur_use_freq=%d",
+ app_idx, p_acb->app_nv_idx, p_ncb->app_cb.app[p_acb->app_nv_idx].use_freq);
+ if (p_ncb->app_cb.app[p_acb->app_nv_idx].use_freq != 0xFFFF )
+ p_ncb->app_cb.app[p_acb->app_nv_idx].use_freq ++;
+
+ p_ncb->app_cb.app[p_acb->app_nv_idx].in_use = TRUE;
+ if ((bt_status = btif_storage_write_hl_apps_cb((char *) &p_ncb->app_cb,
+ sizeof(btif_hl_nv_app_cb_t)))!= BT_STATUS_SUCCESS)
+ {
+ ASSERTC(bt_status == BT_STATUS_SUCCESS, "Unable to save app_cb into NV app_nv_idx=%d ", p_acb->app_nv_idx);
+ state = BTHL_APP_REG_STATE_REG_FAILED;
+ }
+ }
+
+ if (state == BTHL_APP_REG_STATE_REG_FAILED)
+ {
+ BTA_HlDeregister(p_acb->app_handle);
+ btif_hl_free_app_idx(app_idx);
+ }
+ }
+ else
+ {
+ btif_hl_free_app_idx(app_idx);
+ state = BTHL_APP_REG_STATE_REG_FAILED;
+ }
+
+ BTIF_TRACE_DEBUG3("%s call reg state callback app_id=%d reg state=%d", __FUNCTION__, p_data->reg_cfm.app_id, state);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, app_reg_state_cb, ((int) p_data->reg_cfm.app_id), state );
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_sdp_info_ind
+**
+** Description Process the SDP info indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_sdp_info_ind(tBTA_HL *p_data)
+
+{
+ btif_hl_app_cb_t *p_acb;
+ UINT8 app_idx;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ if (btif_hl_find_app_idx_using_handle(p_data->sdp_info_ind.app_handle, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ memcpy(&p_acb->sdp_info_ind, &p_data->sdp_info_ind, sizeof(tBTA_HL_SDP_INFO_IND));
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_set_chan_cb_state
+**
+** Description set the channel callback state
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_set_chan_cb_state(UINT8 app_idx, UINT8 mcl_idx, btif_hl_chan_cb_state_t state){
+ btif_hl_pending_chan_cb_t *p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ btif_hl_chan_cb_state_t cur_state = p_pcb->cb_state;
+
+ if (cur_state != state)
+ {
+ p_pcb->cb_state = state;
+ BTIF_TRACE_DEBUG3("%s state %d--->%d",__FUNCTION__, cur_state, state);
+ }
+
+
+}
+/*******************************************************************************
+**
+** Function btif_hl_send_destroyed_cb
+**
+** Description send the channel destroyed callback
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_send_destroyed_cb(btif_hl_app_cb_t *p_acb ){
+ bt_bdaddr_t bd_addr;
+ int app_id = (int) btif_hl_get_app_id(p_acb->delete_mdl.channel_id);
+
+ btif_hl_copy_bda(&bd_addr, p_acb->delete_mdl.bd_addr);
+ BTIF_TRACE_DEBUG1("%s",__FUNCTION__);
+ BTIF_TRACE_DEBUG4("call channel state callback channel_id=0x%08x mdep_cfg_idx=%d, state=%d fd=%d",p_acb->delete_mdl.channel_id,
+ p_acb->delete_mdl.mdep_cfg_idx, BTHL_CONN_STATE_DESTROYED, 0);
+ btif_hl_display_bt_bda(&bd_addr);
+
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id,
+ &bd_addr, p_acb->delete_mdl.mdep_cfg_idx,
+ p_acb->delete_mdl.channel_id, BTHL_CONN_STATE_DESTROYED, 0 );
+}
+/*******************************************************************************
+**
+** Function btif_hl_send_disconnecting_cb
+**
+** Description send a channel disconnecting callback
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_send_disconnecting_cb(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx){
+ btif_hl_mdl_cb_t *p_dcb = BTIF_HL_GET_MDL_CB_PTR( app_idx, mcl_idx, mdl_idx);
+ btif_hl_soc_cb_t *p_scb = p_dcb->p_scb;
+ bt_bdaddr_t bd_addr;
+ int app_id = (int) btif_hl_get_app_id(p_scb->channel_id);
+
+ btif_hl_copy_bda(&bd_addr, p_scb->bd_addr);
+
+ BTIF_TRACE_DEBUG1("%s",__FUNCTION__);
+ BTIF_TRACE_DEBUG4("call channel state callback channel_id=0x%08x mdep_cfg_idx=%d, state=%d fd=%d",p_scb->channel_id,
+ p_scb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTING, p_scb->socket_id[0]);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id,
+ &bd_addr, p_scb->mdep_cfg_idx,
+ p_scb->channel_id, BTHL_CONN_STATE_DISCONNECTING, p_scb->socket_id[0] );
+}
+/*******************************************************************************
+**
+** Function btif_hl_send_setup_connecting_cb
+**
+** Description send a channel connecting callback
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_send_setup_connecting_cb(UINT8 app_idx, UINT8 mcl_idx){
+ btif_hl_pending_chan_cb_t *p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ bt_bdaddr_t bd_addr;
+ int app_id = (int) btif_hl_get_app_id(p_pcb->channel_id);
+
+ btif_hl_copy_bda(&bd_addr, p_pcb->bd_addr);
+
+ if (p_pcb->in_use && p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING)
+ {
+ BTIF_TRACE_DEBUG1("%s",__FUNCTION__);
+ BTIF_TRACE_DEBUG4("call channel state callback channel_id=0x%08x mdep_cfg_idx=%d state=%d fd=%d",p_pcb->channel_id,
+ p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_CONNECTING, 0);
+ btif_hl_display_bt_bda(&bd_addr);
+
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id,
+ &bd_addr, p_pcb->mdep_cfg_idx,
+ p_pcb->channel_id, BTHL_CONN_STATE_CONNECTING, 0 );
+ btif_hl_set_chan_cb_state(app_idx, mcl_idx, BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING);
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_send_setup_disconnected_cb
+**
+** Description send a channel disconnected callback
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_send_setup_disconnected_cb(UINT8 app_idx, UINT8 mcl_idx){
+ btif_hl_pending_chan_cb_t *p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ bt_bdaddr_t bd_addr;
+ int app_id = (int) btif_hl_get_app_id(p_pcb->channel_id);
+
+ btif_hl_copy_bda(&bd_addr, p_pcb->bd_addr);
+
+ BTIF_TRACE_DEBUG2("%s p_pcb->in_use=%d",__FUNCTION__, p_pcb->in_use);
+ if (p_pcb->in_use)
+ {
+ BTIF_TRACE_DEBUG1("%p_pcb->cb_state=%d",p_pcb->cb_state);
+ if (p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING)
+ {
+ BTIF_TRACE_DEBUG4("call channel state callback channel_id=0x%08x mdep_cfg_idx=%d state=%d fd=%d",p_pcb->channel_id,
+ p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_CONNECTING, 0);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id,
+ &bd_addr, p_pcb->mdep_cfg_idx,
+ p_pcb->channel_id, BTHL_CONN_STATE_CONNECTING, 0 );
+
+ BTIF_TRACE_DEBUG4("call channel state callback channel_id=0x%08x mdep_cfg_idx=%d state=%d fd=%d",p_pcb->channel_id,
+ p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTED, 0);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id,
+ &bd_addr, p_pcb->mdep_cfg_idx,
+ p_pcb->channel_id, BTHL_CONN_STATE_DISCONNECTED, 0 );
+ }
+ else if (p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING)
+ {
+ BTIF_TRACE_DEBUG4("call channel state callback channel_id=0x%08x mdep_cfg_idx=%d state=%d fd=%d",p_pcb->channel_id,
+ p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTED, 0);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id,
+ &bd_addr, p_pcb->mdep_cfg_idx,
+ p_pcb->channel_id, BTHL_CONN_STATE_DISCONNECTED, 0 );
+ }
+ btif_hl_clean_pcb(p_pcb);
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_proc_sdp_query_cfm
+**
+** Description Process the SDP query confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_proc_sdp_query_cfm(tBTA_HL *p_data){
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ tBTA_HL_SDP *p_sdp;
+ tBTA_HL_CCH_OPEN_PARAM open_param;
+ UINT8 app_idx, mcl_idx, sdp_idx = 0;
+ UINT8 num_recs, i, num_mdeps, j;
+ btif_hl_cch_op_t old_cch_oper;
+ BOOLEAN status =FALSE;
+ btif_hl_pending_chan_cb_t *p_pcb;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ p_sdp = p_data->sdp_query_cfm.p_sdp;
+ num_recs = p_sdp->num_recs;
+
+ BTIF_TRACE_DEBUG1("num of SDP records=%d",num_recs);
+ for (i=0; i<num_recs; i++)
+ {
+ BTIF_TRACE_DEBUG3("rec_idx=%d ctrl_psm=0x%x data_psm=0x%x",
+ (i+1),p_sdp->sdp_rec[i].ctrl_psm, p_sdp->sdp_rec[i].data_psm);
+ BTIF_TRACE_DEBUG1("MCAP supported procedures=0x%x",p_sdp->sdp_rec[i].mcap_sup_proc);
+ num_mdeps = p_sdp->sdp_rec[i].num_mdeps;
+ BTIF_TRACE_DEBUG1("num of mdeps =%d",num_mdeps);
+ for (j=0; j< num_mdeps; j++)
+ {
+ BTIF_TRACE_DEBUG4("mdep_idx=%d mdep_id=0x%x data_type=0x%x mdep_role=0x%x",
+ (j+1),
+ p_sdp->sdp_rec[i].mdep_cfg[j].mdep_id,
+ p_sdp->sdp_rec[i].mdep_cfg[j].data_type,
+ p_sdp->sdp_rec[i].mdep_cfg[j].mdep_role );
+ }
+ }
+
+ if (btif_hl_find_app_idx_using_handle(p_data->sdp_query_cfm.app_handle, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ if (btif_hl_find_mcl_idx(app_idx, p_data->sdp_query_cfm.bd_addr, &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_oper != BTIF_HL_CCH_OP_NONE)
+ {
+ memcpy(&p_mcb->sdp, p_sdp, sizeof(tBTA_HL_SDP));
+ old_cch_oper = p_mcb->cch_oper;
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_NONE;
+
+ switch (old_cch_oper)
+ {
+ case BTIF_HL_CCH_OP_MDEP_FILTERING:
+ status = btif_hl_find_sdp_idx_using_mdep_filter(app_idx, mcl_idx, &sdp_idx);
+ break;
+ default:
+ break;
+ }
+
+ if (status)
+ {
+ p_mcb->sdp_idx = sdp_idx;
+ p_mcb->valid_sdp_idx = TRUE;
+ p_mcb->ctrl_psm = p_mcb->sdp.sdp_rec[sdp_idx].ctrl_psm;
+
+ switch (old_cch_oper)
+ {
+ case BTIF_HL_CCH_OP_MDEP_FILTERING:
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ if (p_pcb->in_use)
+ {
+ if (!p_pcb->abort_pending)
+ {
+ switch (p_pcb->op)
+ {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ open_param.ctrl_psm = p_mcb->ctrl_psm;
+ bdcpy(open_param.bd_addr, p_mcb->bd_addr);
+ open_param.sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ BTA_HlCchOpen(p_acb->app_handle, &open_param);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("channel abort pending");
+ }
+ }
+ break;
+
+ case BTIF_HL_CCH_OP_DCH_OPEN:
+ status = btif_hl_proc_pending_op(app_idx,mcl_idx);
+ break;
+
+ default:
+ BTIF_TRACE_ERROR1("Invalid CCH oper %d", old_cch_oper);
+ break;
+ }
+
+
+ }
+ else
+ {
+ BTIF_TRACE_ERROR0("Can not find SDP idx discard CCH Open request");
+ }
+ }
+ }
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_cch_open_ind
+**
+** Description Process the CCH open indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_cch_open_ind(tBTA_HL *p_data)
+
+{
+ btif_hl_mcl_cb_t *p_mcb;
+ UINT8 app_idx, mcl_idx;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ if (btif_hl_find_app_idx_using_handle(p_data->cch_open_ind.app_handle, &app_idx))
+ {
+ if (!btif_hl_find_mcl_idx(app_idx, p_data->cch_open_ind.bd_addr, &mcl_idx))
+ {
+ if (btif_hl_find_avail_mcl_idx(app_idx, &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
+ p_mcb->in_use = TRUE;
+ p_mcb->is_connected = TRUE;
+ p_mcb->mcl_handle = p_data->cch_open_ind.mcl_handle;
+ bdcpy(p_mcb->bd_addr, p_data->cch_open_ind.bd_addr);
+ btif_hl_start_cch_timer(app_idx, mcl_idx);
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR0("The MCL already exist for cch_open_ind");
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_pending_op
+**
+** Description Process the pending dch operation.
+**
+** Returns Nothing
+**
+*******************************************************************************/
+BOOLEAN btif_hl_proc_pending_op(UINT8 app_idx, UINT8 mcl_idx)
+
+{
+
+ btif_hl_app_cb_t *p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_mcl_cb_t *p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ btif_hl_pending_chan_cb_t *p_pcb;
+ BOOLEAN status = FALSE;
+ tBTA_HL_DCH_OPEN_PARAM dch_open;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_DCH_RECONNECT_PARAM reconnect_param;
+
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ if (p_pcb->in_use)
+ {
+ switch (p_pcb->op)
+ {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ if (!p_pcb->abort_pending)
+ {
+ BTIF_TRACE_DEBUG0("op BTIF_HL_PEND_DCH_OP_OPEN");
+ dch_open.ctrl_psm = p_mcb->ctrl_psm;
+ dch_open.local_mdep_id = p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx].mdep_id;
+ if (btif_hl_find_peer_mdep_id(p_acb->app_id, p_mcb->bd_addr,
+ p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx].mdep_cfg.mdep_role,
+ p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx].mdep_cfg.data_cfg[0].data_type, &dch_open.peer_mdep_id ))
+ {
+ dch_open.local_cfg = p_acb->channel_type[p_pcb->mdep_cfg_idx];
+ if ((p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+ && !btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx))
+ {
+ dch_open.local_cfg = BTA_HL_DCH_CFG_RELIABLE;
+ }
+ dch_open.sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ BTIF_TRACE_DEBUG1("dch_open.local_cfg=%d ", dch_open.local_cfg);
+ btif_hl_send_setup_connecting_cb(app_idx,mcl_idx);
+
+ if (!btif_hl_is_reconnect_possible(app_idx, mcl_idx, p_pcb->mdep_cfg_idx, &dch_open, &mdl_id ))
+ {
+ BTIF_TRACE_DEBUG0("Issue DCH open" );
+ BTA_HlDchOpen(p_mcb->mcl_handle, &dch_open);
+ }
+ else
+ {
+ reconnect_param.ctrl_psm = p_mcb->ctrl_psm;
+ reconnect_param.mdl_id = mdl_id;;
+ BTIF_TRACE_DEBUG2("Issue Reconnect ctrl_psm=0x%x mdl_id=0x%x",reconnect_param.ctrl_psm, reconnect_param.mdl_id);
+ BTA_HlDchReconnect(p_mcb->mcl_handle, &reconnect_param);
+ }
+ status = TRUE;
+ }
+ }
+ else
+ {
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ status = TRUE;
+ }
+ break;
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ BTA_HlDeleteMdl(p_mcb->mcl_handle, p_acb->delete_mdl.mdl_id);
+ status = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_cch_open_cfm
+**
+** Description Process the CCH open confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_proc_cch_open_cfm(tBTA_HL *p_data)
+
+{
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ UINT8 app_idx, mcl_idx;
+ BOOLEAN status = FALSE;
+ tBTA_HL_DCH_OPEN_PARAM dch_open;
+
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_app_idx_using_handle(p_data->cch_open_cfm.app_handle, &app_idx))
+ {
+ BTIF_TRACE_DEBUG1("app_idx=%d", app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, p_data->cch_open_cfm.bd_addr, &mcl_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG1("mcl_idx=%d", mcl_idx);
+ p_mcb->mcl_handle = p_data->cch_open_cfm.mcl_handle;
+ p_mcb->is_connected = TRUE;
+ status = btif_hl_proc_pending_op(app_idx, mcl_idx);
+ if (status)
+ btif_hl_start_cch_timer(app_idx, mcl_idx);
+ }
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_cch_close_ind
+**
+** Description Process the CCH close indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_cch_close_ind(tBTA_HL *p_data)
+
+{
+ UINT8 app_idx, mcl_idx;
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_mcl_idx_using_handle(p_data->cch_close_ind.mcl_handle, &app_idx, &mcl_idx))
+ {
+ btif_hl_stop_cch_timer(app_idx, mcl_idx);
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ btif_hl_release_mcl_sockets(app_idx, mcl_idx);
+ btif_hl_clean_mcl_cb(app_idx, mcl_idx);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_cch_close_cfm
+**
+** Description Process the CCH close confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_cch_close_cfm(tBTA_HL *p_data)
+{
+ UINT8 app_idx, mcl_idx;
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_mcl_idx_using_handle(p_data->cch_close_cfm.mcl_handle, &app_idx, &mcl_idx))
+ {
+ btif_hl_stop_cch_timer(app_idx, mcl_idx);
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ btif_hl_release_mcl_sockets(app_idx, mcl_idx);
+ btif_hl_clean_mcl_cb(app_idx, mcl_idx);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_create_ind
+**
+** Description Process the MDL create indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_create_ind(tBTA_HL *p_data){
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ tBTA_HL_MDEP *p_mdep;
+ UINT8 app_idx, mcl_idx, mdep_cfg_idx;
+ BOOLEAN first_reliable_exist;
+ BOOLEAN success = TRUE;
+ tBTA_HL_DCH_CFG rsp_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+ tBTA_HL_DCH_CREATE_RSP rsp_code = BTA_HL_DCH_CREATE_RSP_CFG_REJ;
+ tBTA_HL_DCH_CREATE_RSP_PARAM create_rsp_param;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_create_ind.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_acb =BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb =BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(app_idx, p_data->dch_create_ind.local_mdep_id, &mdep_cfg_idx))
+ {
+ p_mdep = &(p_acb->sup_feature.mdep[mdep_cfg_idx]);
+ first_reliable_exist = btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx);
+ switch (p_mdep->mdep_cfg.mdep_role)
+ {
+ case BTA_HL_MDEP_ROLE_SOURCE:
+ if (p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_NO_PREF)
+ {
+ if (first_reliable_exist)
+ {
+ rsp_cfg = p_acb->channel_type[mdep_cfg_idx];
+ }
+ else
+ {
+ rsp_cfg = BTA_HL_DCH_CFG_RELIABLE;
+ }
+ rsp_code = BTA_HL_DCH_CREATE_RSP_SUCCESS;
+ }
+
+ break;
+ case BTA_HL_MDEP_ROLE_SINK:
+
+ if ((p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_RELIABLE) ||
+ (first_reliable_exist && (p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_STREAMING)))
+ {
+ rsp_code = BTA_HL_DCH_CREATE_RSP_SUCCESS;
+ rsp_cfg = p_data->dch_create_ind.cfg;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ success = FALSE;
+ }
+
+ if (success)
+ {
+ BTIF_TRACE_DEBUG2("create response rsp_code=%d rsp_cfg=%d", rsp_code, rsp_cfg );
+ create_rsp_param.local_mdep_id = p_data->dch_create_ind.local_mdep_id;
+ create_rsp_param.mdl_id = p_data->dch_create_ind.mdl_id;
+ create_rsp_param.rsp_code = rsp_code;
+ create_rsp_param.cfg_rsp = rsp_cfg;
+ BTA_HlDchCreateRsp(p_mcb->mcl_handle, &create_rsp_param);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_dch_open_ind
+**
+** Description Process the DCH open indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_dch_open_ind(tBTA_HL *p_data)
+
+{
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_mdl_cb_t *p_dcb;
+ UINT8 app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+ UINT8 dc_cfg;
+ BOOLEAN close_dch = FALSE;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_ind.mcl_handle, &app_idx, &mcl_idx ))
+ {
+ p_acb =BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb =BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(app_idx, p_data->dch_open_ind.local_mdep_id, &mdep_cfg_idx))
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->mdl_handle = p_data->dch_open_ind.mdl_handle;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_mdep_id = p_data->dch_open_ind.local_mdep_id;
+ p_dcb->mdl_id = p_data->dch_open_ind.mdl_id;
+ p_dcb->dch_mode = p_data->dch_open_ind.dch_mode;
+ p_dcb->dch_mode = p_data->dch_open_ind.dch_mode;
+ p_dcb->is_the_first_reliable = p_data->dch_open_ind.first_reliable;
+ p_dcb->mtu = p_data->dch_open_ind.mtu;
+
+ if(btif_hl_find_channel_id_using_mdl_id(app_idx,p_dcb->mdl_id , &p_dcb->channel_id))
+ {
+ BTIF_TRACE_DEBUG4(" app_idx=%d mcl_idx=%d mdl_idx=%d channel_id=%d",
+ app_idx, mcl_idx, mdl_idx, p_dcb->channel_id );
+ if (!btif_hl_create_socket(app_idx, mcl_idx, mdl_idx))
+ {
+ BTIF_TRACE_ERROR0("Unable to create socket");
+ close_dch = TRUE;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR1("Unable find channel id for mdl_id=0x%x", p_dcb->mdl_id );
+ close_dch = TRUE;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR1("INVALID_LOCAL_MDEP_ID mdep_id=%d",p_data->dch_open_cfm.local_mdep_id);
+ close_dch = TRUE;
+ }
+
+ if (close_dch)
+ btif_hl_clean_mdl_cb(p_dcb);
+ }
+ else
+ close_dch = TRUE;
+ }
+ else
+ close_dch = TRUE;
+
+ if (close_dch)
+ BTA_HlDchClose(p_data->dch_open_cfm.mdl_handle);
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_dch_open_cfm
+**
+** Description Process the DCH close confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_proc_dch_open_cfm(tBTA_HL *p_data)
+
+{
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_mdl_cb_t *p_dcb;
+ btif_hl_pending_chan_cb_t *p_pcb;
+ UINT8 app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+ BOOLEAN status = FALSE;
+ BOOLEAN close_dch = FALSE;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_cfm.mcl_handle, &app_idx, &mcl_idx ))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+
+ if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(app_idx, p_data->dch_open_cfm.local_mdep_id, &mdep_cfg_idx))
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->mdl_handle = p_data->dch_open_cfm.mdl_handle;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_mdep_id = p_data->dch_open_cfm.local_mdep_id;
+ p_dcb->mdl_id = p_data->dch_open_cfm.mdl_id;
+ p_dcb->dch_mode = p_data->dch_open_cfm.dch_mode;
+ p_dcb->is_the_first_reliable= p_data->dch_open_cfm.first_reliable;
+ p_dcb->mtu = p_data->dch_open_cfm.mtu;
+ p_dcb->channel_id = p_pcb->channel_id;
+
+ BTIF_TRACE_DEBUG3("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx, mdl_idx );
+ btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+ if (btif_hl_create_socket(app_idx, mcl_idx, mdl_idx))
+ {
+ status = TRUE;
+ BTIF_TRACE_DEBUG4("app_idx=%d mcl_idx=%d mdl_idx=%d p_dcb->channel_id=0x%08x",
+ app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+ btif_hl_clean_pcb(p_pcb);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR0("Unable to create socket");
+ close_dch = TRUE;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR1("INVALID_LOCAL_MDEP_ID mdep_id=%d",p_data->dch_open_cfm.local_mdep_id);
+ close_dch = TRUE;
+ }
+
+ if (close_dch)
+ {
+ btif_hl_clean_mdl_cb(p_dcb);
+ BTA_HlDchClose(p_data->dch_open_cfm.mdl_handle);
+ }
+ }
+ }
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function btif_hl_proc_dch_reconnect_cfm
+**
+** Description Process the DCH reconnect indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_proc_dch_reconnect_cfm(tBTA_HL *p_data)
+{
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_mdl_cb_t *p_dcb;
+ btif_hl_pending_chan_cb_t *p_pcb;
+ UINT8 app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+ BOOLEAN status = FALSE;
+ BOOLEAN close_dch = FALSE;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_cfm.mcl_handle, &app_idx, &mcl_idx ))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+
+ if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(app_idx, p_data->dch_reconnect_cfm.local_mdep_id, &mdep_cfg_idx))
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->mdl_handle = p_data->dch_reconnect_cfm.mdl_handle;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_mdep_id = p_data->dch_reconnect_cfm.local_mdep_id;
+ p_dcb->mdl_id = p_data->dch_reconnect_cfm.mdl_id;
+ p_dcb->dch_mode = p_data->dch_reconnect_cfm.dch_mode;
+ p_dcb->is_the_first_reliable= p_data->dch_reconnect_cfm.first_reliable;
+ p_dcb->mtu = p_data->dch_reconnect_cfm.mtu;
+ p_dcb->channel_id = p_pcb->channel_id;
+
+ BTIF_TRACE_DEBUG3("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx, mdl_idx );
+ btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+ if (btif_hl_create_socket(app_idx, mcl_idx, mdl_idx))
+ {
+ status = TRUE;
+ BTIF_TRACE_DEBUG4("app_idx=%d mcl_idx=%d mdl_idx=%d p_dcb->channel_id=0x%08x",
+ app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+ btif_hl_clean_pcb(p_pcb);
+ }
+ else
+ {
+ BTIF_TRACE_ERROR0("Unable to create socket");
+ close_dch = TRUE;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR1("INVALID_LOCAL_MDEP_ID mdep_id=%d",p_data->dch_open_cfm.local_mdep_id);
+ close_dch = TRUE;
+ }
+
+ if (close_dch)
+ {
+ btif_hl_clean_mdl_cb(p_dcb);
+ BTA_HlDchClose(p_data->dch_reconnect_cfm.mdl_handle);
+ }
+ }
+ }
+
+ return status;
+
+}
+/*******************************************************************************
+**
+** Function btif_hl_proc_dch_reconnect_ind
+**
+** Description Process the DCH reconnect indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_dch_reconnect_ind(tBTA_HL *p_data)
+
+{
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_mdl_cb_t *p_dcb;
+ UINT8 app_idx, mcl_idx, mdl_idx, mdep_cfg_idx, dc_cfg;
+ BOOLEAN close_dch = FALSE;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_reconnect_ind.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx))
+ {
+ p_dcb =BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(app_idx, p_data->dch_reconnect_ind.local_mdep_id, &mdep_cfg_idx))
+ {
+ p_dcb->in_use = TRUE;
+ p_dcb->mdl_handle = p_data->dch_reconnect_ind.mdl_handle;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_mdep_id = p_data->dch_reconnect_ind.local_mdep_id;
+ p_dcb->mdl_id = p_data->dch_reconnect_ind.mdl_id;
+ p_dcb->dch_mode = p_data->dch_reconnect_ind.dch_mode;
+ p_dcb->dch_mode = p_data->dch_reconnect_ind.dch_mode;
+ p_dcb->is_the_first_reliable= p_data->dch_reconnect_ind.first_reliable;
+ p_dcb->mtu = p_data->dch_reconnect_ind.mtu;
+ p_dcb->channel_id = btif_hl_get_next_channel_id(p_acb->app_id);
+
+ BTIF_TRACE_DEBUG4(" app_idx=%d mcl_idx=%d mdl_idx=%d channel_id=%d",
+ app_idx, mcl_idx, mdl_idx, p_dcb->channel_id );
+ if (!btif_hl_create_socket(app_idx, mcl_idx, mdl_idx))
+ {
+ BTIF_TRACE_ERROR0("Unable to create socket");
+ close_dch = TRUE;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_ERROR1("INVALID_LOCAL_MDEP_ID mdep_id=%d",p_data->dch_open_cfm.local_mdep_id);
+ close_dch = TRUE;
+ }
+
+ if (close_dch)
+ btif_hl_clean_mdl_cb(p_dcb);
+ }
+ else
+ close_dch = TRUE;
+ }
+ else
+ close_dch = TRUE;
+
+ if (close_dch)
+ BTA_HlDchClose(p_data->dch_reconnect_ind.mdl_handle);
+
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_dch_close_ind
+**
+** Description Process the DCH close indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_dch_close_ind(tBTA_HL *p_data)
+
+{
+ btif_hl_mdl_cb_t *p_dcb;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ if (btif_hl_find_mdl_idx_using_handle(p_data->dch_close_ind.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx ))
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ btif_hl_release_socket(app_idx,mcl_idx, mdl_idx);
+ btif_hl_clean_mdl_cb(p_dcb);
+ if (!btif_hl_num_dchs_in_use(app_idx, mcl_idx))
+ btif_hl_start_cch_timer(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG1("remote DCH close success mdl_idx=%d", mdl_idx);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_dch_close_cfm
+**
+** Description Process the DCH reconnect confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_dch_close_cfm(tBTA_HL *p_data)
+
+{
+ btif_hl_mdl_cb_t *p_dcb;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ if (btif_hl_find_mdl_idx_using_handle(p_data->dch_close_cfm.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx ))
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ btif_hl_release_socket(app_idx,mcl_idx,mdl_idx);
+ btif_hl_clean_mdl_cb(p_dcb);
+ if (!btif_hl_num_dchs_in_use(app_idx, mcl_idx))
+ btif_hl_start_cch_timer(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG1("BTAPP local DCH close success mdl_idx=%d", mdl_idx);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_abort_ind
+**
+** Description Process the abort indicaiton
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_abort_ind(tBTA_HL_MCL_HANDLE mcl_handle){
+
+ UINT8 app_idx,mcl_idx;
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__ );
+ if (btif_hl_find_mcl_idx_using_handle(mcl_handle, &app_idx, &mcl_idx))
+ {
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_abort_cfm
+**
+** Description Process the abort confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_abort_cfm(tBTA_HL_MCL_HANDLE mcl_handle){
+ UINT8 app_idx,mcl_idx;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__ );
+ if (btif_hl_find_mcl_idx_using_handle(mcl_handle, &app_idx, &mcl_idx))
+ {
+ btif_hl_send_setup_disconnected_cb(app_idx,mcl_idx);
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_send_data_cfm
+**
+** Description Process the send data confirmation
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_send_data_cfm(tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status){
+ UINT8 app_idx,mcl_idx, mdl_idx;
+ btif_hl_mdl_cb_t *p_dcb;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ if (btif_hl_find_mdl_idx_using_handle(mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx ))
+ {
+ p_dcb =BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ btif_hl_free_buf((void **) &p_dcb->p_tx_pkt);
+ BTIF_TRACE_DEBUG1("send success free p_tx_pkt tx_size=%d", p_dcb->tx_size);
+ p_dcb->tx_size = 0;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_dch_cong_ind
+**
+** Description Process the DCH congestion change indication
+**
+** Returns Nothing
+**
+*******************************************************************************/
+static void btif_hl_proc_dch_cong_ind(tBTA_HL *p_data)
+
+{
+ btif_hl_mdl_cb_t *p_dcb;
+ UINT8 app_idx, mcl_idx, mdl_idx;
+
+ BTIF_TRACE_DEBUG0("btif_hl_proc_dch_cong_ind");
+
+
+ if (btif_hl_find_mdl_idx_using_handle(p_data->dch_cong_ind.mdl_handle, &app_idx, &mcl_idx, &mdl_idx))
+ {
+ p_dcb =BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ p_dcb->cong = p_data->dch_cong_ind.cong;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_app_data
+**
+** Description Process registration request
+**
+** Returns void
+**
+*******************************************************************************/
+static BOOLEAN btif_hl_proc_app_data(UINT8 app_idx){
+ btif_hl_app_cb_t *p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_app_data_t *p_data;
+ btif_hl_nv_app_data_t *p_nv;
+ BOOLEAN is_match;
+ UINT8 num_mdeps, i;
+ tBTA_HL_MDEP_CFG *p_cfg;
+ tBTA_HL_MDEP_CFG *p_nv_cfg;
+ BOOLEAN status = TRUE;
+ bt_status_t bt_status;
+
+ BTIF_TRACE_DEBUG2("%s app_idx=%d ", __FUNCTION__, app_idx );
+
+ if (!GKI_queue_is_empty(&p_ncb->app_queue))
+ {
+ p_data = (btif_hl_app_data_t *)GKI_getfirst((void *)&p_ncb->app_queue);
+ while (p_data != NULL)
+ {
+ is_match = FALSE;
+ p_nv = &p_data->app_data;
+ BTIF_TRACE_DEBUG1("compare with nv idx=%d", p_data->app_nv_idx);
+ if (p_nv->application_name != NULL &&
+ memcmp((void *)p_acb->application_name, p_nv->application_name,(BTIF_HL_APPLICATION_NAME_LEN +1)) != 0 )
+ {
+ BTIF_TRACE_DEBUG1("application_name mismatch NV(%s)",p_nv->application_name);
+ }
+ else if (p_nv->provider_name != NULL &&
+ memcmp((void *)p_acb->provider_name, p_nv->provider_name,(BTA_PROVIDER_NAME_LEN +1)) != 0)
+ {
+ BTIF_TRACE_DEBUG1("provider_name mismatch NV(%s)",p_nv->provider_name);
+ }
+ else if (p_nv->srv_name != NULL &&
+ memcmp((void *)p_acb->srv_name, p_nv->srv_name,(BTA_SERVICE_NAME_LEN +1)) != 0)
+ {
+ BTIF_TRACE_DEBUG1("srv_name mismatch NV(%s)",p_nv->srv_name);
+ }
+ else if (p_nv->srv_desp != NULL &&
+ memcmp((void *)p_acb->srv_desp, p_nv->srv_desp,(BTA_SERVICE_DESP_LEN +1)) != 0)
+ {
+ BTIF_TRACE_DEBUG1("srv_desp mismatch NV(%s)",p_nv->srv_desp);
+ }
+ else if (p_acb->sup_feature.app_role_mask != p_nv->sup_feature.app_role_mask)
+ {
+ BTIF_TRACE_DEBUG1("app_role_mask mismatch app_role_mask=0x%x", p_nv->sup_feature.app_role_mask);
+ }
+ else if (p_acb->sup_feature.advertize_source_sdp != p_nv->sup_feature.advertize_source_sdp)
+ {
+ BTIF_TRACE_DEBUG1("advertize_source_sdp mismatch advertize_source_sdp=0x%x",
+ p_nv->sup_feature.advertize_source_sdp);
+ }
+ else if (p_acb->sup_feature.num_of_mdeps != p_nv->sup_feature.num_of_mdeps)
+ {
+ BTIF_TRACE_DEBUG1("num_of_mdeps mismatch num_of_mdeps=0x%x", p_nv->sup_feature.num_of_mdeps);
+ }
+ else
+ {
+ //TODO remove debug after testing completed
+ BTIF_TRACE_DEBUG1("Step1 match for app_idx=%d now check mdep cfg", app_idx);
+ is_match = TRUE;
+ num_mdeps = p_acb->sup_feature.num_of_mdeps;
+ BTIF_TRACE_DEBUG1("num of medeps num_mdeps=%d ", num_mdeps);
+ for (i=0; i< num_mdeps; i++)
+ {
+ p_cfg = &p_acb->sup_feature.mdep[i].mdep_cfg;
+ p_nv_cfg = &p_nv->sup_feature.mdep[i].mdep_cfg;
+
+ BTIF_TRACE_DEBUG2("mdep-role=%d data_type=%d ",
+ p_cfg->mdep_role,p_cfg->data_cfg[0].data_type );
+ BTIF_TRACE_DEBUG2("from NV mdep-role=%d data_type=%d ",
+ p_nv_cfg->mdep_role,p_nv_cfg->data_cfg[0].data_type );
+ if (p_cfg->mdep_role != p_nv_cfg->mdep_role ||
+ p_cfg->data_cfg[0].data_type != p_nv_cfg->data_cfg[0].data_type )
+ {
+ is_match = FALSE;
+ BTIF_TRACE_DEBUG0("Not Match" );
+ break;
+ }
+ }
+ }
+
+ if (!is_match)
+ {
+ p_data = (btif_hl_app_data_t *)GKI_getnext((void *)p_data);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG1("Match is found app_nv_idx=%d",p_data->app_nv_idx );
+ break;
+ }
+ }
+ }
+
+ if (is_match)
+ {
+ if ((bt_status = btif_storage_read_hl_mdl_data(p_data->app_nv_idx,
+ (char *) &p_acb->mdl_cfg[0], sizeof(btif_hl_nv_mdl_data_t)))
+ == BT_STATUS_SUCCESS)
+ {
+ p_data->app_idx = app_idx;
+ p_acb->is_new_app = FALSE;
+ p_acb->app_nv_idx = p_data->app_nv_idx;
+ BTIF_TRACE_DEBUG2("btif_storage_read_hl_mdl_data OK app_idx=%d app_nv_idx=%d",
+ app_idx, p_data->app_nv_idx );
+
+ for (i=0; i<BTA_HL_NUM_MDL_CFGS; i++)
+ {
+ //TODO remove debug after testing completed
+ if (p_acb->mdl_cfg[i].base.active)
+ {
+ BTIF_TRACE_DEBUG5("i=%d mdl_id=0x%x dch_mode=%d local_mdep_id=%d peer_mdep_id=%d",
+ i,
+ p_acb->mdl_cfg[i].base.mdl_id,
+ p_acb->mdl_cfg[i].base.dch_mode,
+ p_acb->mdl_cfg[i].base.local_mdep_id,
+ p_acb->mdl_cfg[i].extra.peer_mdep_id );
+
+ }
+
+ }
+ }
+ else
+ {
+ status= FALSE;
+ }
+ }
+ else
+ {
+ memset(&p_acb->mdl_cfg, 0, sizeof(btif_hl_nv_mdl_data_t));
+ p_acb->is_new_app = TRUE;
+ BTIF_TRACE_DEBUG0("No Match this is a new app set is_new_app=TRUE");
+ }
+
+ BTIF_TRACE_DEBUG1("status=%d ",status );
+ return status;
+
+
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_cb_evt
+**
+** Description Process registration request
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_proc_reg_request(UINT8 app_idx, UINT8 app_id,
+ tBTA_HL_REG_PARAM *p_reg_param,
+ tBTA_HL_CBACK *p_cback){
+ bt_status_t status= BT_STATUS_SUCCESS;
+ UINT8 i;
+ btif_hl_app_data_t *p_data;
+ btif_hl_nv_app_cb_t *p_app_cb;
+ BTIF_TRACE_DEBUG4("%s app_idx=%d app_id=%d is_app_read=%d", __FUNCTION__, app_idx, app_id,p_ncb->is_app_read );
+
+ if (!p_ncb->is_app_read)
+ {
+ if ((status = btif_storage_read_hl_apps_cb((char *)&p_ncb->app_cb, sizeof(btif_hl_nv_app_cb_t))) == BT_STATUS_SUCCESS)
+ {
+ p_app_cb = &p_ncb->app_cb;
+ for (i=0; i< BTIF_HL_NV_MAX_APPS; i++)
+ {
+ if (p_app_cb->app[i].in_use )
+ {
+ BTIF_TRACE_DEBUG1("app_nv_idx=%d in_use=TRUE",i);
+ if ( (p_data = (btif_hl_app_data_t *)GKI_getbuf((UINT16)sizeof(btif_hl_app_data_t)))!=NULL)
+ {
+ BTIF_TRACE_DEBUG1("load app_nv_idx=%d ", i );
+ p_data->active = FALSE;
+ p_data->app_idx = 0;
+ p_data->app_nv_idx = i;
+ if ((status = btif_storage_read_hl_app_data(i, (char *)&p_data->app_data, sizeof(btif_hl_nv_app_data_t)))
+ == BT_STATUS_SUCCESS)
+ {
+ BTIF_TRACE_DEBUG0("enuque app_data");
+ GKI_enqueue(&p_ncb->app_queue, (void *) p_data);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("btif_storage_read_hl_app_data failed");
+ status = BT_STATUS_FAIL;
+ btif_hl_free_buf((void **)&p_data);
+ break;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("GKI_getbuf failed");
+ status = BT_STATUS_FAIL;
+ btif_hl_free_buf((void **)&p_data);
+ break;
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG1("app data load status=%d (0-BT_STATUS_SUCCESS) ", status );
+ if ( status == BT_STATUS_SUCCESS)
+ {
+ p_ncb->is_app_read = TRUE;
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("status=failed remove all elements in app_queue");
+ if (!GKI_queue_is_empty(&p_ncb->app_queue))
+ {
+ p_data = (btif_hl_app_data_t *)GKI_getfirst((void *)&p_ncb->app_queue);
+ while (p_data != NULL)
+ {
+ GKI_remove_from_queue((void *)&p_ncb->app_queue, p_data);
+ p_data = (btif_hl_app_data_t *)GKI_getfirst((void *)&p_ncb->app_queue);
+ }
+ }
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("btif_storage_read_hl_apps_cb failed");
+ }
+ }
+
+ if (status == BT_STATUS_SUCCESS)
+ {
+ if (!btif_hl_proc_app_data(app_idx))
+ {
+ btif_hl_free_app_idx(app_idx);
+ BTIF_TRACE_DEBUG2("call reg state callback app_id=%d state=%d", app_id, BTHL_APP_REG_STATE_REG_FAILED);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, app_reg_state_cb, (int) app_id,
+ BTHL_APP_REG_STATE_REG_FAILED );
+ }
+ else
+ {
+ BTA_HlRegister(app_id, p_reg_param, btif_hl_cback);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function btif_hl_proc_cb_evt
+**
+** Description Process HL callback events
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_proc_cb_evt(UINT16 event, char* p_param){
+
+ btif_hl_evt_cb_t *p_data = (btif_hl_evt_cb_t *)p_param;
+ bt_bdaddr_t bd_addr;
+ bthl_channel_state_t state=BTHL_CONN_STATE_DISCONNECTED;
+ BOOLEAN send_chan_cb=TRUE;
+ tBTA_HL_REG_PARAM reg_param;
+ btif_hl_app_cb_t *p_acb;
+ bthl_app_reg_state_t reg_state = BTHL_APP_REG_STATE_REG_FAILED;
+ int app_id;
+ UINT8 preg_idx;
+ bt_status_t bt_status;
+
+ BTIF_TRACE_DEBUG2("%s event %d", __FUNCTION__, event);
+ btif_hl_display_calling_process_name();
+
+ switch (event)
+ {
+ case BTIF_HL_SEND_CONNECTED_CB:
+ case BTIF_HL_SEND_DISCONNECTED_CB:
+ if (p_data->chan_cb.cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING)
+ state = BTHL_CONN_STATE_CONNECTED;
+ else if (p_data->chan_cb.cb_state == BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING)
+ state = BTHL_CONN_STATE_DISCONNECTED;
+ else
+ send_chan_cb = FALSE;
+
+ if (send_chan_cb)
+ {
+ btif_hl_copy_bda(&bd_addr, p_data->chan_cb.bd_addr);
+ BTIF_TRACE_DEBUG4("state callbk: ch_id=0x%08x cb_state=%d state=%d fd=%d",
+ p_data->chan_cb.channel_id,
+ p_data->chan_cb.cb_state,
+ state, p_data->chan_cb.fd);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, p_data->chan_cb.app_id,
+ &bd_addr, p_data->chan_cb.mdep_cfg_index,
+ p_data->chan_cb.channel_id, state, p_data->chan_cb.fd );
+ }
+
+ break;
+ case BTIF_HL_REG_APP:
+ p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->reg.app_idx);
+ app_id = (int) p_acb->app_id;
+ BTIF_TRACE_DEBUG2("Rcv BTIF_HL_REG_APP app_idx=%d reg_pending=%d", p_data->reg.app_idx, p_acb->reg_pending);
+ if (btif_hl_get_state() == BTIF_HL_STATE_ENABLED && p_acb->reg_pending )
+ {
+ p_acb->reg_pending = FALSE;
+
+ reg_param.dev_type = p_acb->dev_type;
+ reg_param.sec_mask = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT;
+ reg_param.p_srv_name = p_acb->srv_name;
+ reg_param.p_srv_desp = p_acb->srv_desp;
+ reg_param.p_provider_name = p_acb->provider_name;
+ btif_hl_proc_reg_request (p_data->reg.app_idx, p_acb->app_id, &reg_param, btif_hl_cback);
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG2("reg request is processed state=%d reg_pending=%d", btif_hl_get_state(), p_acb->reg_pending);
+ }
+
+ break;
+
+ case BTIF_HL_UNREG_APP:
+ BTIF_TRACE_DEBUG1("Rcv BTIF_HL_UNREG_APP app_idx=%d", p_data->unreg.app_idx );
+ p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->unreg.app_idx);
+ BTA_HlDeregister(p_acb->app_handle);
+ break;
+ case BTIF_HL_UPDATE_MDL:
+ BTIF_TRACE_DEBUG1("Rcv BTIF_HL_UPDATE_MDL app_idx=%d", p_data->update_mdl.app_idx );
+ p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->update_mdl.app_idx);
+ BTIF_TRACE_DEBUG1("app_nv_idx=%d", p_acb->app_nv_idx );
+ bt_status = btif_storage_write_hl_mdl_data(p_acb->app_nv_idx,(char *) &p_acb->mdl_cfg[0],
+ sizeof(btif_hl_nv_mdl_data_t));
+ BTIF_TRACE_DEBUG1("bt_status=%d", bt_status);
+ break;
+
+ default:
+ BTIF_TRACE_ERROR1("Unknown event %d", event);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_upstreams_evt
+**
+** Description Process HL events
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_upstreams_evt(UINT16 event, char* p_param){
+ tBTA_HL *p_data = (tBTA_HL *)p_param;
+ UINT8 app_idx, mcl_idx;
+ btif_hl_app_cb_t *p_acb;
+ btif_hl_mcl_cb_t *p_mcb = NULL;
+ BD_ADDR bd_addr;
+ btif_hl_pend_dch_op_t pending_op;
+ BOOLEAN status;
+
+ BTIF_TRACE_DEBUG2("%s event %d", __FUNCTION__, event);
+ btif_hl_display_calling_process_name();
+ switch (event)
+ {
+ case BTA_HL_REGISTER_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_REGISTER_CFM_EVT");
+ BTIF_TRACE_DEBUG3("app_id=%d app_handle=%d status=%d ",
+ p_data->reg_cfm.app_id,
+ p_data->reg_cfm.app_handle,
+ p_data->reg_cfm.status );
+
+ btif_hl_proc_reg_cfm(p_data);
+ break;
+ case BTA_HL_SDP_INFO_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_SDP_INFO_IND_EVT");
+ BTIF_TRACE_DEBUG5("app_handle=%d ctrl_psm=0x%04x data_psm=0x%04x x_spec=%d mcap_sup_procs=0x%02x",
+ p_data->sdp_info_ind.app_handle,
+ p_data->sdp_info_ind.ctrl_psm,
+ p_data->sdp_info_ind.data_psm,
+ p_data->sdp_info_ind.data_x_spec,
+ p_data->sdp_info_ind.mcap_sup_procs);
+ btif_hl_proc_sdp_info_ind(p_data);
+ break;
+
+ case BTA_HL_DEREGISTER_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DEREGISTER_CFM_EVT");
+ BTIF_TRACE_DEBUG2("app_handle=%d status=%d ",
+ p_data->dereg_cfm.app_handle,
+ p_data->dereg_cfm.status );
+ btif_hl_proc_dereg_cfm(p_data);
+ break;
+
+ case BTA_HL_SDP_QUERY_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_SDP_QUERY_CFM_EVT");
+ BTIF_TRACE_DEBUG2("app_handle=%d status =%d",
+ p_data->sdp_query_cfm.app_handle,
+ p_data->sdp_query_cfm.status);
+
+ BTIF_TRACE_DEBUG6("DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+ p_data->sdp_query_cfm.bd_addr[0], p_data->sdp_query_cfm.bd_addr[1],
+ p_data->sdp_query_cfm.bd_addr[2], p_data->sdp_query_cfm.bd_addr[3],
+ p_data->sdp_query_cfm.bd_addr[4], p_data->sdp_query_cfm.bd_addr[5]);
+
+ if (p_data->sdp_query_cfm.status == BTA_HL_STATUS_OK)
+ status = btif_hl_proc_sdp_query_cfm(p_data);
+ else
+ status = FALSE;
+
+ if (!status)
+ {
+ if (btif_hl_find_app_idx_using_handle(p_data->sdp_query_cfm.app_handle, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, p_data->sdp_query_cfm.bd_addr, &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if ( (p_mcb->cch_oper = BTIF_HL_CCH_OP_MDEP_FILTERING) ||
+ (p_mcb->cch_oper == BTIF_HL_CCH_OP_DCH_OPEN) )
+ {
+ pending_op = p_mcb->pcb.op;
+ switch (pending_op)
+ {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_RECONNECT:
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ if (!p_mcb->is_connected)
+ btif_hl_clean_mcl_cb(app_idx, mcl_idx);
+ }
+ }
+ }
+ }
+
+ break;
+
+
+ case BTA_HL_CCH_OPEN_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_CCH_OPEN_CFM_EVT");
+ BTIF_TRACE_DEBUG3("app_handle=%d mcl_handle=%d status =%d",
+ p_data->cch_open_cfm.app_handle,
+ p_data->cch_open_cfm.mcl_handle,
+ p_data->cch_open_cfm.status);
+ BTIF_TRACE_DEBUG6("DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+ p_data->cch_open_cfm.bd_addr[0], p_data->cch_open_cfm.bd_addr[1],
+ p_data->cch_open_cfm.bd_addr[2], p_data->cch_open_cfm.bd_addr[3],
+ p_data->cch_open_cfm.bd_addr[4], p_data->cch_open_cfm.bd_addr[5]);
+
+ if (p_data->cch_open_cfm.status == BTA_HL_STATUS_OK)
+ {
+ status = btif_hl_proc_cch_open_cfm(p_data);
+ }
+ else
+ {
+ status = FALSE;
+ }
+
+ if (!status)
+ {
+ if (btif_hl_find_app_idx_using_handle(p_data->cch_open_cfm.app_handle, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, p_data->cch_open_cfm.bd_addr, &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ pending_op = p_mcb->pcb.op;
+ switch (pending_op)
+ {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_RECONNECT:
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ btif_hl_clean_mcl_cb(app_idx, mcl_idx);
+ }
+ }
+ }
+ break;
+
+ case BTA_HL_DCH_OPEN_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_OPEN_CFM_EVT");
+ BTIF_TRACE_DEBUG3("mcl_handle=%d mdl_handle=0x%x status=%d ",
+ p_data->dch_open_cfm.mcl_handle,
+ p_data->dch_open_cfm.mdl_handle,
+ p_data->dch_open_cfm.status);
+ BTIF_TRACE_DEBUG5("first_reliable =%d dch_mode=%d local_mdep_id=%d mdl_id=%d mtu=%d",
+ p_data->dch_open_cfm.first_reliable,
+ p_data->dch_open_cfm.dch_mode,
+ p_data->dch_open_cfm.local_mdep_id,
+ p_data->dch_open_cfm.mdl_id,
+ p_data->dch_open_cfm.mtu);
+ if (p_data->dch_open_cfm.status == BTA_HL_STATUS_OK)
+ {
+ status = btif_hl_proc_dch_open_cfm(p_data);
+ }
+ else
+ {
+ status = FALSE;
+ }
+
+ if (!status)
+ {
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_cfm.mcl_handle,&app_idx, &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ pending_op = p_mcb->pcb.op;
+ switch (pending_op)
+ {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_RECONNECT:
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+
+ case BTA_HL_CCH_OPEN_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_CCH_OPEN_IND_EVT");
+ BTIF_TRACE_DEBUG2("app_handle=%d mcl_handle=%d",
+ p_data->cch_open_ind.app_handle,
+ p_data->cch_open_ind.mcl_handle);
+ BTIF_TRACE_DEBUG6("DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+ p_data->cch_open_ind.bd_addr[0], p_data->cch_open_ind.bd_addr[1],
+ p_data->cch_open_ind.bd_addr[2], p_data->cch_open_ind.bd_addr[3],
+ p_data->cch_open_ind.bd_addr[4], p_data->cch_open_ind.bd_addr[5]);
+
+ btif_hl_proc_cch_open_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_CREATE_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_CREATE_IND_EVT");
+ BTIF_TRACE_DEBUG1("mcl_handle=%d",
+ p_data->dch_create_ind.mcl_handle );
+ BTIF_TRACE_DEBUG3("local_mdep_id =%d mdl_id=%d cfg=%d",
+ p_data->dch_create_ind.local_mdep_id,
+ p_data->dch_create_ind.mdl_id,
+ p_data->dch_create_ind.cfg);
+ btif_hl_proc_create_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_OPEN_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_OPEN_IND_EVT");
+ BTIF_TRACE_DEBUG2("mcl_handle=%d mdl_handle=0x%x",
+ p_data->dch_open_ind.mcl_handle,
+ p_data->dch_open_ind.mdl_handle );
+ BTIF_TRACE_DEBUG5("first_reliable =%d dch_mode=%d local_mdep_id=%d mdl_id=%d mtu=%d",
+ p_data->dch_open_ind.first_reliable,
+ p_data->dch_open_ind.dch_mode,
+ p_data->dch_open_ind.local_mdep_id,
+ p_data->dch_open_ind.mdl_id,
+ p_data->dch_open_ind.mtu);
+
+ btif_hl_proc_dch_open_ind(p_data);
+ break;
+
+ case BTA_HL_DELETE_MDL_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DELETE_MDL_IND_EVT");
+ BTIF_TRACE_DEBUG2("mcl_handle=%d mdl_id=0x%x",
+ p_data->delete_mdl_ind.mcl_handle,
+ p_data->delete_mdl_ind.mdl_id);
+ if (btif_hl_find_mcl_idx_using_handle( p_data->delete_mdl_ind.mcl_handle, &app_idx, &mcl_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ /* todo send callback find channel id from NV? */
+ }
+ break;
+
+ case BTA_HL_DELETE_MDL_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DELETE_MDL_CFM_EVT");
+ BTIF_TRACE_DEBUG3("mcl_handle=%d mdl_id=0x%x status=%d",
+ p_data->delete_mdl_cfm.mcl_handle,
+ p_data->delete_mdl_cfm.mdl_id,
+ p_data->delete_mdl_cfm.status);
+
+
+ if (btif_hl_find_mcl_idx_using_handle( p_data->delete_mdl_cfm.mcl_handle, &app_idx,&mcl_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ btif_hl_send_destroyed_cb(p_acb);
+ btif_hl_clean_delete_mdl(&p_acb->delete_mdl);
+ /* todo if delete mdl failed we still report mdl delete ok and remove the mld_id from NV*/
+ }
+ break;
+
+ case BTA_HL_DCH_RECONNECT_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_RECONNECT_CFM_EVT");
+ BTIF_TRACE_DEBUG3("mcl_handle=%d mdl_handle=%d status=%d ",
+ p_data->dch_reconnect_cfm.mcl_handle,
+ p_data->dch_reconnect_cfm.mdl_handle,
+ p_data->dch_reconnect_cfm.status);
+ BTIF_TRACE_DEBUG4("first_reliable =%d dch_mode=%d mdl_id=%d mtu=%d",
+ p_data->dch_reconnect_cfm.first_reliable,
+ p_data->dch_reconnect_cfm.dch_mode,
+ p_data->dch_reconnect_cfm.mdl_id,
+ p_data->dch_reconnect_cfm.mtu);
+
+
+ if (p_data->dch_reconnect_cfm.status == BTA_HL_STATUS_OK)
+ {
+ status = btif_hl_proc_dch_reconnect_cfm(p_data);
+ }
+ else
+ {
+ status = FALSE;
+ }
+
+ if (!status)
+ {
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_cfm.mcl_handle,&app_idx, &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ pending_op = p_mcb->pcb.op;
+ switch (pending_op)
+ {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_RECONNECT:
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ }
+ }
+
+ break;
+
+ case BTA_HL_CCH_CLOSE_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_CCH_CLOSE_CFM_EVT");
+ BTIF_TRACE_DEBUG2("mcl_handle=%d status =%d",
+ p_data->cch_close_cfm.mcl_handle,
+ p_data->cch_close_cfm.status);
+ if (p_data->cch_close_cfm.status == BTA_HL_STATUS_OK)
+ {
+ btif_hl_proc_cch_close_cfm(p_data);
+ }
+ break;
+
+ case BTA_HL_CCH_CLOSE_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_CCH_CLOSE_IND_EVT");
+ BTIF_TRACE_DEBUG2("mcl_handle =%d intentional_close=%s",
+ p_data->cch_close_ind.mcl_handle,
+ (p_data->cch_close_ind.intentional?"Yes":"No"));
+
+ btif_hl_proc_cch_close_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_CLOSE_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_CLOSE_IND_EVT");
+ BTIF_TRACE_DEBUG2("mdl_handle=%d intentional_close=%s",
+ p_data->dch_close_ind.mdl_handle,
+ (p_data->dch_close_ind.intentional?"Yes":"No") );
+
+ btif_hl_proc_dch_close_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_CLOSE_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_CLOSE_CFM_EVT");
+ BTIF_TRACE_DEBUG2("mdl_handle=%d status=%d ",
+ p_data->dch_close_cfm.mdl_handle,
+ p_data->dch_close_cfm.status);
+
+ if (p_data->dch_close_cfm.status == BTA_HL_STATUS_OK)
+ {
+ btif_hl_proc_dch_close_cfm(p_data);
+ }
+ break;
+
+ case BTA_HL_DCH_ECHO_TEST_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_ECHO_TEST_CFM_EVT");
+ BTIF_TRACE_DEBUG2("mcl_handle=%d status=%d",
+ p_data->echo_test_cfm.mcl_handle,
+ p_data->echo_test_cfm.status );
+ /* not supported */
+ break;
+
+
+ case BTA_HL_DCH_RECONNECT_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_RECONNECT_IND_EVT");
+
+ BTIF_TRACE_DEBUG2("mcl_handle=%d mdl_handle=5d",
+ p_data->dch_reconnect_ind.mcl_handle,
+ p_data->dch_reconnect_ind.mdl_handle );
+ BTIF_TRACE_DEBUG4("first_reliable =%d dch_mode=%d mdl_id=%d mtu=%d",
+ p_data->dch_reconnect_ind.first_reliable,
+ p_data->dch_reconnect_ind.dch_mode,
+ p_data->dch_reconnect_ind.mdl_id,
+ p_data->dch_reconnect_ind.mtu);
+
+ btif_hl_proc_dch_reconnect_ind(p_data);
+ break;
+
+ case BTA_HL_CONG_CHG_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_CONG_CHG_IND_EVT");
+ BTIF_TRACE_DEBUG2("mdl_handle=%d cong =%d",
+ p_data->dch_cong_ind.mdl_handle,
+ p_data->dch_cong_ind.cong);
+ btif_hl_proc_dch_cong_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_ABORT_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_ABORT_IND_EVT");
+ BTIF_TRACE_DEBUG1("mcl_handle=%d",
+ p_data->dch_abort_ind.mcl_handle );
+ btif_hl_proc_abort_ind(p_data->dch_abort_ind.mcl_handle);
+ break;
+ case BTA_HL_DCH_ABORT_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_ABORT_CFM_EVT");
+ BTIF_TRACE_DEBUG2("mcl_handle=%d status =%d",
+ p_data->dch_abort_cfm.mcl_handle,
+ p_data->dch_abort_cfm.status);
+ if (p_data->dch_abort_cfm.status == BTA_HL_STATUS_OK)
+ {
+ btif_hl_proc_abort_cfm(p_data->dch_abort_ind.mcl_handle);
+ }
+ break;
+
+ case BTA_HL_DCH_SEND_DATA_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_SEND_DATA_CFM_EVT");
+ BTIF_TRACE_DEBUG2("mdl_handle=0x%x status =%d",
+ p_data->dch_send_data_cfm.mdl_handle,
+ p_data->dch_send_data_cfm.status);
+ btif_hl_proc_send_data_cfm(p_data->dch_send_data_cfm.mdl_handle,
+ p_data->dch_send_data_cfm.status);
+ break;
+
+ case BTA_HL_DCH_RCV_DATA_IND_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_DCH_RCV_DATA_IND_EVT");
+ BTIF_TRACE_DEBUG1("mdl_handle=0x%x ",
+ p_data->dch_rcv_data_ind.mdl_handle);
+ /* do nothing here */
+ break;
+
+ default:
+ BTIF_TRACE_DEBUG1("Unknown Event (0x%02x)...", event);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_cback
+**
+** Description Callback function for HL events
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_cback(tBTA_HL_EVT event, tBTA_HL *p_data){
+ bt_status_t status;
+ int param_len = 0;
+ BTIF_TRACE_DEBUG2("%s event %d", __FUNCTION__, event);
+ btif_hl_display_calling_process_name();
+ switch (event)
+ {
+ case BTA_HL_REGISTER_CFM_EVT:
+ param_len = sizeof(tBTA_HL_REGISTER_CFM);
+ break;
+ case BTA_HL_SDP_INFO_IND_EVT:
+ param_len = sizeof(tBTA_HL_SDP_INFO_IND);
+ break;
+ case BTA_HL_DEREGISTER_CFM_EVT:
+ param_len = sizeof(tBTA_HL_DEREGISTER_CFM);
+ break;
+ case BTA_HL_SDP_QUERY_CFM_EVT:
+ param_len = sizeof(tBTA_HL_SDP_QUERY_CFM);
+ break;
+ case BTA_HL_CCH_OPEN_CFM_EVT:
+ param_len = sizeof(tBTA_HL_CCH_OPEN_CFM);
+ break;
+ case BTA_HL_DCH_OPEN_CFM_EVT:
+ param_len = sizeof(tBTA_HL_DCH_OPEN_CFM);
+ break;
+ case BTA_HL_CCH_OPEN_IND_EVT:
+ param_len = sizeof(tBTA_HL_CCH_OPEN_IND);
+ break;
+ case BTA_HL_DCH_CREATE_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_CREATE_IND);
+ break;
+ case BTA_HL_DCH_OPEN_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_OPEN_IND);
+ break;
+ case BTA_HL_DELETE_MDL_IND_EVT:
+ param_len = sizeof(tBTA_HL_MDL_IND);
+ break;
+ case BTA_HL_DELETE_MDL_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MDL_CFM);
+ break;
+ case BTA_HL_DCH_RECONNECT_CFM_EVT:
+ param_len = sizeof(tBTA_HL_DCH_OPEN_CFM);
+ break;
+ case BTA_HL_CCH_CLOSE_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MCL_CFM);
+ break;
+ case BTA_HL_CCH_CLOSE_IND_EVT:
+ param_len = sizeof(tBTA_HL_CCH_CLOSE_IND);
+ break;
+ case BTA_HL_DCH_CLOSE_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_CLOSE_IND);
+ break;
+ case BTA_HL_DCH_CLOSE_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MDL_CFM);
+ break;
+ case BTA_HL_DCH_ECHO_TEST_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MCL_CFM);
+ break;
+ case BTA_HL_DCH_RECONNECT_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_OPEN_IND);
+ break;
+ case BTA_HL_CONG_CHG_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_CONG_IND);
+ break;
+ case BTA_HL_DCH_ABORT_IND_EVT:
+ param_len = sizeof(tBTA_HL_MCL_IND);
+ break;
+ case BTA_HL_DCH_ABORT_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MCL_CFM);
+ break;
+ case BTA_HL_DCH_SEND_DATA_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MDL_CFM);
+ break;
+ case BTA_HL_DCH_RCV_DATA_IND_EVT:
+ param_len = sizeof(tBTA_HL_MDL_IND);
+ break;
+ default:
+ param_len = sizeof(tBTA_HL_MDL_IND);
+ break;
+ }
+ status = btif_transfer_context(btif_hl_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_upstreams_ctrl_evt
+**
+** Description Callback function for HL control events in the BTIF task context
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_upstreams_ctrl_evt(UINT16 event, char* p_param){
+ tBTA_HL_CTRL *p_data = (tBTA_HL_CTRL *) p_param;
+ UINT8 i;
+ tBTA_HL_REG_PARAM reg_param;
+ btif_hl_app_cb_t *p_acb;
+
+ BTIF_TRACE_DEBUG2("%s event %d", __FUNCTION__, event);
+ btif_hl_display_calling_process_name();
+
+ switch ( event )
+ {
+ case BTA_HL_CTRL_ENABLE_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_CTRL_ENABLE_CFM_EVT");
+ BTIF_TRACE_DEBUG1("status=%d", p_data->enable_cfm.status);
+
+ if (p_data->enable_cfm.status == BTA_HL_STATUS_OK)
+ {
+ btif_hl_set_state(BTIF_HL_STATE_ENABLED);
+
+
+ for (i=0; i < BTA_HL_NUM_APPS ; i ++)
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use && p_acb->reg_pending)
+ {
+ p_acb->reg_pending = FALSE;
+ reg_param.dev_type = p_acb->dev_type;
+ reg_param.sec_mask = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT;
+ reg_param.p_srv_name = p_acb->srv_name;
+ reg_param.p_srv_desp = p_acb->srv_desp;
+ reg_param.p_provider_name = p_acb->provider_name;
+
+ BTIF_TRACE_DEBUG1("Register pending app_id=%d", p_acb->app_id);
+ btif_hl_proc_reg_request (i, p_acb->app_id, &reg_param, btif_hl_cback);
+ }
+ }
+ }
+
+ break;
+ case BTA_HL_CTRL_DISABLE_CFM_EVT:
+ BTIF_TRACE_DEBUG0("Rcv BTA_HL_CTRL_DISABLE_CFM_EVT");
+ BTIF_TRACE_DEBUG1("status=%d",
+ p_data->disable_cfm.status);
+
+ if (p_data->disable_cfm.status == BTA_HL_STATUS_OK)
+ {
+ memset(p_btif_hl_cb, 0, sizeof(btif_hl_cb_t));
+ btif_hl_set_state(BTIF_HL_STATE_DISABLED);
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_ctrl_cback
+**
+** Description Callback function for HL control events
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_ctrl_cback(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL *p_data){
+ bt_status_t status;
+ int param_len = 0;
+
+ BTIF_TRACE_DEBUG2("%s event %d", __FUNCTION__, event);
+ btif_hl_display_calling_process_name();
+
+ switch ( event )
+ {
+ case BTA_HL_CTRL_ENABLE_CFM_EVT:
+ case BTA_HL_CTRL_DISABLE_CFM_EVT:
+ param_len = sizeof(tBTA_HL_CTRL_ENABLE_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ status = btif_transfer_context(btif_hl_upstreams_ctrl_evt, (uint16_t)event, (void*)p_data, param_len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+/*******************************************************************************
+**
+** Function connect_channel
+**
+** Description connect a data channel
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t connect_channel(int app_id, bt_bdaddr_t *bd_addr, int mdep_cfg_index, int *channel_id){
+ UINT8 app_idx, mcl_idx;
+ btif_hl_app_cb_t *p_acb = NULL;
+ btif_hl_mcl_cb_t *p_mcb=NULL;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ tBTA_HL_DCH_OPEN_PARAM dch_open;
+ BD_ADDR bda;
+ UINT8 i;
+
+ CHECK_BTHL_INIT();
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ btif_hl_display_calling_process_name();
+
+
+ for (i=0; i<6; i++)
+ {
+ bda[i] = (UINT8) bd_addr->address[i];
+ }
+ if (btif_hl_find_app_idx(((UINT8)app_id), &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, bda , &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->is_connected)
+ {
+ dch_open.ctrl_psm = p_mcb->ctrl_psm;
+ dch_open.local_mdep_id = p_acb->sup_feature.mdep[mdep_cfg_index].mdep_id;
+ if (btif_hl_find_peer_mdep_id(p_acb->app_id, p_mcb->bd_addr,
+ p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role,
+ p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.data_cfg[0].data_type, &dch_open.peer_mdep_id ))
+ {
+ dch_open.local_cfg = p_acb->channel_type[mdep_cfg_index];
+ if ((p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+ && !btif_hl_is_the_first_reliable_existed(app_idx,mcl_idx))
+ {
+ dch_open.local_cfg = BTA_HL_DCH_CFG_RELIABLE;
+ }
+ dch_open.sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+
+ if( !btif_hl_dch_open(p_acb->app_id, bda, &dch_open,
+ mdep_cfg_index, BTIF_HL_PEND_DCH_OP_OPEN, channel_id ))
+ {
+ status = BT_STATUS_FAIL;
+ BTIF_TRACE_EVENT1("%s loc0 status = BT_STATUS_FAIL", __FUNCTION__);
+ }
+ }
+ else
+ {
+ status = BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ status = BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ p_acb->filter.num_elems =1;
+ p_acb->filter.elem[0].data_type = p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.data_cfg[mdep_cfg_index].data_type;
+ if (p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SINK)
+ p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ else
+ p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+
+ if ( !btif_hl_cch_open(p_acb->app_id, bda, 0, mdep_cfg_index,
+ BTIF_HL_PEND_DCH_OP_OPEN,
+ channel_id))
+ {
+ status = BT_STATUS_FAIL;
+ }
+ }
+ }
+ else
+ {
+ status = BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG3("%s status=%d channel_id=0x%08x", __FUNCTION__, status, *channel_id);
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function destroy_channel
+**
+** Description destroy a data channel
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t destroy_channel(int channel_id){
+ UINT8 app_idx, mcl_idx, mdl_idx, mdl_cfg_idx, app_id, mdep_cfg_idx;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ btif_hl_mdl_cfg_t *p_mdl;
+ btif_hl_mcl_cb_t *p_mcb;
+ btif_hl_app_cb_t *p_acb;
+
+ CHECK_BTHL_INIT();
+ BTIF_TRACE_EVENT2("%s channel_id=0x%08x", __FUNCTION__, channel_id);
+ btif_hl_display_calling_process_name();
+
+
+ if (btif_hl_if_channel_setup_pending(channel_id, &app_idx, &mcl_idx))
+ {
+ btif_hl_dch_abort(app_idx, mcl_idx);
+ }
+ else
+ {
+ if (btif_hl_find_mdl_cfg_idx_using_channel_id(channel_id, &app_idx, &mdl_cfg_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (!p_acb->delete_mdl.active)
+ {
+ p_mdl =BTIF_HL_GET_MDL_CFG_PTR(app_idx, mdl_cfg_idx);
+ p_acb->delete_mdl.active = TRUE;
+ p_acb->delete_mdl.mdl_id = p_mdl->base.mdl_id;
+ p_acb->delete_mdl.channel_id = channel_id;
+ p_acb->delete_mdl.mdep_cfg_idx = p_mdl->extra.mdep_cfg_idx;
+ memcpy(p_acb->delete_mdl.bd_addr, p_mdl->base.peer_bd_addr,sizeof(BD_ADDR));
+
+ if (btif_hl_find_mcl_idx(app_idx, p_mdl->base.peer_bd_addr, &mcl_idx))
+ {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->is_connected)
+ {
+ BTIF_TRACE_DEBUG1("calling BTA_HlDeleteMdl mdl_id=%d",p_acb->delete_mdl.mdl_id );
+ BTA_HlDeleteMdl(p_mcb->mcl_handle, p_acb->delete_mdl.mdl_id);
+ }
+ else
+ {
+ status = BT_STATUS_FAIL;
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("btif_hl_delete_mdl calling btif_hl_cch_open" );
+ mdep_cfg_idx = p_mdl->extra.mdep_cfg_idx;
+ p_acb->filter.num_elems =1;
+ p_acb->filter.elem[0].data_type = p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.data_cfg[mdep_cfg_idx].data_type;
+ if (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SINK)
+ p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ else
+ p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+ if (btif_hl_cch_open(p_acb->app_id, p_acb->delete_mdl.bd_addr, 0,
+ mdep_cfg_idx,
+ BTIF_HL_PEND_DCH_OP_DELETE_MDL, NULL))
+ {
+ status = BT_STATUS_FAIL;
+ }
+ }
+
+ if ( status == BT_STATUS_FAIL)
+ {
+ /* fail for now */
+ btif_hl_clean_delete_mdl(&p_acb->delete_mdl);
+ }
+ }
+ else
+ {
+ status = BT_STATUS_BUSY;
+ }
+ }
+ else
+ {
+ status = BT_STATUS_FAIL;
+ }
+
+ }
+ return status;
+}
+/*******************************************************************************
+**
+** Function unregister_application
+**
+** Description unregister an HDP application
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t unregister_application(int app_id){
+ btif_hl_app_cb_t *p_acb;
+ UINT8 app_idx;
+ int len;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ btif_hl_evt_cb_t evt_param;
+
+ CHECK_BTHL_INIT();
+ BTIF_TRACE_EVENT2("%s app_id=%d", __FUNCTION__, app_id);
+ btif_hl_display_calling_process_name();
+
+ if (btif_hl_find_app_idx(((UINT8)app_id), &app_idx))
+ {
+ evt_param.unreg.app_idx = app_idx;
+ len = sizeof(btif_hl_unreg_t);
+ status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_UNREG_APP,
+ (char*) &evt_param, len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+
+
+
+ }
+ else
+ {
+ status = BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG1("de-reg return status=%d", status);
+ return status;
+}
+/*******************************************************************************
+**
+** Function register_application
+**
+** Description register an HDP application
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t register_application(bthl_reg_param_t *p_reg_param, int *app_id){
+ btif_hl_app_cb_t *p_acb;
+ tBTA_HL_SUP_FEATURE *p_sup;
+ tBTA_HL_MDEP_CFG *p_cfg;
+ tBTA_HL_MDEP_DATA_TYPE_CFG *p_data;
+ UINT8 app_idx=0, i=0, pending_reg_idx=0;
+ bthl_mdep_cfg_t *p_mdep_cfg;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ btif_hl_evt_cb_t evt_param;
+ int len;
+
+ CHECK_BTHL_INIT();
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ btif_hl_display_calling_process_name();
+
+ if (btif_hl_get_state() == BTIF_HL_STATE_DISABLED)
+ {
+ btif_hl_init();
+ btif_hl_set_state(BTIF_HL_STATE_ENABLING);
+ BTA_HlEnable(btif_hl_ctrl_cback);
+ }
+
+ if (!btif_hl_find_avail_app_idx(&app_idx))
+ {
+ BTIF_TRACE_ERROR0("Unable to allocate a new application control block");
+ return BT_STATUS_FAIL;
+ }
+
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->in_use = TRUE;
+
+
+ p_acb->app_id = btif_hl_get_next_app_id();
+
+ if (p_reg_param->application_name != NULL )
+ strncpy(p_acb->application_name, p_reg_param->application_name, BTIF_HL_APPLICATION_NAME_LEN);
+
+ if (p_reg_param->provider_name != NULL )
+ strncpy(p_acb->provider_name, p_reg_param->provider_name, BTA_PROVIDER_NAME_LEN);
+
+ if (p_reg_param->srv_name != NULL )
+ strncpy(p_acb->srv_name, p_reg_param->srv_name, BTA_SERVICE_NAME_LEN);
+
+ if (p_reg_param->srv_desp != NULL )
+ strncpy(p_acb->srv_desp, p_reg_param->srv_desp, BTA_SERVICE_DESP_LEN);
+
+ p_sup = &p_acb->sup_feature;
+ p_sup->advertize_source_sdp = TRUE;
+ p_sup->echo_cfg.max_rx_apdu_size = BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE;
+ p_sup->echo_cfg.max_tx_apdu_size = BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE;
+ p_sup->num_of_mdeps = p_reg_param->number_of_mdeps;
+
+ for (i=0, p_mdep_cfg = p_reg_param->mdep_cfg ; i< p_sup->num_of_mdeps; i++, p_mdep_cfg++ )
+ {
+ p_cfg = &p_sup->mdep[i].mdep_cfg;
+ p_cfg->num_of_mdep_data_types = 1;
+ p_data = &p_cfg->data_cfg[0];
+
+ if ( !btif_hl_get_bta_mdep_role(p_mdep_cfg->mdep_role, &(p_cfg->mdep_role)))
+ {
+ BTIF_TRACE_ERROR1("Invalid mdep_role=%d", p_mdep_cfg->mdep_role);
+ status = BT_STATUS_FAIL;
+ break;
+ }
+ else
+ {
+ if (p_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK )
+ p_sup->app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
+ else
+ p_sup->app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
+
+ if ( (p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SINK) &&
+ (p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SINK) )
+ {
+ p_acb->dev_type = BTA_HL_DEVICE_TYPE_DUAL;
+ }
+ else if ( p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SINK )
+ p_acb->dev_type = BTA_HL_DEVICE_TYPE_SINK;
+ else
+
+ p_acb->dev_type = BTA_HL_DEVICE_TYPE_SOURCE;
+
+ p_data->data_type = (UINT16) p_mdep_cfg->data_type;
+ p_data->max_rx_apdu_size = btif_hl_get_max_rx_apdu_size(p_cfg->mdep_role, p_data->data_type);
+ p_data->max_tx_apdu_size = btif_hl_get_max_tx_apdu_size(p_cfg->mdep_role, p_data->data_type);
+
+ if (p_mdep_cfg->mdep_description != NULL )
+ strncpy(p_data->desp, p_mdep_cfg->mdep_description, BTA_SERVICE_DESP_LEN);
+
+ if ( !btif_hl_get_bta_channel_type(p_mdep_cfg->channel_type, &(p_acb->channel_type[i])))
+ {
+ BTIF_TRACE_ERROR1("Invalid channel_type=%d", p_mdep_cfg->channel_type);
+ status = BT_STATUS_FAIL;
+ break;
+ }
+ }
+ }
+
+ if (status == BT_STATUS_SUCCESS)
+ {
+ *app_id = (int) p_acb->app_id;
+ evt_param.reg.app_idx = app_idx;
+ len = sizeof(btif_hl_reg_t);
+ p_acb->reg_pending = TRUE;
+ BTIF_TRACE_DEBUG2("calling btif_transfer_context status=%d app_id=%d", status, *app_id);
+ status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_REG_APP,
+ (char*) &evt_param, len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+
+ }
+ else
+ {
+ btif_hl_free_app_idx(app_idx);
+ }
+
+ BTIF_TRACE_DEBUG2("register_application status=%d app_id=%d", status, *app_id);
+ return status;
+}
+/*******************************************************************************
+**
+** Function init
+**
+** Description initializes the hl interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static bt_status_t init( bthl_callbacks_t* callbacks ){
+ bt_status_t status = BT_STATUS_SUCCESS;
+
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ btif_hl_display_calling_process_name();
+ bt_hl_callbacks_cb = *callbacks;
+ bt_hl_callbacks = &bt_hl_callbacks_cb;
+ btif_hl_soc_thread_init();
+
+ return status;
+}
+/*******************************************************************************
+**
+** Function cleanup
+**
+** Description Closes the HL interface
+**
+** Returns void
+**
+*******************************************************************************/
+static void cleanup( void ){
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ btif_hl_display_calling_process_name();
+ if (bt_hl_callbacks)
+ {
+ btif_disable_service(BTA_HDP_SERVICE_ID);
+ bt_hl_callbacks = NULL;
+ }
+
+ btif_hl_disable();
+ btif_hl_close_select_thread();
+}
+
+static const bthl_interface_t bthlInterface = {
+ sizeof(bthl_interface_t),
+ init,
+ register_application,
+ unregister_application,
+ connect_channel,
+ destroy_channel,
+ cleanup,
+};
+
+
+/*******************************************************************************
+**
+** Function btif_hl_get_interface
+**
+** Description Get the hl callback interface
+**
+** Returns bthf_interface_t
+**
+*******************************************************************************/
+const bthl_interface_t *btif_hl_get_interface(){
+ BTIF_TRACE_EVENT1("%s", __FUNCTION__);
+ return &bthlInterface;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_update_maxfd
+**
+** Description Update the max fd if the input fd is greater than the current max fd
+**
+** Returns int
+**
+*******************************************************************************/
+int btif_hl_update_maxfd( int max_org_s){
+ btif_hl_soc_cb_t *p_scb = NULL;
+ int maxfd=0;
+
+ BTIF_TRACE_DEBUG1("btif_hl_update_maxfd max_org_s= %d", max_org_s);
+
+ maxfd = max_org_s;
+ if (!GKI_queue_is_empty(&soc_queue))
+ {
+ p_scb = (btif_hl_soc_cb_t *)GKI_getfirst((void *)&soc_queue);
+ if (maxfd < p_scb->max_s)
+ {
+ maxfd = p_scb->max_s;
+ BTIF_TRACE_DEBUG1("btif_hl_update_maxfd 1 maxfd=%d", maxfd);
+ }
+ while (p_scb != NULL)
+ {
+ if (maxfd < p_scb->max_s)
+ {
+ maxfd = p_scb->max_s;
+ BTIF_TRACE_DEBUG1("btif_hl_update_maxfd 2 maxfd=%d", maxfd);
+ }
+ p_scb = (btif_hl_soc_cb_t *)GKI_getnext((void *)p_scb );
+ }
+ }
+
+ BTIF_TRACE_DEBUG1("btif_hl_update_maxfd final *p_max_s=%d", maxfd);
+ return maxfd;
+}
+/*******************************************************************************
+**
+** Function btif_hl_get_socket_state
+**
+** Description get socket state
+**
+** Returns btif_hl_soc_state_t
+**
+*******************************************************************************/
+btif_hl_soc_state_t btif_hl_get_socket_state(btif_hl_soc_cb_t *p_scb){
+ BTIF_TRACE_DEBUG1("btif_hl_get_socket_state state=%d", p_scb->state);
+ return p_scb->state;
+}
+/*******************************************************************************
+**
+** Function btif_hl_set_socket_state
+**
+** Description set socket state
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_set_socket_state(btif_hl_soc_cb_t *p_scb, btif_hl_soc_state_t new_state){
+ BTIF_TRACE_DEBUG2("btif_hl_set_socket_state %d---->%d", p_scb->state, new_state);
+ p_scb->state = new_state;
+}
+/*******************************************************************************
+**
+** Function btif_hl_release_mcl_sockets
+**
+** Description Release all sockets on the MCL
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_release_mcl_sockets(UINT8 app_idx, UINT8 mcl_idx){
+ btif_hl_soc_cb_t *p_scb = NULL;
+ UINT8 i;
+ btif_hl_mdl_cb_t *p_dcb;
+ BOOLEAN found= FALSE;
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++)
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, i);
+ if (p_dcb && p_dcb->in_use && p_dcb->p_scb)
+ {
+ BTIF_TRACE_DEBUG3("found socket for app_idx=%d mcl_id=%d, mdl_idx=%d", app_idx, mcl_idx, i);
+ btif_hl_set_socket_state (p_dcb->p_scb, BTIF_HL_SOC_STATE_W4_REL);
+ p_dcb->p_scb = NULL;
+ found = TRUE;
+ }
+ }
+ if (found)
+ btif_hl_select_close_connected();
+}
+/*******************************************************************************
+**
+** Function btif_hl_release_socket
+**
+** Description release a specified socket
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_release_socket(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx){
+ btif_hl_soc_cb_t *p_scb = NULL;
+ btif_hl_mdl_cb_t *p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ BTIF_TRACE_DEBUG3("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx, mdl_idx );
+
+ if (p_dcb && p_dcb->p_scb)
+ {
+ p_scb = p_dcb->p_scb;
+ btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_REL);
+ p_dcb->p_scb = NULL;
+ btif_hl_select_close_connected();
+ }
+}
+/*******************************************************************************
+**
+** Function btif_hl_create_socket
+**
+** Description create a socket
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_create_socket(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx){
+ btif_hl_mcl_cb_t *p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ btif_hl_mdl_cb_t *p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ btif_hl_soc_cb_t *p_scb = NULL;
+ UINT8 soc_idx;
+ BOOLEAN status = FALSE;
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (p_dcb && ((p_scb = (btif_hl_soc_cb_t *)GKI_getbuf((UINT16)sizeof(btif_hl_soc_cb_t)))!=NULL))
+ {
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, p_scb->socket_id) >= 0)
+ {
+ BTIF_TRACE_DEBUG2("socket id[0]=%d id[1]=%d",p_scb->socket_id[0], p_scb->socket_id[1] );
+ p_dcb->p_scb = p_scb;
+ p_scb->app_idx = app_idx;
+ p_scb->mcl_idx = mcl_idx;
+ p_scb->mdl_idx = mdl_idx;
+ p_scb->channel_id = p_dcb->channel_id;
+ p_scb->mdep_cfg_idx = p_dcb->local_mdep_cfg_idx;
+ memcpy(p_scb->bd_addr, p_mcb->bd_addr,sizeof(BD_ADDR));
+ btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_ADD);
+ p_scb->max_s = p_scb->socket_id[1];
+ GKI_enqueue(&soc_queue, (void *) p_scb);
+ btif_hl_select_wakeup();
+ status = TRUE;
+ }
+ else
+ {
+
+ btif_hl_free_buf((void **)&p_scb);
+ }
+ }
+
+ BTIF_TRACE_DEBUG2("%s status=%d", __FUNCTION__, status);
+ return status;
+}
+/*******************************************************************************
+**
+** Function btif_hl_add_socket_to_set
+**
+** Description Add a socket
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_add_socket_to_set( fd_set *p_org_set){
+ btif_hl_soc_cb_t *p_scb = NULL;
+ btif_hl_mdl_cb_t *p_dcb = NULL;
+ btif_hl_mcl_cb_t *p_mcb = NULL;
+ btif_hl_evt_cb_t evt_param;
+ bt_status_t status;
+ int len;
+
+ BTIF_TRACE_DEBUG1("entering %s",__FUNCTION__);
+
+ if (!GKI_queue_is_empty(&soc_queue))
+ {
+ p_scb = (btif_hl_soc_cb_t *)GKI_getfirst((void *)&soc_queue);
+ BTIF_TRACE_DEBUG1("btif_hl_add_socket_to_set first p_scb=0x%x", p_scb);
+ while (p_scb != NULL)
+ {
+ if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_ADD)
+ {
+ btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_READ);
+ FD_SET(p_scb->socket_id[1], p_org_set);
+ BTIF_TRACE_DEBUG2("found and set socket_id=%d is_set=%d", p_scb->socket_id[1], FD_ISSET(p_scb->socket_id[1], p_org_set));
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(p_scb->app_idx, p_scb->mcl_idx);
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx);
+ if (p_mcb && p_dcb)
+ {
+ btif_hl_stop_cch_timer(p_scb->app_idx, p_scb->mcl_idx);
+ evt_param.chan_cb.app_id = (int) btif_hl_get_app_id(p_dcb->channel_id);
+ memcpy(evt_param.chan_cb.bd_addr, p_mcb->bd_addr, sizeof(BD_ADDR));
+ evt_param.chan_cb.channel_id = p_dcb->channel_id;
+ evt_param.chan_cb.fd = p_scb->socket_id[0];
+ evt_param.chan_cb.mdep_cfg_index = (int ) p_dcb->local_mdep_cfg_idx;
+ evt_param.chan_cb.cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING;
+ len = sizeof(btif_hl_send_chan_state_cb_t);
+ status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_SEND_CONNECTED_CB,
+ (char*) &evt_param, len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+ }
+ }
+ p_scb = (btif_hl_soc_cb_t *)GKI_getnext((void *)p_scb );
+ BTIF_TRACE_DEBUG1("next p_scb=0x%x", p_scb);
+ }
+ }
+
+ BTIF_TRACE_DEBUG1("leaving %s",__FUNCTION__);
+}
+/*******************************************************************************
+**
+** Function btif_hl_close_socket
+**
+** Description close a socket
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_close_socket( fd_set *p_org_set){
+ btif_hl_soc_cb_t *p_scb = NULL;
+ BOOLEAN element_removed = FALSE;
+ btif_hl_mdl_cb_t *p_dcb = NULL ;
+ btif_hl_evt_cb_t evt_param;
+ int len;
+ bt_status_t status;
+
+ BTIF_TRACE_DEBUG1("entering %s",__FUNCTION__);
+ if (!GKI_queue_is_empty(&soc_queue))
+ {
+ p_scb = (btif_hl_soc_cb_t *)GKI_getfirst((void *)&soc_queue);
+ while (p_scb != NULL)
+ {
+ if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_REL)
+ {
+ BTIF_TRACE_DEBUG3("app_idx=%d mcl_id=%d, mdl_idx=%d",
+ p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx);
+ btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_IDLE);
+ if (p_scb->socket_id[1] != -1)
+ {
+ FD_CLR(p_scb->socket_id[1] , p_org_set);
+ shutdown(p_scb->socket_id[1], SHUT_RDWR);
+ close(p_scb->socket_id[1]);
+
+ evt_param.chan_cb.app_id = (int) btif_hl_get_app_id(p_scb->channel_id);
+ memcpy(evt_param.chan_cb.bd_addr, p_scb->bd_addr, sizeof(BD_ADDR));
+ evt_param.chan_cb.channel_id = p_scb->channel_id;
+ evt_param.chan_cb.fd = p_scb->socket_id[0];
+ evt_param.chan_cb.mdep_cfg_index = (int ) p_scb->mdep_cfg_idx;
+ evt_param.chan_cb.cb_state = BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING;
+ len = sizeof(btif_hl_send_chan_state_cb_t);
+ status = btif_transfer_context (btif_hl_proc_cb_evt, BTIF_HL_SEND_DISCONNECTED_CB,
+ (char*) &evt_param, len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+
+
+
+ }
+ }
+ p_scb = (btif_hl_soc_cb_t *)GKI_getnext((void *)p_scb );
+ BTIF_TRACE_DEBUG1("while loop next p_scb=0x%x", p_scb);
+ }
+
+ p_scb = (btif_hl_soc_cb_t *)GKI_getfirst((void *)&soc_queue);
+ while (p_scb != NULL)
+ {
+ if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_IDLE)
+ {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx);
+ BTIF_TRACE_DEBUG4("idle socket app_idx=%d mcl_id=%d, mdl_idx=%d p_dcb->in_use=%d",
+ p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx, p_dcb->in_use);
+ GKI_remove_from_queue((void *)&soc_queue, p_scb);
+ btif_hl_free_buf((void **)&p_scb);
+ p_dcb->p_scb = NULL;
+ element_removed = TRUE;
+ }
+ BTIF_TRACE_DEBUG2("element_removed=%d p_scb=0x%x", element_removed, p_scb);
+ if (element_removed)
+ {
+ element_removed = FALSE;
+ p_scb = (btif_hl_soc_cb_t *)GKI_getfirst((void *)&soc_queue);
+ }
+ else
+ p_scb = (btif_hl_soc_cb_t *)GKI_getnext((void *)p_scb );
+
+ BTIF_TRACE_DEBUG1("while loop p_scb=0x%x", p_scb);
+ }
+ }
+ BTIF_TRACE_DEBUG1("leaving %s",__FUNCTION__);
+}
+/*******************************************************************************
+**
+** Function btif_hl_select_wakeup_callback
+**
+** Description Select wakup callback to add or close a socket
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_hl_select_wakeup_callback( fd_set *p_org_set , int wakeup_signal){
+ BTIF_TRACE_DEBUG2("entering %s wakeup_signal=0x%04x",__FUNCTION__, wakeup_signal);
+
+ if (wakeup_signal == btif_hl_signal_select_wakeup )
+ {
+ btif_hl_add_socket_to_set(p_org_set);
+ }
+ else if (wakeup_signal == btif_hl_signal_select_close_connected)
+ {
+ btif_hl_close_socket(p_org_set);
+ }
+ BTIF_TRACE_DEBUG1("leaving %s",__FUNCTION__);
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_select_monitor_callback
+**
+** Description Select monitor callback to check pending socket actions
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_select_monitor_callback( fd_set *p_cur_set , fd_set *p_org_set){
+ btif_hl_soc_cb_t *p_scb = NULL;
+ btif_hl_mdl_cb_t *p_dcb = NULL;
+ int r;
+
+ BTIF_TRACE_DEBUG1("entering %s",__FUNCTION__);
+
+ if (!GKI_queue_is_empty(&soc_queue))
+ {
+ p_scb = (btif_hl_soc_cb_t *)GKI_getfirst((void *)&soc_queue);
+ BTIF_TRACE_DEBUG0(" GKI queue is not empty ");
+ while (p_scb != NULL)
+ {
+ if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_READ)
+ {
+ if (FD_ISSET(p_scb->socket_id[1], p_cur_set))
+ {
+ BTIF_TRACE_DEBUG0("read data");
+ BTIF_TRACE_DEBUG0("state= BTIF_HL_SOC_STATE_W4_READ");
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx);
+ if (p_dcb->p_tx_pkt)
+ {
+ BTIF_TRACE_ERROR1("Rcv new pkt but the last pkt is still not been sent tx_size=%d", p_dcb->tx_size);
+ btif_hl_free_buf((void **) &p_dcb->p_tx_pkt);
+ }
+ p_dcb->p_tx_pkt = btif_hl_get_buf (p_dcb->mtu);
+ if (p_dcb )
+ {
+ //do
+ // {
+ // r = recv(p_scb->socket_id[1], p_dcb->p_tx_pkt, p_dcb->mtu , MSG_DONTWAIT));
+ // } while (r == SOCKET_ERROR && errno == EINTR);
+
+ if ((r = (int)recv(p_scb->socket_id[1], p_dcb->p_tx_pkt, p_dcb->mtu , MSG_DONTWAIT)) > 0)
+ {
+ BTIF_TRACE_DEBUG1("btif_hl_select_monitor_callback send data r =%d", r);
+ p_dcb->tx_size = r;
+ BTIF_TRACE_DEBUG1("btif_hl_select_monitor_callback send data tx_size=%d", p_dcb->tx_size );
+ BTA_HlSendData(p_dcb->mdl_handle, p_dcb->tx_size );
+ }
+
+ if (r <= 0 )
+ {
+ BTIF_TRACE_DEBUG1("btif_hl_select_monitor_callback receive failed r=%d",r);
+ BTA_HlDchClose(p_dcb->mdl_handle );
+ }
+ }
+ }
+ }
+ p_scb = (btif_hl_soc_cb_t *)GKI_getnext((void *)p_scb );
+ }
+ }
+ else
+ {
+ BTIF_TRACE_DEBUG0("btif_hl_select_monitor_queue is empty");
+ }
+ BTIF_TRACE_DEBUG1("leaving %s",__FUNCTION__);
+}
+/*******************************************************************************
+**
+** Function btif_hl_select_wakeup_init
+**
+** Description select loop wakup init
+**
+** Returns int
+**
+*******************************************************************************/
+static inline int btif_hl_select_wakeup_init(fd_set* set){
+ BTIF_TRACE_DEBUG0("btif_hl_select_wakeup_init");
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds) < 0)
+ {
+ BTIF_TRACE_ERROR1("socketpair failed: %s", strerror(errno));
+ return -1;
+ }
+
+ BTIF_TRACE_DEBUG2("btif_hl_select_wakeup_init signal_fds[0]=%d signal_fds[1]=%d",signal_fds[0], signal_fds[1] );
+ FD_SET(signal_fds[0], set);
+
+ return signal_fds[0];
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_select_wakeup
+**
+** Description send a signal to wakupo the select loop
+**
+** Returns int
+**
+*******************************************************************************/
+static inline int btif_hl_select_wakeup(void){
+ char sig_on = btif_hl_signal_select_wakeup;
+ BTIF_TRACE_DEBUG0("btif_hl_select_wakeup");
+ return send(signal_fds[1], &sig_on, sizeof(sig_on), 0);
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_select_close_connected
+**
+** Description send a signal to close a socket
+**
+** Returns int
+**
+*******************************************************************************/
+static inline int btif_hl_select_close_connected(void){
+ char sig_on = btif_hl_signal_select_close_connected;
+ BTIF_TRACE_DEBUG0("btif_hl_select_close_connected");
+ return send(signal_fds[1], &sig_on, sizeof(sig_on), 0);
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_close_select_thread
+**
+** Description send signal to close the thread and then close all signal FDs
+**
+** Returns int
+**
+*******************************************************************************/
+static inline int btif_hl_close_select_thread(void)
+{
+ int result = 0;
+ char sig_on = btif_hl_signal_select_exit;
+ BTIF_TRACE_DEBUG0("btif_hl_signal_select_exit");
+ result = send(signal_fds[1], &sig_on, sizeof(sig_on), 0);
+ /* Wait for the select_thread_id to exit */
+ if (select_thread_id != -1) {
+ pthread_join(select_thread_id, NULL);
+ select_thread_id = -1;
+ }
+ /* Cleanup signal sockets */
+ if(signal_fds[0] != -1)
+ {
+ close(signal_fds[0]);
+ signal_fds[0] = -1;
+ }
+ if(signal_fds[1] != -1)
+ {
+ close(signal_fds[1]);
+ signal_fds[1] = -1;
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_select_wake_reset
+**
+** Description clear the received signal for the select loop
+**
+** Returns int
+**
+*******************************************************************************/
+static inline int btif_hl_select_wake_reset(void){
+ char sig_recv = 0;
+
+ BTIF_TRACE_DEBUG0("btif_hl_select_wake_reset");
+ recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL);
+ return(int)sig_recv;
+}
+/*******************************************************************************
+**
+** Function btif_hl_select_wake_signaled
+**
+** Description check whether a fd is set or not
+**
+** Returns int
+**
+*******************************************************************************/
+static inline int btif_hl_select_wake_signaled(fd_set* set){
+ BTIF_TRACE_DEBUG0("btif_hl_select_wake_signaled");
+ return FD_ISSET(signal_fds[0], set);
+}
+/*******************************************************************************
+**
+** Function btif_hl_thread_cleanup
+**
+** Description shut down and clean up the select loop
+**
+** Returns void
+**
+*******************************************************************************/
+static void btif_hl_thread_cleanup(){
+ if (listen_s != -1)
+ close(listen_s);
+ if (connected_s != -1)
+ {
+ shutdown(connected_s, SHUT_RDWR);
+ close(connected_s);
+ }
+ listen_s = connected_s = -1;
+ BTIF_TRACE_DEBUG0("hl thread cleanup");
+}
+/*******************************************************************************
+**
+** Function btif_hl_select_thread
+**
+** Description the select loop
+**
+** Returns void
+**
+*******************************************************************************/
+static void *btif_hl_select_thread(void *arg){
+ fd_set org_set, curr_set;
+ int r, max_curr_s, max_org_s;
+
+ BTIF_TRACE_DEBUG0("entered btif_hl_select_thread");
+ FD_ZERO(&org_set);
+ max_org_s = btif_hl_select_wakeup_init(&org_set);
+ BTIF_TRACE_DEBUG1("max_s=%d ", max_org_s);
+
+ for (;;)
+ {
+ r = 0;
+ BTIF_TRACE_DEBUG0("set curr_set = org_set ");
+ curr_set = org_set;
+ max_curr_s = max_org_s;
+ int ret = select((max_curr_s + 1), &curr_set, NULL, NULL, NULL);
+ BTIF_TRACE_DEBUG1("select unblocked ret=%d", ret);
+ if (ret == -1)
+ {
+ BTIF_TRACE_DEBUG0("select() ret -1, exit the thread");
+ btif_hl_thread_cleanup();
+ select_thread_id = -1;
+ return 0;
+ }
+ else if (ret)
+ {
+ BTIF_TRACE_DEBUG1("btif_hl_select_wake_signaled, signal ret=%d", ret);
+ if (btif_hl_select_wake_signaled(&curr_set))
+ {
+ r = btif_hl_select_wake_reset();
+ BTIF_TRACE_DEBUG1("btif_hl_select_wake_signaled, signal:%d", r);
+ if (r == btif_hl_signal_select_wakeup || r == btif_hl_signal_select_close_connected )
+ {
+ btif_hl_select_wakeup_callback(&org_set, r);
+ }
+ else if( r == btif_hl_signal_select_exit)
+ {
+ btif_hl_thread_cleanup();
+ BTIF_TRACE_DEBUG0("Exit hl_select_thread for btif_hl_signal_select_exit");
+ return 0;
+ }
+ }
+
+ btif_hl_select_monitor_callback(&curr_set, &org_set);
+ max_org_s = btif_hl_update_maxfd(max_org_s);
+ }
+ else
+ BTIF_TRACE_DEBUG1("no data, select ret: %d\n", ret);
+ }
+ BTIF_TRACE_DEBUG0("leaving hl_select_thread");
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function create_thread
+**
+** Description creat a select loop
+**
+** Returns pthread_t
+**
+*******************************************************************************/
+static inline pthread_t create_thread(void *(*start_routine)(void *), void * arg){
+ BTIF_TRACE_DEBUG0("create_thread: entered");
+ pthread_attr_t thread_attr;
+
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ pthread_t thread_id = -1;
+ if ( pthread_create(&thread_id, &thread_attr, start_routine, arg)!=0 )
+ {
+ BTIF_TRACE_ERROR1("pthread_create : %s", strerror(errno));
+ return -1;
+ }
+ BTIF_TRACE_DEBUG0("create_thread: thread created successfully");
+ return thread_id;
+}
+
+/*******************************************************************************
+**
+** Function btif_hl_soc_thread_init
+**
+** Description HL select loop init function.
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_hl_soc_thread_init(void){
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ GKI_init_q(&soc_queue);
+ select_thread_id = create_thread(btif_hl_select_thread, NULL);
+}
+/*******************************************************************************
+**
+** Function btif_hl_load_mdl_config
+**
+** Description load the MDL configuation from the application control block
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN btif_hl_load_mdl_config (UINT8 app_id, UINT8 buffer_size,
+ tBTA_HL_MDL_CFG *p_mdl_buf ){
+ UINT8 app_idx;
+ BOOLEAN result = FALSE;
+ btif_hl_app_cb_t *p_acb;
+ tBTA_HL_MDL_CFG *p;
+ int i;
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ for (i=0, p=p_mdl_buf; i<buffer_size; i++, p++)
+ {
+ memcpy(p, &p_acb->mdl_cfg[i].base, sizeof(tBTA_HL_MDL_CFG));
+ }
+ result = TRUE;
+ }
+
+ BTIF_TRACE_DEBUG1("result=%d", result);
+ return result;
+}
diff --git a/btif/src/btif_media_task.c b/btif/src/btif_media_task.c
new file mode 100755
index 0000000..8978cf6
--- /dev/null
+++ b/btif/src/btif_media_task.c
@@ -0,0 +1,2287 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ **
+ ** Name: btif_media_task.c
+ **
+ ** Description: This is the multimedia module for the BTIF system. It
+ ** contains task implementations AV, HS and HF profiles
+ ** audio & video processing
+ **
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "bt_target.h"
+#include "gki.h"
+#include "bta_api.h"
+#include "btu.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+
+#include "bta_av_api.h"
+#include "a2d_api.h"
+#include "a2d_sbc.h"
+#include "a2d_int.h"
+#include "bta_av_sbc.h"
+#include "bta_av_ci.h"
+#include "l2c_api.h"
+
+
+#include "btif_av_co.h"
+#include "btif_media.h"
+
+
+#if (BTA_AV_INCLUDED == TRUE)
+#include "sbc_encoder.h"
+#endif
+
+#define LOG_TAG "BTIF-MEDIA"
+
+#include <hardware/bluetooth.h>
+#include "audio_a2dp_hw.h"
+#include "btif_av.h"
+#include "btif_sm.h"
+#include "btif_util.h"
+#include "bt_utils.h"
+
+/*****************************************************************************
+ ** Constants
+ *****************************************************************************/
+
+//#define DEBUG_MEDIA_AV_FLOW TRUE
+
+/* BTIF media task gki event definition */
+#define BTIF_MEDIA_TASK_CMD TASK_MBOX_0_EVT_MASK
+#define BTIF_MEDIA_TASK_DATA TASK_MBOX_1_EVT_MASK
+
+#define BTIF_MEDIA_TASK_KILL EVENT_MASK(GKI_SHUTDOWN_EVT)
+
+#define BTIF_MEDIA_AA_TASK_TIMER_ID TIMER_0
+#define BTIF_MEDIA_AV_TASK_TIMER_ID TIMER_1
+#define BTIF_MEDIA_AA_TASK_TIMER TIMER_0_EVT_MASK
+#define BTIF_MEDIA_AV_TASK_TIMER TIMER_1_EVT_MASK
+
+#define BTIF_MEDIA_TASK_CMD_MBOX TASK_MBOX_0 /* cmd mailbox */
+#define BTIF_MEDIA_TASK_DATA_MBOX TASK_MBOX_1 /* data mailbox */
+
+/* BTIF media cmd event definition : BTIF_MEDIA_TASK_CMD */
+enum
+{
+ BTIF_MEDIA_START_AA_TX = 1,
+ BTIF_MEDIA_STOP_AA_TX,
+ BTIF_MEDIA_AA_RX_RDY,
+ BTIF_MEDIA_UIPC_RX_RDY,
+ BTIF_MEDIA_SBC_ENC_INIT,
+ BTIF_MEDIA_SBC_ENC_UPDATE,
+ BTIF_MEDIA_SBC_DEC_INIT,
+ BTIF_MEDIA_VIDEO_DEC_INIT,
+ BTIF_MEDIA_FLUSH_AA_TX,
+ BTIF_MEDIA_FLUSH_AA_RX,
+ BTIF_MEDIA_AUDIO_FEEDING_INIT,
+ BTIF_MEDIA_AUDIO_RECEIVING_INIT
+};
+
+enum {
+ MEDIA_TASK_STATE_OFF = 0,
+ MEDIA_TASK_STATE_ON = 1,
+ MEDIA_TASK_STATE_SHUTTING_DOWN = 2
+};
+
+/* Macro to multiply the media task tick */
+#ifndef BTIF_MEDIA_NUM_TICK
+#define BTIF_MEDIA_NUM_TICK 1
+#endif
+
+/* Media task tick in milliseconds */
+#define BTIF_MEDIA_TIME_TICK (20 * BTIF_MEDIA_NUM_TICK)
+
+/* Number of frames per media task tick.
+ Configure value rounded up to closest integer and
+ adjust any deltas in btif_get_num_aa_frame */
+
+/* 7.5 frames/tick @ 20 ms tick (every 2nd frame send one less) */
+#define BTIF_MEDIA_FR_PER_TICKS_48 (8 * BTIF_MEDIA_NUM_TICK)
+
+/* 6.89 frames/tick @ 20 ms tick (7 out of 64 frames send one less */
+#define BTIF_MEDIA_FR_PER_TICKS_44_1 (7 * BTIF_MEDIA_NUM_TICK)
+
+/* 5.0 frames/tick @ 20 ms tick */
+#define BTIF_MEDIA_FR_PER_TICKS_32 (5 * BTIF_MEDIA_NUM_TICK)
+
+/* 2.5 frames/tick @ 20 ms tick (every 2nd frame send one less) */
+#define BTIF_MEDIA_FR_PER_TICKS_16 (3 * BTIF_MEDIA_NUM_TICK)
+
+
+/* buffer pool */
+#define BTIF_MEDIA_AA_POOL_ID GKI_POOL_ID_3
+#define BTIF_MEDIA_AA_BUF_SIZE GKI_BUF3_SIZE
+
+/* offset */
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define BTIF_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE + 1)
+#else
+#define BTIF_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE)
+#endif
+
+/* Define the bitrate step when trying to match bitpool value */
+#ifndef BTIF_MEDIA_BITRATE_STEP
+#define BTIF_MEDIA_BITRATE_STEP 5
+#endif
+
+/* Middle quality quality setting @ 44.1 khz */
+#define DEFAULT_SBC_BITRATE 229
+
+#ifndef A2DP_MEDIA_TASK_STACK_SIZE
+#define A2DP_MEDIA_TASK_STACK_SIZE 0x2000 /* In bytes */
+#endif
+
+#define A2DP_MEDIA_TASK_TASK_STR ((INT8 *) "A2DP-MEDIA")
+static UINT32 a2dp_media_task_stack[(A2DP_MEDIA_TASK_STACK_SIZE + 3) / 4];
+
+#define BT_MEDIA_TASK A2DP_MEDIA_TASK
+
+#define USEC_PER_SEC 1000000L
+#define TPUT_STATS_INTERVAL_US (1000*1000)
+
+/*
+ * CONGESTION COMPENSATION CTRL ::
+ *
+ * Thus setting controls how many buffers we will hold in media task
+ * during temp link congestion. Together with the stack buffer queues
+ * it controls much temporary a2dp link congestion we can
+ * compensate for. It however also depends on the default run level of sinks
+ * jitterbuffers. Depending on type of sink this would vary.
+ * Ideally the (SRC) max tx buffer capacity should equal the sinks
+ * jitterbuffer runlevel including any intermediate buffers on the way
+ * towards the sinks codec.
+ */
+
+/* fixme -- define this in pcm time instead of buffer count */
+/* fixme -- tune optimal value. For now set a large buffer capacity */
+#define MAX_OUTPUT_BUFFER_QUEUE_SZ 24
+
+//#define BTIF_MEDIA_VERBOSE_ENABLED
+
+#ifdef BTIF_MEDIA_VERBOSE_ENABLED
+#define VERBOSE(fmt, ...) \
+ LogMsg( TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_ERROR, fmt, ## __VA_ARGS__)
+#else
+#define VERBOSE(fmt, ...)
+#endif
+
+/*****************************************************************************
+ ** Data types
+ *****************************************************************************/
+
+typedef struct
+{
+ UINT32 aa_frame_counter;
+ INT32 aa_feed_counter;
+ INT32 aa_feed_residue;
+} tBTIF_AV_MEDIA_FEEDINGS_PCM_STATE;
+
+
+typedef union
+{
+ tBTIF_AV_MEDIA_FEEDINGS_PCM_STATE pcm;
+} tBTIF_AV_MEDIA_FEEDINGS_STATE;
+
+typedef struct
+{
+#if (BTA_AV_INCLUDED == TRUE)
+ BUFFER_Q TxAaQ;
+ BOOLEAN is_tx_timer;
+ UINT16 TxAaMtuSize;
+ UINT32 timestamp;
+ UINT8 TxTranscoding;
+ tBTIF_AV_FEEDING_MODE feeding_mode;
+ tBTIF_AV_MEDIA_FEEDINGS media_feeding;
+ tBTIF_AV_MEDIA_FEEDINGS_STATE media_feeding_state;
+ SBC_ENC_PARAMS encoder;
+ UINT8 busy_level;
+ void* av_sm_hdl;
+ UINT8 a2dp_cmd_pending; /* we can have max one command pending */
+ BOOLEAN tx_flush; /* discards any outgoing data when true */
+ BOOLEAN scaling_disabled;
+#endif
+
+} tBTIF_MEDIA_CB;
+
+typedef struct {
+ int rx;
+ int rx_tot;
+ int tx;
+ int tx_tot;
+ int ts_prev_us;
+} t_stat;
+
+/*****************************************************************************
+ ** Local data
+ *****************************************************************************/
+
+static tBTIF_MEDIA_CB btif_media_cb;
+static int media_task_running = MEDIA_TASK_STATE_OFF;
+
+
+/*****************************************************************************
+ ** Local functions
+ *****************************************************************************/
+
+static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
+static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
+static void btif_a2dp_encoder_update(void);
+
+/*****************************************************************************
+ ** Externs
+ *****************************************************************************/
+
+static void btif_media_task_handle_cmd(BT_HDR *p_msg);
+static void btif_media_task_handle_media(BT_HDR *p_msg);
+
+#if (BTA_AV_INCLUDED == TRUE)
+static void btif_media_send_aa_frame(void);
+static void btif_media_task_feeding_state_reset(void);
+static void btif_media_task_aa_start_tx(void);
+static void btif_media_task_aa_stop_tx(void);
+static void btif_media_task_enc_init(BT_HDR *p_msg);
+static void btif_media_task_enc_update(BT_HDR *p_msg);
+static void btif_media_task_audio_feeding_init(BT_HDR *p_msg);
+static void btif_media_task_aa_tx_flush(BT_HDR *p_msg);
+static void btif_media_aa_prep_2_send(UINT8 nb_frame);
+#endif
+
+
+/*****************************************************************************
+ ** Misc helper functions
+ *****************************************************************************/
+
+static void tput_mon(int is_rx, int len, int reset)
+{
+ /* only monitor one connection at a time for now */
+ static t_stat cur_stat;
+ struct timespec now;
+ unsigned int prev_us;
+ unsigned int now_us;
+
+ if (reset == TRUE)
+ {
+ memset(&cur_stat, 0, sizeof(t_stat));
+ return;
+ }
+
+ if (is_rx)
+ {
+ cur_stat.rx+=len;
+ cur_stat.rx_tot+=len;
+ }
+ else
+ {
+ cur_stat.tx+=len;
+ cur_stat.tx_tot+=len;
+ }
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
+
+ //APPL_TRACE_DEBUG1("%d us", now_us - cur_stat.ts_prev_us);
+
+ if ((now_us - cur_stat.ts_prev_us) < TPUT_STATS_INTERVAL_US)
+ return;
+
+ APPL_TRACE_WARNING4("tput rx:%d, tx:%d (kB/s) (tot : rx %d, tx %d bytes)",
+ (cur_stat.rx)/((now_us - cur_stat.ts_prev_us)/1000),
+ (cur_stat.tx)/((now_us - cur_stat.ts_prev_us)/1000),
+ cur_stat.rx_tot, cur_stat.tx_tot);
+
+ /* stats dumped. now reset stats for next interval */
+ cur_stat.rx = 0;
+ cur_stat.tx = 0;
+ cur_stat.ts_prev_us = now_us;
+}
+
+
+static void log_tstamps_us(char *comment)
+{
+ #define USEC_PER_SEC 1000000L
+ static struct timespec prev = {0, 0};
+ struct timespec now, diff;
+ unsigned int diff_us = 0;
+ unsigned int now_us = 0;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
+ diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
+
+ APPL_TRACE_DEBUG4("[%s] ts %08d, diff : %08d, queue sz %d", comment, now_us, diff_us,
+ btif_media_cb.TxAaQ.count);
+
+ prev = now;
+}
+
+const char* dump_media_event(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTIF_MEDIA_START_AA_TX)
+ CASE_RETURN_STR(BTIF_MEDIA_STOP_AA_TX)
+ CASE_RETURN_STR(BTIF_MEDIA_AA_RX_RDY)
+ CASE_RETURN_STR(BTIF_MEDIA_UIPC_RX_RDY)
+ CASE_RETURN_STR(BTIF_MEDIA_SBC_ENC_INIT)
+ CASE_RETURN_STR(BTIF_MEDIA_SBC_ENC_UPDATE)
+ CASE_RETURN_STR(BTIF_MEDIA_SBC_DEC_INIT)
+ CASE_RETURN_STR(BTIF_MEDIA_VIDEO_DEC_INIT)
+ CASE_RETURN_STR(BTIF_MEDIA_FLUSH_AA_TX)
+ CASE_RETURN_STR(BTIF_MEDIA_FLUSH_AA_RX)
+ CASE_RETURN_STR(BTIF_MEDIA_AUDIO_FEEDING_INIT)
+ CASE_RETURN_STR(BTIF_MEDIA_AUDIO_RECEIVING_INIT)
+
+ default:
+ return "UNKNOWN MEDIA EVENT";
+ }
+}
+
+/*****************************************************************************
+ ** A2DP CTRL PATH
+ *****************************************************************************/
+
+static const char* dump_a2dp_ctrl_event(UINT8 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(A2DP_CTRL_CMD_NONE)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_READY)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_START)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+static void btif_audiopath_detached(void)
+{
+ APPL_TRACE_EVENT0("## AUDIO PATH DETACHED ##");
+
+ /* send stop request only if we are actively streaming and haven't received
+ a stop request. Potentially audioflinger detached abnormally */
+ if (btif_media_cb.is_tx_timer)
+ {
+ /* post stop event and wait for audio path to stop */
+ btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+ }
+}
+
+static void a2dp_cmd_acknowledge(int status)
+{
+ UINT8 ack = status;
+
+ APPL_TRACE_EVENT2("## a2dp ack : %s, status %d ##", dump_a2dp_ctrl_event(btif_media_cb.a2dp_cmd_pending), status);
+
+ /* sanity check */
+ if (btif_media_cb.a2dp_cmd_pending == A2DP_CTRL_CMD_NONE)
+ {
+ APPL_TRACE_ERROR0("warning : no command pending, ignore ack");
+ return;
+ }
+
+ /* clear pending */
+ btif_media_cb.a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+
+ /* acknowledge start request */
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &ack, 1);
+}
+
+
+static void btif_recv_ctrl_data(void)
+{
+ UINT8 cmd = 0;
+ int n;
+
+ n = UIPC_Read(UIPC_CH_ID_AV_CTRL, NULL, &cmd, 1);
+
+ /* detach on ctrl channel means audioflinger process was terminated */
+ if (n == 0)
+ {
+ APPL_TRACE_EVENT0("CTRL CH DETACHED");
+ UIPC_Close(UIPC_CH_ID_AV_CTRL);
+ /* we can operate only on datachannel, if af client wants to
+ do send additional commands the ctrl channel would be reestablished */
+ //btif_audiopath_detached();
+ return;
+ }
+
+ APPL_TRACE_DEBUG1("a2dp-ctrl-cmd : %s", dump_a2dp_ctrl_event(cmd));
+
+ btif_media_cb.a2dp_cmd_pending = cmd;
+
+ switch(cmd)
+ {
+ case A2DP_CTRL_CMD_CHECK_READY:
+
+ if (media_task_running == MEDIA_TASK_STATE_SHUTTING_DOWN)
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ return;
+ }
+
+ /* check whether av is ready to setup a2dp datapath */
+ if ((btif_av_stream_ready() == TRUE) || (btif_av_stream_started_ready() == TRUE))
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+ break;
+
+ case A2DP_CTRL_CMD_START:
+
+ if (btif_av_stream_ready() == TRUE)
+ {
+ /* setup audio data channel listener */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+
+ /* post start event and wait for audio path to open */
+ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+ }
+ else if (btif_av_stream_started_ready())
+ {
+ /* already started, setup audio data channel listener
+ and ack back immediately */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ break;
+ }
+ break;
+
+ case A2DP_CTRL_CMD_STOP:
+
+ if (btif_media_cb.is_tx_timer == FALSE)
+ {
+ /* we are already stopped, just ack back */
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ break;
+ }
+
+ btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+ break;
+
+ case A2DP_CTRL_CMD_SUSPEND:
+ /* local suspend */
+ if (btif_av_stream_started_ready())
+ {
+ btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ }
+ else
+ {
+ /* if we are not in started state, just ack back ok and let
+ audioflinger close the channel. This can happen if we are
+ remotely suspended */
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ break;
+
+ default:
+ APPL_TRACE_ERROR1("UNSUPPORTED CMD (%d)", cmd);
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ break;
+ }
+ APPL_TRACE_DEBUG1("a2dp-ctrl-cmd : %s DONE", dump_a2dp_ctrl_event(cmd));
+}
+
+static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event)
+{
+ APPL_TRACE_DEBUG1("A2DP-CTRL-CHANNEL EVENT %s", dump_uipc_event(event));
+
+ switch(event)
+ {
+ case UIPC_OPEN_EVT:
+ /* fetch av statemachine handle */
+ btif_media_cb.av_sm_hdl = btif_av_get_sm_handle();
+ break;
+
+ case UIPC_CLOSE_EVT:
+ /* restart ctrl server unless we are shutting down */
+ if (media_task_running == MEDIA_TASK_STATE_ON)
+ UIPC_Open(UIPC_CH_ID_AV_CTRL , btif_a2dp_ctrl_cb);
+ break;
+
+ case UIPC_RX_DATA_READY_EVT:
+ btif_recv_ctrl_data();
+ break;
+
+ default :
+ APPL_TRACE_ERROR1("### A2DP-CTRL-CHANNEL EVENT %d NOT HANDLED ###", event);
+ break;
+ }
+}
+
+static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event)
+{
+ APPL_TRACE_DEBUG1("BTIF MEDIA (A2DP-DATA) EVENT %s", dump_uipc_event(event));
+
+ switch(event)
+ {
+ case UIPC_OPEN_EVT:
+
+ /* read directly from media task from here on (keep callback for
+ connection events */
+ UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET, NULL);
+
+ /* Start the media task to encode SBC */
+ btif_media_task_start_aa_req();
+
+ /* make sure we update any changed sbc encoder params */
+ btif_a2dp_encoder_update();
+
+ /* ack back when media task is fully started */
+ break;
+
+ case UIPC_CLOSE_EVT:
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ btif_audiopath_detached();
+ break;
+
+ default :
+ APPL_TRACE_ERROR1("### A2DP-DATA EVENT %d NOT HANDLED ###", event);
+ break;
+ }
+}
+
+
+/*****************************************************************************
+ ** BTIF ADAPTATION
+ *****************************************************************************/
+
+static void btif_a2dp_encoder_init(void)
+{
+ UINT16 minmtu;
+ tBTIF_MEDIA_INIT_AUDIO msg;
+ tA2D_SBC_CIE sbc_config;
+
+ /* lookup table for converting channel mode */
+ UINT16 codec_mode_tbl[5] = { SBC_JOINT_STEREO, SBC_STEREO, SBC_DUAL, 0, SBC_MONO };
+
+ /* lookup table for converting number of blocks */
+ UINT16 codec_block_tbl[5] = { 16, 12, 8, 0, 4 };
+
+ /* lookup table to convert freq */
+ UINT16 freq_block_tbl[5] = { SBC_sf48000, SBC_sf44100, SBC_sf32000, 0, SBC_sf16000 };
+
+ APPL_TRACE_DEBUG0("btif_a2dp_encoder_init");
+
+ /* Retrieve the current SBC configuration (default if currently not used) */
+ bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
+ msg.NumOfSubBands = (sbc_config.num_subbands == A2D_SBC_IE_SUBBAND_4) ? 4 : 8;
+ msg.NumOfBlocks = codec_block_tbl[sbc_config.block_len >> 5];
+ msg.AllocationMethod = (sbc_config.alloc_mthd == A2D_SBC_IE_ALLOC_MD_L) ? SBC_LOUDNESS : SBC_SNR;
+ msg.ChannelMode = codec_mode_tbl[sbc_config.ch_mode >> 1];
+ msg.SamplingFreq = freq_block_tbl[sbc_config.samp_freq >> 5];
+ msg.MtuSize = minmtu;
+
+ APPL_TRACE_EVENT1("msg.ChannelMode %x", msg.ChannelMode);
+
+ /* Init the media task to encode SBC properly */
+ btif_media_task_enc_init_req(&msg);
+}
+
+static void btif_a2dp_encoder_update(void)
+{
+ UINT16 minmtu;
+ tA2D_SBC_CIE sbc_config;
+ tBTIF_MEDIA_UPDATE_AUDIO msg;
+ UINT8 pref_min;
+ UINT8 pref_max;
+
+ APPL_TRACE_DEBUG0("btif_a2dp_encoder_update");
+
+ /* Retrieve the current SBC configuration (default if currently not used) */
+ bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
+
+ APPL_TRACE_DEBUG4("btif_a2dp_encoder_update: Common min_bitpool:%d(0x%x) max_bitpool:%d(0x%x)",
+ sbc_config.min_bitpool, sbc_config.min_bitpool,
+ sbc_config.max_bitpool, sbc_config.max_bitpool);
+
+ if (sbc_config.min_bitpool > sbc_config.max_bitpool)
+ {
+ APPL_TRACE_ERROR0("btif_a2dp_encoder_update: ERROR btif_a2dp_encoder_update min_bitpool > max_bitpool");
+ }
+
+ /* check if remote sink has a preferred bitpool range */
+ if (bta_av_co_get_remote_bitpool_pref(&pref_min, &pref_max) == TRUE)
+ {
+ /* adjust our preferred bitpool with the remote preference if within
+ our capable range */
+
+ if (pref_min < sbc_config.min_bitpool)
+ pref_min = sbc_config.min_bitpool;
+
+ if (pref_max > sbc_config.max_bitpool)
+ pref_max = sbc_config.max_bitpool;
+
+ msg.MinBitPool = pref_min;
+ msg.MaxBitPool = pref_max;
+
+ if ((pref_min != sbc_config.min_bitpool) || (pref_max != sbc_config.max_bitpool))
+ {
+ APPL_TRACE_EVENT2("## adjusted our bitpool range to peer pref [%d:%d] ##",
+ pref_min, pref_max);
+ }
+ }
+ else
+ {
+ msg.MinBitPool = sbc_config.min_bitpool;
+ msg.MaxBitPool = sbc_config.max_bitpool;
+ }
+
+ msg.MinMtuSize = minmtu;
+
+ /* Update the media task to encode SBC properly */
+ btif_media_task_enc_update_req(&msg);
+}
+
+
+/*****************************************************************************
+**
+** Function btif_a2dp_start_media_task
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+int btif_a2dp_start_media_task(void)
+{
+ int retval;
+
+ if (media_task_running != MEDIA_TASK_STATE_OFF)
+ {
+ APPL_TRACE_ERROR0("warning : media task already running");
+ return GKI_FAILURE;
+ }
+
+ APPL_TRACE_EVENT0("## A2DP START MEDIA TASK ##");
+
+ /* start a2dp media task */
+ retval = GKI_create_task((TASKPTR)btif_media_task, A2DP_MEDIA_TASK,
+ A2DP_MEDIA_TASK_TASK_STR,
+ (UINT16 *) ((UINT8 *)a2dp_media_task_stack + A2DP_MEDIA_TASK_STACK_SIZE),
+ sizeof(a2dp_media_task_stack));
+
+ if (retval != GKI_SUCCESS)
+ return retval;
+
+ /* wait for task to come up to sure we are able to send messages to it */
+ while (media_task_running == MEDIA_TASK_STATE_OFF)
+ usleep(10);
+
+ APPL_TRACE_EVENT0("## A2DP MEDIA TASK STARTED ##");
+
+ return retval;
+}
+
+/*****************************************************************************
+**
+** Function btif_a2dp_stop_media_task
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_stop_media_task(void)
+{
+ APPL_TRACE_EVENT0("## A2DP STOP MEDIA TASK ##");
+ GKI_destroy_task(BT_MEDIA_TASK);
+}
+
+/*****************************************************************************
+**
+** Function btif_a2dp_on_init
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_on_init(void)
+{
+ //tput_mon(1, 0, 1);
+}
+
+
+/*****************************************************************************
+**
+** Function btif_a2dp_setup_codec
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_setup_codec(void)
+{
+ tBTIF_AV_MEDIA_FEEDINGS media_feeding;
+ tBTIF_STATUS status;
+
+ APPL_TRACE_EVENT0("## A2DP SETUP CODEC ##");
+
+ GKI_disable();
+
+ /* for now hardcode 44.1 khz 16 bit stereo */
+ media_feeding.cfg.pcm.sampling_freq = 44100;
+ media_feeding.cfg.pcm.bit_per_sample = 16;
+ media_feeding.cfg.pcm.num_channel = 2;
+ media_feeding.format = BTIF_AV_CODEC_PCM;
+
+ if (bta_av_co_audio_set_codec(&media_feeding, &status))
+ {
+ tBTIF_MEDIA_INIT_AUDIO_FEEDING mfeed;
+
+ /* Init the encoding task */
+ btif_a2dp_encoder_init();
+
+ /* Build the media task configuration */
+ mfeed.feeding = media_feeding;
+ mfeed.feeding_mode = BTIF_AV_FEEDING_ASYNCHRONOUS;
+ /* Send message to Media task to configure transcoding */
+ btif_media_task_audio_feeding_init_req(&mfeed);
+ }
+
+ GKI_enable();
+}
+
+
+/*****************************************************************************
+**
+** Function btif_a2dp_on_idle
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_on_idle(void)
+{
+ APPL_TRACE_EVENT0("## ON A2DP IDLE ##");
+
+ /* Make sure media task is stopped */
+ btif_media_task_stop_aa_req();
+
+ bta_av_co_init();
+}
+
+/*****************************************************************************
+**
+** Function btif_a2dp_on_open
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_on_open(void)
+{
+ APPL_TRACE_EVENT0("## ON A2DP OPEN ##");
+
+ /* always use callback to notify socket events */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+}
+
+/*****************************************************************************
+**
+** Function btif_a2dp_on_started
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_on_started(tBTA_AV_START *p_av)
+{
+ tBTIF_AV_MEDIA_FEEDINGS media_feeding;
+ tBTIF_STATUS status;
+
+ APPL_TRACE_EVENT0("## ON A2DP STARTED ##");
+
+ if (p_av->status == BTA_AV_SUCCESS)
+ {
+ if (p_av->suspending == FALSE)
+ {
+ if (p_av->initiator)
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);
+ }
+ else
+ {
+ /* we were remotely started, make sure codec
+ is setup before datapath is started */
+ btif_a2dp_setup_codec();
+ }
+
+ /* media task is autostarted upon a2dp audiopath connection */
+ }
+ }
+ else
+ {
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+}
+
+
+/*****************************************************************************
+**
+** Function btif_a2dp_on_stopped
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av)
+{
+ APPL_TRACE_EVENT0("## ON A2DP STOPPED ##");
+
+ /* allow using this api for other than suspend */
+ if (p_av != NULL)
+ {
+ if (p_av->status != BTA_AV_SUCCESS)
+ {
+ APPL_TRACE_EVENT1("AV STOP FAILED (%d)", p_av->status);
+
+ if (p_av->initiator)
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ return;
+ }
+ }
+
+ /* ensure tx frames are immediately suspended */
+ btif_media_cb.tx_flush = 1;
+
+ /* request to stop media task */
+ btif_media_task_aa_tx_flush_req();
+ btif_media_task_stop_aa_req();
+
+ /* once stream is fully stopped we will ack back */
+}
+
+
+/*****************************************************************************
+**
+** Function btif_a2dp_on_suspended
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+
+void btif_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av)
+{
+ APPL_TRACE_EVENT0("## ON A2DP SUSPENDED ##");
+
+ /* check for status failures */
+ if (p_av->status != BTA_AV_SUCCESS)
+ {
+ if (p_av->initiator == TRUE)
+ a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
+ }
+
+ /* once stream is fully stopped we will ack back */
+
+ /* ensure tx frames are immediately flushed */
+ btif_media_cb.tx_flush = 1;
+
+ /* stop timer tick */
+ btif_media_task_stop_aa_req();
+}
+
+/* when true media task discards any tx frames */
+void btif_a2dp_set_tx_flush(BOOLEAN enable)
+{
+ APPL_TRACE_EVENT1("## DROP TX %d ##", enable);
+ btif_media_cb.tx_flush = enable;
+}
+
+/*****************************************************************************
+**
+** Function btif_calc_pcmtime
+**
+** Description Calculates the pcmtime equivalent of a datapacket
+**
+** Returns microseconds
+**
+*******************************************************************************/
+
+static int btif_calc_pcmtime(UINT32 bytes_processed)
+{
+ int pcm_time_us = 0;
+ tBTIF_AV_MEDIA_FEED_CFG *p_cfg;
+
+ p_cfg = &btif_media_cb.media_feeding.cfg;
+
+ /* calculate corresponding pcm time based on data processed */
+ switch(btif_media_cb.media_feeding.format)
+ {
+ case BTIF_AV_CODEC_PCM:
+ pcm_time_us = (bytes_processed*1000000)/
+ (p_cfg->pcm.num_channel*p_cfg->pcm.sampling_freq*p_cfg->pcm.bit_per_sample/8);
+ break;
+
+ default :
+ APPL_TRACE_ERROR1("mediafeeding format invalid : %d", btif_media_cb.media_feeding.format);
+ break;
+ }
+
+ return pcm_time_us;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_aa_handle_timer
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+
+static void btif_media_task_aa_handle_timer(void)
+{
+#if (defined(DEBUG_MEDIA_AV_FLOW) && (DEBUG_MEDIA_AV_FLOW == TRUE))
+ static UINT16 Debug = 0;
+ APPL_TRACE_DEBUG1("btif_media_task_aa_handle_timer: %d", Debug++);
+#endif
+
+ log_tstamps_us("media task tx timer");
+
+#if (BTA_AV_INCLUDED == TRUE)
+ btif_media_send_aa_frame();
+#endif
+}
+
+#if (BTA_AV_INCLUDED == TRUE)
+/*******************************************************************************
+ **
+ ** Function btif_media_task_aa_handle_timer
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_aa_handle_uipc_rx_rdy(void)
+{
+#if (defined(DEBUG_MEDIA_AV_FLOW) && (DEBUG_MEDIA_AV_FLOW == TRUE))
+ static UINT16 Debug = 0;
+ APPL_TRACE_DEBUG1("btif_media_task_aa_handle_uipc_rx_rdy: %d", Debug++);
+#endif
+
+ /* process all the UIPC data */
+ btif_media_aa_prep_2_send(0xFF);
+
+ /* send it */
+ VERBOSE("btif_media_task_aa_handle_uipc_rx_rdy calls bta_av_ci_src_data_ready");
+ bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
+}
+#endif
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_init
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+
+void btif_media_task_init(void)
+{
+ memset(&(btif_media_cb), 0, sizeof(btif_media_cb));
+
+ UIPC_Init(NULL);
+
+#if (BTA_AV_INCLUDED == TRUE)
+ UIPC_Open(UIPC_CH_ID_AV_CTRL , btif_a2dp_ctrl_cb);
+#endif
+
+
+}
+/*******************************************************************************
+ **
+ ** Function btif_media_task
+ **
+ ** Description Task for SBC encoder. This task receives an
+ ** event when the waveIn interface has a pcm data buffer
+ ** ready. On receiving the event, handle all ready pcm
+ ** data buffers. If stream is started, run the SBC encoder
+ ** on each chunk of pcm samples and build an output packet
+ ** consisting of one or more encoded SBC frames.
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+int btif_media_task(void *p)
+{
+ UINT16 event;
+ BT_HDR *p_msg;
+
+ VERBOSE("================ MEDIA TASK STARTING ================");
+
+ btif_media_task_init();
+
+ media_task_running = MEDIA_TASK_STATE_ON;
+
+ raise_priority_a2dp(TASK_HIGH_MEDIA);
+
+ while (1)
+ {
+ event = GKI_wait(0xffff, 0);
+
+ VERBOSE("================= MEDIA TASK EVENT %d ===============", event);
+
+ if (event & BTIF_MEDIA_TASK_CMD)
+ {
+ /* Process all messages in the queue */
+ while ((p_msg = (BT_HDR *) GKI_read_mbox(BTIF_MEDIA_TASK_CMD_MBOX)) != NULL)
+ {
+ btif_media_task_handle_cmd(p_msg);
+ }
+ }
+
+ if (event & BTIF_MEDIA_TASK_DATA)
+ {
+ /* Process all messages in the queue */
+ while ((p_msg = (BT_HDR *) GKI_read_mbox(BTIF_MEDIA_TASK_DATA_MBOX)) != NULL)
+ {
+ btif_media_task_handle_media(p_msg);
+ }
+ }
+
+ if (event & BTIF_MEDIA_AA_TASK_TIMER)
+ {
+ /* advance audio timer expiration */
+ btif_media_task_aa_handle_timer();
+ }
+
+
+ VERBOSE("=============== MEDIA TASK EVENT %d DONE ============", event);
+
+ /* When we get this event we exit the task - should only happen on GKI_shutdown */
+ if (event & BTIF_MEDIA_TASK_KILL)
+ {
+ /* make sure no channels are restarted while shutting down */
+ media_task_running = MEDIA_TASK_STATE_SHUTTING_DOWN;
+
+ /* this calls blocks until uipc is fully closed */
+ UIPC_Close(UIPC_CH_ID_ALL);
+ break;
+ }
+ }
+
+ /* Clear media task flag */
+ media_task_running = MEDIA_TASK_STATE_OFF;
+
+ APPL_TRACE_DEBUG0("MEDIA TASK EXITING");
+
+ return 0;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_send_cmd_evt
+ **
+ ** Description
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+BOOLEAN btif_media_task_send_cmd_evt(UINT16 Evt)
+{
+ BT_HDR *p_buf;
+ if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR))))
+ {
+ return FALSE;
+ }
+
+ p_buf->event = Evt;
+
+ GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf);
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_flush_q
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_flush_q(BUFFER_Q *p_q)
+{
+ while (GKI_IS_QUEUE_EMPTY(p_q) == FALSE)
+ {
+ GKI_freebuf(GKI_dequeue(p_q));
+ }
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_handle_cmd
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_handle_cmd(BT_HDR *p_msg)
+{
+ VERBOSE("btif_media_task_handle_cmd : %d %s", p_msg->event, dump_media_event(p_msg->event));
+
+ switch (p_msg->event)
+ {
+#if (BTA_AV_INCLUDED == TRUE)
+ case BTIF_MEDIA_START_AA_TX:
+ btif_media_task_aa_start_tx();
+ break;
+ case BTIF_MEDIA_STOP_AA_TX:
+ btif_media_task_aa_stop_tx();
+ break;
+ case BTIF_MEDIA_SBC_ENC_INIT:
+ btif_media_task_enc_init(p_msg);
+ break;
+ case BTIF_MEDIA_SBC_ENC_UPDATE:
+ btif_media_task_enc_update(p_msg);
+ break;
+ case BTIF_MEDIA_AUDIO_FEEDING_INIT:
+ btif_media_task_audio_feeding_init(p_msg);
+ break;
+ case BTIF_MEDIA_FLUSH_AA_TX:
+ btif_media_task_aa_tx_flush(p_msg);
+ break;
+ case BTIF_MEDIA_UIPC_RX_RDY:
+ btif_media_task_aa_handle_uipc_rx_rdy();
+ break;
+#endif
+ default:
+ APPL_TRACE_ERROR1("ERROR in btif_media_task_handle_cmd unknown event %d", p_msg->event);
+ }
+ GKI_freebuf(p_msg);
+ VERBOSE("btif_media_task_handle_cmd : %s DONE", dump_media_event(p_msg->event));
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_handle_media
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_handle_media(BT_HDR *p_msg)
+{
+ APPL_TRACE_ERROR0("ERROR btif_media_task_handle_media: not in use");
+
+ GKI_freebuf(p_msg);
+}
+
+
+
+
+#if (BTA_AV_INCLUDED == TRUE)
+/*******************************************************************************
+ **
+ ** Function btif_media_task_enc_init_req
+ **
+ ** Description
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+BOOLEAN btif_media_task_enc_init_req(tBTIF_MEDIA_INIT_AUDIO *p_msg)
+{
+ tBTIF_MEDIA_INIT_AUDIO *p_buf;
+ if (NULL == (p_buf = GKI_getbuf(sizeof(tBTIF_MEDIA_INIT_AUDIO))))
+ {
+ return FALSE;
+ }
+
+ memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_INIT_AUDIO));
+ p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_INIT;
+
+ GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf);
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_enc_update_req
+ **
+ ** Description
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+BOOLEAN btif_media_task_enc_update_req(tBTIF_MEDIA_UPDATE_AUDIO *p_msg)
+{
+ tBTIF_MEDIA_UPDATE_AUDIO *p_buf;
+ if (NULL == (p_buf = GKI_getbuf(sizeof(tBTIF_MEDIA_UPDATE_AUDIO))))
+ {
+ return FALSE;
+ }
+
+ memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_UPDATE_AUDIO));
+ p_buf->hdr.event = BTIF_MEDIA_SBC_ENC_UPDATE;
+
+ GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf);
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_audio_feeding_init_req
+ **
+ ** Description
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+BOOLEAN btif_media_task_audio_feeding_init_req(tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_msg)
+{
+ tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_buf;
+ if (NULL == (p_buf = GKI_getbuf(sizeof(tBTIF_MEDIA_INIT_AUDIO_FEEDING))))
+ {
+ return FALSE;
+ }
+
+ memcpy(p_buf, p_msg, sizeof(tBTIF_MEDIA_INIT_AUDIO_FEEDING));
+ p_buf->hdr.event = BTIF_MEDIA_AUDIO_FEEDING_INIT;
+
+ GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf);
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_start_aa_req
+ **
+ ** Description
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+BOOLEAN btif_media_task_start_aa_req(void)
+{
+ BT_HDR *p_buf;
+ if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR))))
+ {
+ APPL_TRACE_EVENT0("GKI failed");
+ return FALSE;
+ }
+
+ p_buf->event = BTIF_MEDIA_START_AA_TX;
+
+ GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf);
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_stop_aa_req
+ **
+ ** Description
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+BOOLEAN btif_media_task_stop_aa_req(void)
+{
+ BT_HDR *p_buf;
+ if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR))))
+ {
+ return FALSE;
+ }
+
+ p_buf->event = BTIF_MEDIA_STOP_AA_TX;
+
+ GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf);
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_aa_tx_flush_req
+ **
+ ** Description
+ **
+ ** Returns TRUE is success
+ **
+ *******************************************************************************/
+BOOLEAN btif_media_task_aa_tx_flush_req(void)
+{
+ BT_HDR *p_buf;
+ if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR))))
+ {
+ return FALSE;
+ }
+
+ p_buf->event = BTIF_MEDIA_FLUSH_AA_TX;
+
+ GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_buf);
+ return TRUE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_aa_tx_flush
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_aa_tx_flush(BT_HDR *p_msg)
+{
+ /* Flush all enqueued GKI music buffers (encoded) */
+ APPL_TRACE_DEBUG0("btif_media_task_aa_tx_flush");
+
+ btif_media_flush_q(&(btif_media_cb.TxAaQ));
+
+ UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, NULL);
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_enc_init
+ **
+ ** Description Initialize encoding task
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_enc_init(BT_HDR *p_msg)
+{
+ tBTIF_MEDIA_INIT_AUDIO *pInitAudio = (tBTIF_MEDIA_INIT_AUDIO *) p_msg;
+
+ APPL_TRACE_DEBUG0("btif_media_task_enc_init");
+
+ btif_media_cb.timestamp = 0;
+
+ /* SBC encoder config (enforced even if not used) */
+ btif_media_cb.encoder.s16ChannelMode = pInitAudio->ChannelMode;
+ btif_media_cb.encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
+ btif_media_cb.encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks;
+ btif_media_cb.encoder.s16AllocationMethod = pInitAudio->AllocationMethod;
+ btif_media_cb.encoder.s16SamplingFreq = pInitAudio->SamplingFreq;
+
+ btif_media_cb.encoder.u16BitRate = DEFAULT_SBC_BITRATE;
+ /* Default transcoding is PCM to SBC, modified by feeding configuration */
+ btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_SBC;
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE-BTIF_MEDIA_AA_SBC_OFFSET-sizeof(BT_HDR))
+ < pInitAudio->MtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET
+ - sizeof(BT_HDR)) : pInitAudio->MtuSize;
+
+ APPL_TRACE_EVENT3("btif_media_task_enc_init busy %d, mtu %d, peer mtu %d",
+ btif_media_cb.busy_level, btif_media_cb.TxAaMtuSize, pInitAudio->MtuSize);
+ APPL_TRACE_EVENT6(" ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d",
+ btif_media_cb.encoder.s16ChannelMode, btif_media_cb.encoder.s16NumOfSubBands,
+ btif_media_cb.encoder.s16NumOfBlocks,
+ btif_media_cb.encoder.s16AllocationMethod, btif_media_cb.encoder.u16BitRate,
+ btif_media_cb.encoder.s16SamplingFreq);
+
+ /* Reset entirely the SBC encoder */
+ SBC_Encoder_Init(&(btif_media_cb.encoder));
+ APPL_TRACE_DEBUG1("btif_media_task_enc_init bit pool %d", btif_media_cb.encoder.s16BitPool);
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_enc_update
+ **
+ ** Description Update encoding task
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+
+static void btif_media_task_enc_update(BT_HDR *p_msg)
+{
+ tBTIF_MEDIA_UPDATE_AUDIO * pUpdateAudio = (tBTIF_MEDIA_UPDATE_AUDIO *) p_msg;
+ SBC_ENC_PARAMS *pstrEncParams = &btif_media_cb.encoder;
+ UINT16 s16SamplingFreq;
+ SINT16 s16BitPool;
+ SINT16 s16BitRate;
+ SINT16 s16FrameLen;
+ UINT8 protect = 0;
+
+ APPL_TRACE_DEBUG3("btif_media_task_enc_update : minmtu %d, maxbp %d minbp %d",
+ pUpdateAudio->MinMtuSize, pUpdateAudio->MaxBitPool, pUpdateAudio->MinBitPool);
+
+ /* Only update the bitrate and MTU size while timer is running to make sure it has been initialized */
+ //if (btif_media_cb.is_tx_timer)
+ {
+ btif_media_cb.TxAaMtuSize = ((BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR))
+ < pUpdateAudio->MinMtuSize) ? (BTIF_MEDIA_AA_BUF_SIZE - BTIF_MEDIA_AA_SBC_OFFSET
+ - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
+
+ /* Set the initial target bit rate */
+ pstrEncParams->u16BitRate = DEFAULT_SBC_BITRATE;
+
+ if (pstrEncParams->s16SamplingFreq == SBC_sf16000)
+ s16SamplingFreq = 16000;
+ else if (pstrEncParams->s16SamplingFreq == SBC_sf32000)
+ s16SamplingFreq = 32000;
+ else if (pstrEncParams->s16SamplingFreq == SBC_sf44100)
+ s16SamplingFreq = 44100;
+ else
+ s16SamplingFreq = 48000;
+
+ do
+ {
+ if ((pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) ||
+ (pstrEncParams->s16ChannelMode == SBC_STEREO) )
+ {
+ s16BitPool = (SINT16)( (pstrEncParams->u16BitRate *
+ pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq)
+ -( (32 + (4 * pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->s16NumOfChannels)
+ + ( (pstrEncParams->s16ChannelMode - 2) *
+ pstrEncParams->s16NumOfSubBands ) )
+ / pstrEncParams->s16NumOfBlocks) );
+
+ s16FrameLen = 4 + (4*pstrEncParams->s16NumOfSubBands*
+ pstrEncParams->s16NumOfChannels)/8
+ + ( ((pstrEncParams->s16ChannelMode - 2) *
+ pstrEncParams->s16NumOfSubBands)
+ + (pstrEncParams->s16NumOfBlocks * s16BitPool) ) / 8;
+
+ s16BitRate = (8 * s16FrameLen * s16SamplingFreq)
+ / (pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->s16NumOfBlocks * 1000);
+
+ if (s16BitRate > pstrEncParams->u16BitRate)
+ s16BitPool--;
+
+ if(pstrEncParams->s16NumOfSubBands == 8)
+ s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool;
+ else
+ s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool;
+ }
+ else
+ {
+ s16BitPool = (SINT16)( ((pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->u16BitRate * 1000)
+ / (s16SamplingFreq * pstrEncParams->s16NumOfChannels))
+ -( ( (32 / pstrEncParams->s16NumOfChannels) +
+ (4 * pstrEncParams->s16NumOfSubBands) )
+ / pstrEncParams->s16NumOfBlocks ) );
+
+ pstrEncParams->s16BitPool = (s16BitPool >
+ (16 * pstrEncParams->s16NumOfSubBands))
+ ? (16*pstrEncParams->s16NumOfSubBands) : s16BitPool;
+ }
+
+ if (s16BitPool < 0)
+ {
+ s16BitPool = 0;
+ }
+
+ APPL_TRACE_EVENT2("bitpool candidate : %d (%d kbps)", s16BitPool, pstrEncParams->u16BitRate);
+
+ if (s16BitPool > pUpdateAudio->MaxBitPool)
+ {
+ APPL_TRACE_WARNING1("btif_media_task_enc_update computed bitpool too large (%d)", s16BitPool);
+ /* Decrease bitrate */
+ btif_media_cb.encoder.u16BitRate -= BTIF_MEDIA_BITRATE_STEP;
+ /* Record that we have decreased the bitrate */
+ protect |= 1;
+ }
+ else if (s16BitPool < pUpdateAudio->MinBitPool)
+ {
+ APPL_TRACE_WARNING1("btif_media_task_enc_update computed bitpool too small (%d)", s16BitPool);
+ /* Increase bitrate */
+ btif_media_cb.encoder.u16BitRate += BTIF_MEDIA_BITRATE_STEP;
+ /* Record that we have increased the bitrate */
+ protect |= 2;
+ }
+ else
+ {
+ break;
+ }
+ /* In case we have already increased and decreased the bitrate, just stop */
+ if (protect == 3)
+ {
+ APPL_TRACE_ERROR0("btif_media_task_enc_update could not find bitpool in range");
+ break;
+ }
+ } while (1);
+
+ /* Finally update the bitpool in the encoder structure */
+ pstrEncParams->s16BitPool = s16BitPool;
+
+ APPL_TRACE_DEBUG2("btif_media_task_enc_update final bit rate %d, final bit pool %d",
+ btif_media_cb.encoder.u16BitRate, btif_media_cb.encoder.s16BitPool);
+
+ /* make sure we reinitialize encoder with new settings */
+ SBC_Encoder_Init(&(btif_media_cb.encoder));
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_pcm2sbc_init
+ **
+ ** Description Init encoding task for PCM to SBC according to feeding
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_pcm2sbc_init(tBTIF_MEDIA_INIT_AUDIO_FEEDING * p_feeding)
+{
+ BOOLEAN reconfig_needed = FALSE;
+
+ APPL_TRACE_DEBUG0("PCM feeding:");
+ APPL_TRACE_DEBUG1("sampling_freq:%d", p_feeding->feeding.cfg.pcm.sampling_freq);
+ APPL_TRACE_DEBUG1("num_channel:%d", p_feeding->feeding.cfg.pcm.num_channel);
+ APPL_TRACE_DEBUG1("bit_per_sample:%d", p_feeding->feeding.cfg.pcm.bit_per_sample);
+
+
+ /* Check the PCM feeding sampling_freq */
+ switch (p_feeding->feeding.cfg.pcm.sampling_freq)
+ {
+ case 8000:
+ case 12000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ /* For these sampling_freq the AV connection must be 48000 */
+ if (btif_media_cb.encoder.s16SamplingFreq != SBC_sf48000)
+ {
+ /* Reconfiguration needed at 48000 */
+ APPL_TRACE_DEBUG0("SBC Reconfiguration needed at 48000");
+ btif_media_cb.encoder.s16SamplingFreq = SBC_sf48000;
+ reconfig_needed = TRUE;
+ }
+ break;
+
+ case 11025:
+ case 22050:
+ case 44100:
+ /* For these sampling_freq the AV connection must be 44100 */
+ if (btif_media_cb.encoder.s16SamplingFreq != SBC_sf44100)
+ {
+ /* Reconfiguration needed at 44100 */
+ APPL_TRACE_DEBUG0("SBC Reconfiguration needed at 44100");
+ btif_media_cb.encoder.s16SamplingFreq = SBC_sf44100;
+ reconfig_needed = TRUE;
+ }
+ break;
+ default:
+ APPL_TRACE_DEBUG0("Feeding PCM sampling_freq unsupported");
+ break;
+ }
+
+ /* Some AV Headsets do not support Mono => always ask for Stereo */
+ if (btif_media_cb.encoder.s16ChannelMode == SBC_MONO)
+ {
+ APPL_TRACE_DEBUG0("SBC Reconfiguration needed in Stereo");
+ btif_media_cb.encoder.s16ChannelMode = SBC_JOINT_STEREO;
+ reconfig_needed = TRUE;
+ }
+
+ if (reconfig_needed != FALSE)
+ {
+ APPL_TRACE_DEBUG0("btif_media_task_pcm2sbc_init calls SBC_Encoder_Init");
+ APPL_TRACE_DEBUG1("btif_media_task_pcm2sbc_init mtu %d", btif_media_cb.TxAaMtuSize);
+ APPL_TRACE_DEBUG6("btif_media_task_pcm2sbc_init ch mode %d, nbsubd %d, nb blk %d, alloc method %d, bit rate %d, Smp freq %d",
+ btif_media_cb.encoder.s16ChannelMode, btif_media_cb.encoder.s16NumOfSubBands, btif_media_cb.encoder.s16NumOfBlocks,
+ btif_media_cb.encoder.s16AllocationMethod, btif_media_cb.encoder.u16BitRate, btif_media_cb.encoder.s16SamplingFreq);
+ SBC_Encoder_Init(&(btif_media_cb.encoder));
+ }
+ else
+ {
+ APPL_TRACE_DEBUG0("btif_media_task_pcm2sbc_init no SBC reconfig needed");
+ }
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_audio_feeding_init
+ **
+ ** Description Initialize the audio path according to the feeding format
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_audio_feeding_init(BT_HDR *p_msg)
+{
+ tBTIF_MEDIA_INIT_AUDIO_FEEDING *p_feeding = (tBTIF_MEDIA_INIT_AUDIO_FEEDING *) p_msg;
+
+ APPL_TRACE_DEBUG1("btif_media_task_audio_feeding_init format:%d", p_feeding->feeding.format);
+
+ /* Save Media Feeding information */
+ btif_media_cb.feeding_mode = p_feeding->feeding_mode;
+ btif_media_cb.media_feeding = p_feeding->feeding;
+
+ /* Handle different feeding formats */
+ switch (p_feeding->feeding.format)
+ {
+ case BTIF_AV_CODEC_PCM:
+ btif_media_cb.TxTranscoding = BTIF_MEDIA_TRSCD_PCM_2_SBC;
+ btif_media_task_pcm2sbc_init(p_feeding);
+ break;
+
+ default :
+ APPL_TRACE_ERROR1("unknown feeding format %d", p_feeding->feeding.format);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_uipc_cback
+ **
+ ** Description UIPC call back function for synchronous mode only
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_uipc_cback(BT_HDR *p_msg)
+{
+ /* Sanity check */
+ if (NULL == p_msg)
+ {
+ return;
+ }
+
+ /* Just handle RX_EVT */
+ if (p_msg->event != UIPC_RX_DATA_EVT)
+ {
+ return;
+ }
+
+ p_msg->event = BTIF_MEDIA_UIPC_RX_RDY;
+
+ GKI_send_msg(BT_MEDIA_TASK, BTIF_MEDIA_TASK_CMD_MBOX, p_msg);
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_feeding_state_reset
+ **
+ ** Description Reset the media feeding state
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_feeding_state_reset(void)
+{
+ /* By default, just clear the entire state */
+ memset(&btif_media_cb.media_feeding_state, 0, sizeof(btif_media_cb.media_feeding_state));
+}
+/*******************************************************************************
+ **
+ ** Function btif_media_task_aa_start_tx
+ **
+ ** Description Start media task encoding
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_aa_start_tx(void)
+{
+ APPL_TRACE_DEBUG2("btif_media_task_aa_start_tx is timer %d, feeding mode %d",
+ btif_media_cb.is_tx_timer, btif_media_cb.feeding_mode);
+
+
+ /* Use a timer to poll the UIPC, get rid of the UIPC call back */
+ // UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REG_CBACK, NULL);
+
+ btif_media_cb.is_tx_timer = TRUE;
+
+ /* Reset the media feeding state */
+ btif_media_task_feeding_state_reset();
+
+ APPL_TRACE_EVENT2("starting timer %d ticks (%d)", GKI_MS_TO_TICKS(BTIF_MEDIA_TIME_TICK), TICKS_PER_SEC);
+ GKI_start_timer(BTIF_MEDIA_AA_TASK_TIMER_ID, GKI_MS_TO_TICKS(BTIF_MEDIA_TIME_TICK), TRUE);
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_task_aa_stop_tx
+ **
+ ** Description Stop media task encoding
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_task_aa_stop_tx(void)
+{
+ APPL_TRACE_DEBUG1("btif_media_task_aa_stop_tx is timer: %d", btif_media_cb.is_tx_timer);
+
+ /* Stop the timer first */
+ GKI_stop_timer(BTIF_MEDIA_AA_TASK_TIMER_ID);
+ btif_media_cb.is_tx_timer = FALSE;
+
+ UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+
+ /* audio engine stopped, reset tx suspended flag */
+ btif_media_cb.tx_flush = 0;
+
+ /* Reset the media feeding state */
+ btif_media_task_feeding_state_reset();
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_get_num_aa_frame
+ **
+ ** Description
+ **
+ ** Returns The number of media frames in this time slice
+ **
+ *******************************************************************************/
+
+
+static UINT8 btif_get_num_aa_frame(void)
+{
+ UINT8 result=0;
+
+ switch (btif_media_cb.TxTranscoding)
+ {
+ case BTIF_MEDIA_TRSCD_PCM_2_SBC:
+ switch (btif_media_cb.encoder.s16SamplingFreq)
+ {
+ case SBC_sf16000:
+ if (!btif_media_cb.scaling_disabled &&
+ (btif_media_cb.media_feeding_state.pcm.aa_frame_counter++ % 2) == 0)
+ {
+ result = BTIF_MEDIA_FR_PER_TICKS_16-1;
+ }
+ else
+ {
+ result = BTIF_MEDIA_FR_PER_TICKS_16;
+ }
+ break;
+
+ case SBC_sf32000:
+ result = BTIF_MEDIA_FR_PER_TICKS_32;
+ break;
+
+ case SBC_sf48000:
+ if (!btif_media_cb.scaling_disabled &&
+ (btif_media_cb.media_feeding_state.pcm.aa_frame_counter++ % 2) == 0)
+ {
+ result = BTIF_MEDIA_FR_PER_TICKS_48-1;
+ }
+ else
+ {
+ result = BTIF_MEDIA_FR_PER_TICKS_48;
+ }
+ break;
+
+ case SBC_sf44100:
+ if (!btif_media_cb.scaling_disabled &&
+ (btif_media_cb.media_feeding_state.pcm.aa_frame_counter++ % 64) < 7)
+ {
+ result = BTIF_MEDIA_FR_PER_TICKS_44_1-1;
+ }
+ else
+ {
+ result = BTIF_MEDIA_FR_PER_TICKS_44_1;
+ }
+ break;
+ }
+
+ VERBOSE("WRITE %d FRAMES", result);
+ break;
+
+ default:
+ APPL_TRACE_ERROR1("ERROR btif_get_num_aa_frame Unsupported transcoding format 0x%x",
+ btif_media_cb.TxTranscoding);
+ result = 0;
+ break;
+ }
+
+#if (defined(DEBUG_MEDIA_AV_FLOW) && (DEBUG_MEDIA_AV_FLOW == TRUE))
+ APPL_TRACE_DEBUG1("btif_get_num_aa_frame returns %d", result);
+#endif
+
+ return result;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_aa_readbuf
+ **
+ ** Description This function is called by the av_co to get the next buffer to send
+ **
+ **
+ ** Returns void
+ *******************************************************************************/
+BT_HDR *btif_media_aa_readbuf(void)
+{
+ return GKI_dequeue(&(btif_media_cb.TxAaQ));
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_aa_read_feeding
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+
+BOOLEAN btif_media_aa_read_feeding(tUIPC_CH_ID channel_id)
+{
+ UINT16 event;
+ /* coverity[SIGN_EXTENSION] False-positive: Parameter are always in range avoiding sign extension*/
+ UINT16 blocm_x_subband = btif_media_cb.encoder.s16NumOfSubBands * btif_media_cb.encoder.s16NumOfBlocks;
+ UINT32 read_size;
+ UINT16 sbc_sampling = 48000;
+ UINT32 src_samples;
+ UINT16 bytes_needed = blocm_x_subband * btif_media_cb.encoder.s16NumOfChannels * sizeof(SINT16);
+ static UINT16 up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
+ * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2];
+ static UINT16 read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
+ * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS];
+ UINT32 src_size_used;
+ UINT32 dst_size_used;
+ BOOLEAN fract_needed;
+ INT32 fract_max;
+ INT32 fract_threshold;
+ UINT32 nb_byte_read;
+
+ /* Get the SBC sampling rate */
+ switch (btif_media_cb.encoder.s16SamplingFreq)
+ {
+ case SBC_sf48000:
+ sbc_sampling = 48000;
+ break;
+ case SBC_sf44100:
+ sbc_sampling = 44100;
+ break;
+ case SBC_sf32000:
+ sbc_sampling = 32000;
+ break;
+ case SBC_sf16000:
+ sbc_sampling = 16000;
+ break;
+ }
+
+ /* Some Feeding PCM frequencies require to split the number of sample */
+ /* to read. */
+ /* E.g 128/6=21.3333 => read 22 and 21 and 21 => max = 2; threshold = 0*/
+ fract_needed = FALSE; /* Default */
+ switch (btif_media_cb.media_feeding.cfg.pcm.sampling_freq)
+ {
+ case 32000:
+ case 8000:
+ fract_needed = TRUE;
+ fract_max = 2; /* 0, 1 and 2 */
+ fract_threshold = 0; /* Add one for the first */
+ break;
+ case 16000:
+ fract_needed = TRUE;
+ fract_max = 2; /* 0, 1 and 2 */
+ fract_threshold = 1; /* Add one for the first two frames*/
+ break;
+ }
+
+ /* Compute number of sample to read from source */
+ src_samples = blocm_x_subband;
+ src_samples *= btif_media_cb.media_feeding.cfg.pcm.sampling_freq;
+ src_samples /= sbc_sampling;
+
+ /* The previous division may have a remainder not null */
+ if (fract_needed)
+ {
+ if (btif_media_cb.media_feeding_state.pcm.aa_feed_counter <= fract_threshold)
+ {
+ src_samples++; /* for every read before threshold add one sample */
+ }
+
+ /* do nothing if counter >= threshold */
+ btif_media_cb.media_feeding_state.pcm.aa_feed_counter++; /* one more read */
+ if (btif_media_cb.media_feeding_state.pcm.aa_feed_counter > fract_max)
+ {
+ btif_media_cb.media_feeding_state.pcm.aa_feed_counter = 0;
+ }
+ }
+
+ /* Compute number of bytes to read from source */
+ read_size = src_samples;
+ read_size *= btif_media_cb.media_feeding.cfg.pcm.num_channel;
+ read_size *= (btif_media_cb.media_feeding.cfg.pcm.bit_per_sample / 8);
+
+ /* Read Data from UIPC channel */
+ nb_byte_read = UIPC_Read(channel_id, &event, (UINT8 *)read_buffer, read_size);
+
+ //tput_mon(TRUE, nb_byte_read, FALSE);
+
+ if (nb_byte_read < read_size)
+ {
+ APPL_TRACE_WARNING2("### UNDERRUN :: ONLY READ %d BYTES OUT OF %d ###",
+ nb_byte_read, read_size);
+
+ if (nb_byte_read == 0)
+ return FALSE;
+
+ if(btif_media_cb.feeding_mode == BTIF_AV_FEEDING_ASYNCHRONOUS)
+ {
+ /* Fill the unfilled part of the read buffer with silence (0) */
+ memset(((UINT8 *)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
+ nb_byte_read = read_size;
+ }
+ }
+
+ /* Initialize PCM up-sampling engine */
+ bta_av_sbc_init_up_sample(btif_media_cb.media_feeding.cfg.pcm.sampling_freq,
+ sbc_sampling, btif_media_cb.media_feeding.cfg.pcm.bit_per_sample,
+ btif_media_cb.media_feeding.cfg.pcm.num_channel);
+
+ /* re-sample read buffer */
+ /* The output PCM buffer will be stereo, 16 bit per sec */
+ dst_size_used = bta_av_sbc_up_sample((UINT8 *)read_buffer,
+ (UINT8 *)up_sampled_buffer + btif_media_cb.media_feeding_state.pcm.aa_feed_residue,
+ nb_byte_read,
+ sizeof(up_sampled_buffer) - btif_media_cb.media_feeding_state.pcm.aa_feed_residue,
+ &src_size_used);
+
+#if (defined(DEBUG_MEDIA_AV_FLOW) && (DEBUG_MEDIA_AV_FLOW == TRUE))
+ APPL_TRACE_DEBUG3("btif_media_aa_read_feeding read_size:%d src_size_used:%d dst_size_used:%d",
+ read_size, src_size_used, dst_size_used);
+#endif
+
+ /* update the residue */
+ btif_media_cb.media_feeding_state.pcm.aa_feed_residue += dst_size_used;
+
+ /* only copy the pcm sample when we have up-sampled enough PCM */
+ if(btif_media_cb.media_feeding_state.pcm.aa_feed_residue >= bytes_needed)
+ {
+ /* Copy the output pcm samples in SBC encoding buffer */
+ memcpy((UINT8 *)btif_media_cb.encoder.as16PcmBuffer,
+ (UINT8 *)up_sampled_buffer,
+ bytes_needed);
+ /* update the residue */
+ btif_media_cb.media_feeding_state.pcm.aa_feed_residue -= bytes_needed;
+
+ if (btif_media_cb.media_feeding_state.pcm.aa_feed_residue != 0)
+ {
+ memcpy((UINT8 *)up_sampled_buffer,
+ (UINT8 *)up_sampled_buffer + bytes_needed,
+ btif_media_cb.media_feeding_state.pcm.aa_feed_residue);
+ }
+ return TRUE;
+ }
+
+#if (defined(DEBUG_MEDIA_AV_FLOW) && (DEBUG_MEDIA_AV_FLOW == TRUE))
+ APPL_TRACE_DEBUG3("btif_media_aa_read_feeding residue:%d, dst_size_used %d, bytes_needed %d",
+ btif_media_cb.media_feeding_state.pcm.aa_feed_residue, dst_size_used, bytes_needed);
+#endif
+
+ return FALSE;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_aa_prep_sbc_2_send
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_aa_prep_sbc_2_send(UINT8 nb_frame)
+{
+ BT_HDR * p_buf;
+ UINT16 blocm_x_subband = btif_media_cb.encoder.s16NumOfSubBands * btif_media_cb.encoder.s16NumOfBlocks;
+
+#if (defined(DEBUG_MEDIA_AV_FLOW) && (DEBUG_MEDIA_AV_FLOW == TRUE))
+ APPL_TRACE_DEBUG2("btif_media_aa_prep_sbc_2_send nb_frame %d, TxAaQ %d", nb_frame, btif_media_cb.TxAaQ.count);
+#endif
+ while (nb_frame)
+ {
+ if (NULL == (p_buf = GKI_getpoolbuf(BTIF_MEDIA_AA_POOL_ID)))
+ {
+ APPL_TRACE_ERROR1 ("ERROR btif_media_aa_prep_sbc_2_send no buffer TxCnt %d ", btif_media_cb.TxAaQ.count);
+ return;
+ }
+
+ /* Init buffer */
+ p_buf->offset = BTIF_MEDIA_AA_SBC_OFFSET;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+
+ do
+ {
+ /* Write @ of allocated buffer in encoder.pu8Packet */
+ btif_media_cb.encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len;
+ /* Fill allocated buffer with 0 */
+ /* coverity[SIGN_EXTENSION] False-positive: Parameter are always in range avoiding sign extension*/
+ memset(btif_media_cb.encoder.as16PcmBuffer, 0, blocm_x_subband
+ * btif_media_cb.encoder.s16NumOfChannels);
+
+ /* Read PCM data and upsample them if needed */
+ if (btif_media_aa_read_feeding(UIPC_CH_ID_AV_AUDIO))
+ {
+ /* SBC encode and descramble frame */
+ SBC_Encoder(&(btif_media_cb.encoder));
+ A2D_SbcChkFrInit(btif_media_cb.encoder.pu8Packet);
+ A2D_SbcDescramble(btif_media_cb.encoder.pu8Packet, btif_media_cb.encoder.u16PacketLength);
+ /* Update SBC frame length */
+ p_buf->len += btif_media_cb.encoder.u16PacketLength;
+ nb_frame--;
+ p_buf->layer_specific++;
+ }
+ else
+ {
+ /* no more pcm to read */
+ nb_frame = 0;
+
+ /* break read loop if timer was stopped (media task stopped) */
+ if ( btif_media_cb.is_tx_timer == FALSE )
+ return;
+ }
+
+ } while (((p_buf->len + btif_media_cb.encoder.u16PacketLength) < btif_media_cb.TxAaMtuSize)
+ && (p_buf->layer_specific < 0x0F) && nb_frame);
+
+ /* coverity[SIGN_EXTENSION] False-positive: Parameter are always in range avoiding sign extension*/
+ btif_media_cb.timestamp += p_buf->layer_specific * blocm_x_subband;
+
+ /* store the time stamp in the buffer to send */
+ *((UINT32 *) (p_buf + 1)) = btif_media_cb.timestamp;
+
+ VERBOSE("TX QUEUE NOW %d", btif_media_cb.TxAaQ.count);
+
+ if (btif_media_cb.tx_flush)
+ {
+ APPL_TRACE_DEBUG0("### tx suspended, discarded frame ###");
+
+ if (btif_media_cb.TxAaQ.count > 0)
+ btif_media_flush_q(&(btif_media_cb.TxAaQ));
+
+ GKI_freebuf(p_buf);
+ return;
+ }
+
+ /* Enqueue the encoded SBC frame in AA Tx Queue */
+ GKI_enqueue(&(btif_media_cb.TxAaQ), p_buf);
+ }
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btif_media_aa_prep_2_send
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+
+static void btif_media_aa_prep_2_send(UINT8 nb_frame)
+{
+ VERBOSE("btif_media_aa_prep_2_send : %d frames (queue %d)", nb_frame,
+ btif_media_cb.TxAaQ.count);
+
+ /* Remove all the buffers not sent until there are only 4 in the queue */
+ while (btif_media_cb.TxAaQ.count >= MAX_OUTPUT_BUFFER_QUEUE_SZ)
+ {
+ APPL_TRACE_WARNING1("btif_media_aa_prep_2_send congestion buf count %d",btif_media_cb.TxAaQ.count);
+ GKI_freebuf(GKI_dequeue(&(btif_media_cb.TxAaQ)));
+ }
+
+ switch (btif_media_cb.TxTranscoding)
+ {
+ case BTIF_MEDIA_TRSCD_PCM_2_SBC:
+ btif_media_aa_prep_sbc_2_send(nb_frame);
+ break;
+
+
+ default:
+ APPL_TRACE_ERROR1("ERROR btif_media_aa_prep_2_send unsupported transcoding format 0x%x",btif_media_cb.TxTranscoding);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_send_aa_frame
+ **
+ ** Description
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btif_media_send_aa_frame(void)
+{
+ UINT8 nb_frame_2_send;
+
+ /* get the number of frame to send */
+ nb_frame_2_send = btif_get_num_aa_frame();
+
+ /* format and Q buffer to send */
+ btif_media_aa_prep_2_send(nb_frame_2_send);
+
+ /* send it */
+ VERBOSE("btif_media_send_aa_frame : send %d frames", nb_frame_2_send);
+ bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_media_check_iop_exceptions
+ **
+ ** Description Perform any device specific iop changes
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+
+void btif_media_check_iop_exceptions(UINT8 *peer_bda)
+{
+ /* disable rate scaling for pcm carkit */
+ if ((peer_bda[0] == 0x00) &&
+ (peer_bda[1] == 0x0E) &&
+ (peer_bda[2] == 0x9F))
+ {
+ BTIF_TRACE_WARNING0("detected pcm carkit, disable rate scaling");
+ btif_media_cb.scaling_disabled = TRUE;
+ }
+ else
+ {
+ btif_media_cb.scaling_disabled = FALSE;
+ }
+}
+
+
+#endif /* BTA_AV_INCLUDED == TRUE */
+
+/*******************************************************************************
+ **
+ ** Function dump_codec_info
+ **
+ ** Description Decode and display codec_info (for debug)
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void dump_codec_info(unsigned char *p_codec)
+{
+ tA2D_STATUS a2d_status;
+ tA2D_SBC_CIE sbc_cie;
+
+ a2d_status = A2D_ParsSbcInfo(&sbc_cie, p_codec, FALSE);
+ if (a2d_status != A2D_SUCCESS)
+ {
+ APPL_TRACE_ERROR1("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d", a2d_status);
+ return;
+ }
+
+ APPL_TRACE_DEBUG0("dump_codec_info");
+
+ if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_16)
+ { APPL_TRACE_DEBUG1("\tsamp_freq:%d (16000)", sbc_cie.samp_freq);}
+ else if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_32)
+ { APPL_TRACE_DEBUG1("\tsamp_freq:%d (32000)", sbc_cie.samp_freq);}
+ else if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_44)
+ { APPL_TRACE_DEBUG1("\tsamp_freq:%d (44.100)", sbc_cie.samp_freq);}
+ else if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_48)
+ { APPL_TRACE_DEBUG1("\tsamp_freq:%d (48000)", sbc_cie.samp_freq);}
+ else
+ { APPL_TRACE_DEBUG1("\tBAD samp_freq:%d", sbc_cie.samp_freq);}
+
+ if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_MONO)
+ { APPL_TRACE_DEBUG1("\tch_mode:%d (Mono)", sbc_cie.ch_mode);}
+ else if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_DUAL)
+ { APPL_TRACE_DEBUG1("\tch_mode:%d (Dual)", sbc_cie.ch_mode);}
+ else if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_STEREO)
+ { APPL_TRACE_DEBUG1("\tch_mode:%d (Stereo)", sbc_cie.ch_mode);}
+ else if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_JOINT)
+ { APPL_TRACE_DEBUG1("\tch_mode:%d (Joint)", sbc_cie.ch_mode);}
+ else
+ { APPL_TRACE_DEBUG1("\tBAD ch_mode:%d", sbc_cie.ch_mode);}
+
+ if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_4)
+ { APPL_TRACE_DEBUG1("\tblock_len:%d (4)", sbc_cie.block_len);}
+ else if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_8)
+ { APPL_TRACE_DEBUG1("\tblock_len:%d (8)", sbc_cie.block_len);}
+ else if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_12)
+ { APPL_TRACE_DEBUG1("\tblock_len:%d (12)", sbc_cie.block_len);}
+ else if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_16)
+ { APPL_TRACE_DEBUG1("\tblock_len:%d (16)", sbc_cie.block_len);}
+ else
+ { APPL_TRACE_DEBUG1("\tBAD block_len:%d", sbc_cie.block_len);}
+
+ if (sbc_cie.num_subbands == A2D_SBC_IE_SUBBAND_4)
+ { APPL_TRACE_DEBUG1("\tnum_subbands:%d (4)", sbc_cie.num_subbands);}
+ else if (sbc_cie.num_subbands == A2D_SBC_IE_SUBBAND_8)
+ { APPL_TRACE_DEBUG1("\tnum_subbands:%d (8)", sbc_cie.num_subbands);}
+ else
+ { APPL_TRACE_DEBUG1("\tBAD num_subbands:%d", sbc_cie.num_subbands);}
+
+ if (sbc_cie.alloc_mthd == A2D_SBC_IE_ALLOC_MD_S)
+ { APPL_TRACE_DEBUG1("\talloc_mthd:%d (SNR)", sbc_cie.alloc_mthd);}
+ else if (sbc_cie.alloc_mthd == A2D_SBC_IE_ALLOC_MD_L)
+ { APPL_TRACE_DEBUG1("\talloc_mthd:%d (Loundess)", sbc_cie.alloc_mthd);}
+ else
+ { APPL_TRACE_DEBUG1("\tBAD alloc_mthd:%d", sbc_cie.alloc_mthd);}
+
+ APPL_TRACE_DEBUG2("\tBit pool Min:%d Max:%d", sbc_cie.min_bitpool, sbc_cie.max_bitpool);
+
+}
+
diff --git a/btif/src/btif_pan.c b/btif/src/btif_pan.c
new file mode 100644
index 0000000..2f6c932
--- /dev/null
+++ b/btif/src/btif_pan.c
@@ -0,0 +1,668 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_pan.c
+ *
+ * Description: PAN Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <hardware/bluetooth.h>
+#include <hardware/bt_pan.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <sys/prctl.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+
+#define LOG_TAG "BTIF_PAN"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "bd.h"
+
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+#include "btif_pan_internal.h"
+
+//#define PANU_DISABLED TRUE
+
+#if (PAN_NAP_DISABLED == TRUE) && (PANU_DISABLED == TRUE)
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_NONE
+#elif PAN_NAP_DISABLED == TRUE
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_PANU
+#elif PANU_DISABLED == TRUE
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_PANNAP
+#else
+#define BTPAN_LOCAL_ROLE (BTPAN_ROLE_PANU | BTPAN_ROLE_PANNAP)
+#endif
+
+
+
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("btif_pan: %s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("btif_pan: %s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define warn(fmt, ...) ALOGW ("btif_pan: ## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("btif_pan: ## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("btif_pan: ## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+
+
+btpan_cb_t btpan_cb;
+
+BD_ADDR local_addr;
+static int jni_initialized, stack_initialized;
+static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks);
+static void btpan_jni_cleanup();
+static bt_status_t btpan_connect(const bt_bdaddr_t *bd_addr, int local_role, int remote_role);
+static bt_status_t btpan_disconnect(const bt_bdaddr_t *bd_addr);
+static bt_status_t btpan_enable(int local_role);
+static int btpan_get_local_role(void);
+
+static void btpan_tap_fd_signaled(int fd, int type, int flags, uint32_t user_id);
+static void btpan_cleanup_conn(btpan_conn_t* conn);
+static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN *p_data);
+/*******************************************************************************
+ **
+ ** Function btpan_ini
+ **
+ ** Description initializes the pan interface
+ **
+ ** Returns bt_status_t
+ **
+ *******************************************************************************/
+static btpan_interface_t pan_if = {
+ sizeof(pan_if),
+ btpan_jni_init,
+ btpan_enable,
+ btpan_get_local_role,
+ btpan_connect,
+ btpan_disconnect,
+ btpan_jni_cleanup
+};
+btpan_interface_t *btif_pan_get_interface()
+{
+ return &pan_if;
+}
+void btif_pan_init()
+{
+ debug("jni_initialized = %d, btpan_cb.enabled:%d", jni_initialized, btpan_cb.enabled);
+ stack_initialized = TRUE;
+ if (jni_initialized && !btpan_cb.enabled)
+ {
+ debug("Enabling PAN....");
+ memset(&btpan_cb, 0, sizeof(btpan_cb));
+ btpan_cb.tap_fd = -1;
+ int i;
+ for(i = 0; i < MAX_PAN_CONNS; i++)
+ btpan_cleanup_conn(&btpan_cb.conns[i]);
+ BTA_PanEnable(bta_pan_callback);
+ btpan_cb.enabled = 1;
+ btpan_enable(BTPAN_LOCAL_ROLE);
+ }
+ debug("leaving");
+}
+static void pan_disable()
+{
+ if(btpan_cb.enabled)
+ {
+ btpan_cb.enabled = 0;
+ BTA_PanDisable();
+ if(btpan_cb.tap_fd != -1)
+ {
+ destroy_tap_read_thread();
+ btpan_tap_close(btpan_cb.tap_fd);
+ btpan_cb.tap_fd = -1;
+ }
+ }
+}
+void btif_pan_cleanup()
+{
+ if(stack_initialized)
+ {
+ //bt is shuting down, invalid all bta pan handles
+ int i;
+ for(i = 0; i < MAX_PAN_CONNS; i++)
+ btpan_cleanup_conn(&btpan_cb.conns[i]);
+ pan_disable();
+ debug("leaving");
+ }
+ stack_initialized = FALSE;
+}
+
+static btpan_callbacks_t callback;
+static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks)
+{
+ debug("stack_initialized = %d, btpan_cb.enabled:%d", stack_initialized, btpan_cb.enabled);
+ jni_initialized = TRUE;
+ if(stack_initialized && !btpan_cb.enabled)
+ btif_pan_init();
+ callback = *callbacks;
+ debug(" leaving");
+ return BT_STATUS_SUCCESS;
+}
+
+static void btpan_jni_cleanup()
+{
+ pan_disable();
+ jni_initialized = FALSE;
+ debug("leaving");
+}
+static inline int bta_role_to_btpan(int bta_pan_role)
+{
+ int btpan_role = 0;
+ debug("bta_pan_role:0x%x", bta_pan_role);
+ if(bta_pan_role & PAN_ROLE_NAP_SERVER)
+ {
+ debug("BTPAN_ROLE_PANNAP");
+ btpan_role |= BTPAN_ROLE_PANNAP;
+ }
+ if(bta_pan_role & PAN_ROLE_CLIENT)
+ {
+ debug("BTPAN_ROLE_PANU");
+ btpan_role |= BTPAN_ROLE_PANU;
+ }
+ return btpan_role;
+}
+static inline int btpan_role_to_bta(int btpan_role)
+{
+ int bta_pan_role = PAN_ROLE_INACTIVE;
+ debug("btpan_role:0x%x", btpan_role);
+ if(btpan_role & BTPAN_ROLE_PANNAP)
+ {
+ debug("BTPAN_ROLE_PANNAP");
+ bta_pan_role |= PAN_ROLE_NAP_SERVER;
+ }
+ if(btpan_role & BTPAN_ROLE_PANU)
+ {
+ debug("BTPAN_ROLE_CLIENT");
+ bta_pan_role |= PAN_ROLE_CLIENT;
+ }
+ return bta_pan_role;
+}
+static volatile int btpan_dev_local_role;
+static tBTA_PAN_ROLE_INFO bta_panu_info = {PANU_SERVICE_NAME, 0, PAN_SECURITY};
+static tBTA_PAN_ROLE_INFO bta_pan_nap_info = {PAN_NAP_SERVICE_NAME, 0, PAN_SECURITY};
+
+static bt_status_t btpan_enable(int local_role)
+{
+ int bta_pan_role;
+ debug("local_role:%d", local_role);
+ bta_pan_role = btpan_role_to_bta(local_role);
+ BTA_PanSetRole(bta_pan_role, &bta_panu_info, NULL, &bta_pan_nap_info);
+ btpan_dev_local_role = local_role;
+ return BT_STATUS_SUCCESS;
+}
+static int btpan_get_local_role()
+{
+ debug("btpan_dev_local_role:%d", btpan_dev_local_role);
+ return btpan_dev_local_role;
+}
+static bt_status_t btpan_connect(const bt_bdaddr_t *bd_addr, int local_role, int remote_role)
+{
+ debug("local_role:%d, remote_role:%d", local_role, remote_role);
+ int bta_local_role = btpan_role_to_bta(local_role);
+ int bta_remote_role = btpan_role_to_bta(remote_role);
+ btpan_new_conn(-1, bd_addr->address, bta_local_role, bta_remote_role);
+ BTA_PanOpen((UINT8*)bd_addr->address, bta_local_role, bta_remote_role);
+ return BT_STATUS_SUCCESS;
+}
+static void btif_in_pan_generic_evt(UINT16 event, char *p_param)
+{
+ BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
+ switch (event) {
+ case BTIF_PAN_CB_DISCONNECTING:
+ {
+ bt_bdaddr_t *bd_addr = (bt_bdaddr_t*)p_param;
+ btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
+ int btpan_conn_local_role;
+ int btpan_remote_role;
+ asrt(conn != NULL);
+ if (conn) {
+ btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+ btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+ callback.connection_state_cb(BTPAN_STATE_DISCONNECTING, BT_STATUS_SUCCESS,
+ (const bt_bdaddr_t*)conn->peer, btpan_conn_local_role, btpan_remote_role);
+ }
+ } break;
+ default:
+ {
+ BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
+ }
+ break;
+ }
+}
+static bt_status_t btpan_disconnect(const bt_bdaddr_t *bd_addr)
+{
+ debug("in");
+ btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
+ if(conn && conn->handle >= 0)
+ {
+ BTA_PanClose(conn->handle);
+ /* Inform the application that the disconnect has been initiated successfully */
+ btif_transfer_context(btif_in_pan_generic_evt, BTIF_PAN_CB_DISCONNECTING,
+ (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+static int pth = -1;
+void create_tap_read_thread(int tap_fd)
+{
+ debug("in");
+ if(pth < 0)
+ {
+ pth = btsock_thread_create(btpan_tap_fd_signaled, NULL);
+ if(pth >= 0)
+ btsock_thread_add_fd(pth, tap_fd, 0, SOCK_THREAD_FD_RD, 0);
+ }
+}
+void destroy_tap_read_thread(void)
+{
+ if(pth >= 0)
+ {
+ btsock_thread_exit(pth);
+ pth = -1;
+ }
+}
+static int tap_if_up(const char *devname, BD_ADDR addr)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
+
+ //set mac addr
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+ if(err < 0)
+ {
+ error("Could not get network hardware for interface:%s, errno:%s", devname, strerror(errno));
+ close(sk);
+ return -1;
+ }
+ debug("found mac address for interface:%s = %02x:%02x:%02x:%02x:%02x:%02x", devname,
+ ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1], ifr.ifr_hwaddr.sa_data[2],
+ ifr.ifr_hwaddr.sa_data[3], ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
+ strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
+ memcpy(ifr.ifr_hwaddr.sa_data, addr, 6);
+ debug("setting bt address for interface:%s = %02x:%02x:%02x:%02x:%02x:%02x", devname,
+ ifr.ifr_hwaddr.sa_data[0], ifr.ifr_hwaddr.sa_data[1], ifr.ifr_hwaddr.sa_data[2],
+ ifr.ifr_hwaddr.sa_data[3], ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);
+
+ err = ioctl(sk, SIOCSIFHWADDR, (caddr_t)&ifr);
+
+ if (err < 0) {
+ error("Could not set bt address for interface:%s, errno:%s", devname, strerror(errno));
+ close(sk);
+ return -1;
+ }
+
+ //bring it up
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+
+ ifr.ifr_flags |= IFF_UP;
+ ifr.ifr_flags |= IFF_MULTICAST;
+
+ err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
+
+
+ if (err < 0) {
+ error("Could not bring up network interface:%s, errno:%d", devname, errno);
+ close(sk);
+ return -1;
+ }
+ close(sk);
+ debug("network interface: %s is up", devname);
+ return 0;
+}
+
+static int tap_if_down(const char *devname)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+
+ ifr.ifr_flags &= ~IFF_UP;
+
+ err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
+
+ close(sk);
+
+ return 0;
+}
+int btpan_tap_open()
+{
+ debug("in");
+ struct ifreq ifr;
+ int fd, err;
+ const char *clonedev = "/dev/tun";
+
+ /* open the clone device */
+
+ //system("insmod /system/lib/modules/tun.ko");
+ if( (fd = open(clonedev, O_RDWR)) < 0 ) {
+
+ debug("could not open %s, err:%d", clonedev, errno);
+ return fd;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+ strncpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);
+
+ /* try to create the device */
+ if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 )//|| tap_setup_ip(TAP_IF_NAME) == FALSE)
+ {
+ debug("ioctl error:%d, errno:%s", err, strerror(errno));
+ close(fd);
+ return err;
+ }
+ BTM_GetLocalDeviceAddr (local_addr);
+ if(tap_if_up(TAP_IF_NAME, local_addr) == 0)
+ {
+ return fd;
+ }
+ error("can not bring up tap interface:%s", TAP_IF_NAME);
+ close(fd);
+ return -1;
+}
+int btpan_tap_send(int tap_fd, const BD_ADDR src, const BD_ADDR dst, UINT16 proto, const char* buf,
+ UINT16 len, BOOLEAN ext, BOOLEAN forward)
+{
+ debug("in");
+ debug("SRC ADDR = %02x:%02x:%02x:%02x:%02x:%02x",
+ src[0], src[1], src[2], src[3],
+ src[4], src[5]);
+ debug("DST ADDR = %02x:%02x:%02x:%02x:%02x:%02x",
+ dst[0], dst[1], dst[2], dst[3],
+ dst[4], dst[5]);
+
+ debug("Protocol = 0x%x", proto);
+ debug("Ext = 0x%x", ext);
+ debug("Forward = 0x%x", forward);
+ debug("Len = %d", len);
+ if(tap_fd != -1)
+ {
+ tETH_HDR eth_hdr;
+ //if(is_empty_eth_addr(dst))
+ // memcpy(&eth_hdr.h_dest, local_addr, ETH_ADDR_LEN);
+ //else
+ memcpy(&eth_hdr.h_dest, dst, ETH_ADDR_LEN);
+ memcpy(&eth_hdr.h_src, src, ETH_ADDR_LEN);
+ eth_hdr.h_proto = htons(proto);
+ char packet[2000];
+ memcpy(packet, &eth_hdr, sizeof(tETH_HDR));
+ if(len > 2000)
+ {
+ ALOGE("btpan_tap_send eth packet size:%d is exceeded limit!", len);
+ return -1;
+ }
+ memcpy(packet + sizeof(tETH_HDR), buf, len);
+
+ /* Send data to network interface */
+ //btnet_send(btpan_cb.conn[i].sock.sock, &buffer, (len + sizeof(tETH_HDR)));
+ //dump_bin("packet to network", packet, len + sizeof(tETH_HDR));
+ int ret = write(tap_fd, packet, len + sizeof(tETH_HDR));
+ debug("ret:%d", ret);
+ return ret;
+ }
+ return -1;
+
+}
+int btpan_tap_close(int fd)
+{
+ debug("in");
+ tap_if_down(TAP_IF_NAME);
+ close(fd);
+ return 0;
+}
+btpan_conn_t * btpan_find_conn_handle(UINT16 handle)
+{
+ int i;
+ for(i = 0; i < MAX_PAN_CONNS; i++)
+ if(btpan_cb.conns[i].handle == handle)
+ return &btpan_cb.conns[i];
+ return NULL;
+}
+btpan_conn_t* btpan_find_conn_addr(const BD_ADDR addr)
+{
+ int i;
+ for(i = 0; i < MAX_PAN_CONNS; i++)
+ if(memcmp(btpan_cb.conns[i].peer, addr, sizeof(BD_ADDR)) == 0)
+ return &btpan_cb.conns[i];
+ return NULL;
+}
+static void btpan_cleanup_conn(btpan_conn_t* conn)
+{
+ if(conn)
+ {
+ conn->handle = -1;
+ conn->state = -1;
+ memset(&conn->peer, 0, sizeof(conn->peer));
+ memset(&conn->eth_addr, 0, sizeof(conn->eth_addr));
+ conn->local_role = conn->remote_role = 0;
+ }
+}
+btpan_conn_t* btpan_new_conn(int handle, const BD_ADDR addr, int local_role, int remote_role )
+{
+ int i;
+ debug("in");
+ for(i = 0; i < MAX_PAN_CONNS; i++)
+ {
+ debug("conns[%d]:%d", i, btpan_cb.conns[i].handle);
+ if(btpan_cb.conns[i].handle == -1)
+ {
+ debug("handle:%d, local_role:%d, remote_role:%d", handle, local_role, remote_role);
+
+ btpan_cb.conns[i].handle = handle;
+ bdcpy(btpan_cb.conns[i].peer, addr);
+ btpan_cb.conns[i].local_role = local_role;
+ btpan_cb.conns[i].remote_role = remote_role;
+ return &btpan_cb.conns[i];
+ }
+ }
+ debug("MAX_PAN_CONNS:%d exceeded, return NULL as failed", MAX_PAN_CONNS);
+ return NULL;
+}
+
+void btpan_close_handle(btpan_conn_t *p)
+{
+ debug("btpan_close_handle : close handle %d", p->handle);
+ p->handle = -1;
+ p->local_role = -1;
+ p->remote_role = -1;
+ memset(&p->peer, 0, 6);
+}
+static inline int should_forward(tETH_HDR* hdr)
+{
+ if(ntohs(hdr->h_proto) == ETH_P_IP || ntohs(hdr->h_proto) == ETH_P_ARP)
+ return TRUE;
+ debug("unknown proto:%x", ntohs(hdr->h_proto));
+ return FALSE;
+}
+extern void bta_pan_ci_rx_write(UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol,
+ UINT8 *p_data, UINT16 len, BOOLEAN ext);
+static void forward_bnep(tETH_HDR* eth_hdr, char * packet, int size)
+{
+ int broadcast = eth_hdr->h_dest[0] & 1;
+ int i;
+ for(i = 0; i < MAX_PAN_CONNS; i++)
+ {
+ UINT16 handle = btpan_cb.conns[i].handle;
+ if(handle != (UINT16)-1 &&
+ (broadcast || memcmp(btpan_cb.conns[i].eth_addr, eth_hdr->h_dest, sizeof(BD_ADDR)) == 0
+ || memcmp(btpan_cb.conns[i].peer, eth_hdr->h_dest, sizeof(BD_ADDR)) == 0))
+ {
+ debug("calling bta_pan_ci_rx_write, handle:%d", handle);
+ bta_pan_ci_rx_write(handle, eth_hdr->h_dest, eth_hdr->h_src,
+ ntohs(eth_hdr->h_proto), (UINT8*)packet, size, 0);
+ break;
+ }
+ }
+}
+
+static void bta_pan_callback_transfer(UINT16 event, char *p_param)
+{
+ tBTA_PAN *p_data = (tBTA_PAN *)p_param;
+ switch(event)
+ {
+ case BTA_PAN_ENABLE_EVT:
+ debug("BTA_PAN_ENABLE_EVT");
+ break;
+ case BTA_PAN_SET_ROLE_EVT:
+ {
+ int btpan_role = bta_role_to_btpan(p_data->set_role.role);
+ bt_status_t status = p_data->set_role.status == BTA_PAN_SUCCESS ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+ btpan_control_state_t state = btpan_role == 0 ? BTPAN_STATE_DISABLED : BTPAN_STATE_ENABLED;
+ callback.control_state_cb(state, btpan_role, status, TAP_IF_NAME);
+ break;
+ }
+ case BTA_PAN_OPENING_EVT:
+ {
+ btpan_conn_t* conn;
+ bdstr_t bds;
+ bd2str((bt_bdaddr_t*)p_data->opening.bd_addr, &bds);
+ debug("BTA_PAN_OPENING_EVT handle %d, addr: %s", p_data->opening.handle, bds);
+ conn = btpan_find_conn_addr(p_data->opening.bd_addr);
+
+ asrt(conn != NULL);
+ if (conn)
+ {
+ conn->handle = p_data->opening.handle;
+ int btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+ int btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+ callback.connection_state_cb(BTPAN_STATE_CONNECTING, BT_STATUS_SUCCESS,
+ (const bt_bdaddr_t*)p_data->opening.bd_addr, btpan_conn_local_role, btpan_remote_role);
+ }
+ else
+ error("connection not found");
+ break;
+ }
+ case BTA_PAN_OPEN_EVT:
+ {
+ debug("BTA_PAN_OPEN_EVT, open status:%d, bd_addr = [%02X:%02X:%02X:%02X:%02X:%02X]",
+ p_data->open.status,
+ p_data->open.bd_addr[0], p_data->open.bd_addr[1], p_data->open.bd_addr[2],
+ p_data->open.bd_addr[3], p_data->open.bd_addr[4], p_data->open.bd_addr[5]);
+ btpan_connection_state_t state;
+ bt_status_t status;
+ if(p_data->open.status == BTA_PAN_SUCCESS)
+ {
+ state = BTPAN_STATE_CONNECTED;
+ status = BT_STATUS_SUCCESS;
+ }
+ else
+ {
+ state = BTPAN_STATE_DISCONNECTED;
+ status = BT_STATUS_FAIL;
+ }
+ btpan_conn_t* conn = btpan_find_conn_handle(p_data->open.handle);
+ debug("BTA_PAN_OPEN_EVT handle:%d, conn:%p", p_data->open.handle, conn);
+ debug("conn bta local_role:%d, bta remote role:%d", conn->local_role, conn->remote_role);
+ int btpan_conn_local_role = bta_role_to_btpan(p_data->open.local_role);
+ debug("bta local_role:%d, bta remote role:%d", p_data->open.local_role, p_data->open.peer_role);
+ int btpan_remote_role = bta_role_to_btpan(p_data->open.peer_role);
+ callback.connection_state_cb(state, status, (const bt_bdaddr_t*)p_data->open.bd_addr,
+ btpan_conn_local_role, btpan_remote_role);
+ break;
+ }
+ case BTA_PAN_CLOSE_EVT:
+ {
+ btpan_conn_t* conn = btpan_find_conn_handle(p_data->close.handle);
+
+ ALOGI("%s: event = BTA_PAN_CLOSE_EVT handle %d", __FUNCTION__, p_data->close.handle);
+
+ if(conn && conn->handle >= 0)
+ {
+ debug("BTA_PAN_CLOSE_EVT, conn local_role:%d, remote_role:%d", conn->local_role, conn->remote_role);
+ int btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+ int btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+ callback.connection_state_cb(BTPAN_STATE_DISCONNECTED, 0, (const bt_bdaddr_t*)conn->peer,
+ btpan_conn_local_role, btpan_remote_role);
+ btpan_cleanup_conn(conn);
+ }
+ else
+ error("pan handle not found (%d)", p_data->close.handle);
+ break;
+ }
+ default:
+ debug("Unknown pan event %d", event);
+ break;
+ }
+}
+
+static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN *p_data)
+{
+ btif_transfer_context(bta_pan_callback_transfer, event, (char*)p_data, sizeof(tBTA_PAN), NULL);
+}
+#define MAX_PACKET_SIZE 2000
+static void btpan_tap_fd_signaled(int fd, int type, int flags, uint32_t user_id)
+{
+ char packet[MAX_PACKET_SIZE];
+ tETH_HDR eth_hdr;
+ if(flags & SOCK_THREAD_FD_EXCEPTION)
+ {
+ error("pan tap fd:%d exception", fd);
+ }
+ else if(flags & SOCK_THREAD_FD_RD)
+ {
+ debug("tab fd read trigged, data");
+ int size = read(fd, packet, MAX_PACKET_SIZE);
+ debug("tap fd read trigged, read size:%d", size);
+ memcpy(&eth_hdr, &packet, sizeof(tETH_HDR));
+ debug("eth src = %02x:%02x:%02x:%02x:%02x:%02x",
+ eth_hdr.h_src[0], eth_hdr.h_src[1], eth_hdr.h_src[2], eth_hdr.h_src[3],
+ eth_hdr.h_src[4], eth_hdr.h_src[5]);
+ debug("eth dest = %02x:%02x:%02x:%02x:%02x:%02x",
+ eth_hdr.h_dest[0], eth_hdr.h_dest[1], eth_hdr.h_dest[2], eth_hdr.h_dest[3],
+ eth_hdr.h_dest[4], eth_hdr.h_dest[5]);
+ //dump_bin("eth packet received", packet, size);
+ if(should_forward(&eth_hdr))
+ {
+ forward_bnep(&eth_hdr, packet + sizeof(tETH_HDR), size - sizeof(tETH_HDR));
+ }
+ btsock_thread_add_fd(pth, fd, 0, SOCK_THREAD_FD_RD | SOCK_THREAD_ADD_FD_SYNC, 0);
+ }
+}
+
+
diff --git a/btif/src/btif_profile_queue.c b/btif/src/btif_profile_queue.c
new file mode 100644
index 0000000..4af3b53
--- /dev/null
+++ b/btif/src/btif_profile_queue.c
@@ -0,0 +1,187 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_profile_queue.c
+ *
+ * Description: Bluetooth remote device connection queuing implementation.
+ *
+ ******************************************************************************/
+
+#include <hardware/bluetooth.h>
+
+#define LOG_TAG "BTIF_QUEUE"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "gki.h"
+
+/*******************************************************************************
+** Local type definitions
+*******************************************************************************/
+
+typedef enum {
+ BTIF_QUEUE_CONNECT_EVT,
+ BTIF_QUEUE_ADVANCE_EVT
+} btif_queue_event_t;
+
+typedef struct connect_node_tag
+{
+ bt_bdaddr_t bda;
+ uint16_t uuid;
+ uint16_t busy;
+ void *p_cb;
+ struct connect_node_tag *p_next;
+} __attribute__((packed))connect_node_t;
+
+
+/*******************************************************************************
+** Static variables
+*******************************************************************************/
+
+static connect_node_t *connect_queue;
+
+
+/*******************************************************************************
+** Queue helper functions
+*******************************************************************************/
+
+static void queue_int_add(connect_node_t *p_param)
+{
+ connect_node_t *p_list = connect_queue;
+ connect_node_t *p_node = GKI_getbuf(sizeof(connect_node_t));
+ ASSERTC(p_node != NULL, "Failed to allocate new list node", 0);
+
+ memcpy(p_node, p_param, sizeof(connect_node_t));
+
+ if (connect_queue == NULL)
+ {
+ connect_queue = p_node;
+ return;
+ }
+
+ while (p_list->p_next)
+ p_list = p_list->p_next;
+ p_list->p_next = p_node;
+}
+
+static void queue_int_advance()
+{
+ connect_node_t *p_head = connect_queue;
+ if (connect_queue == NULL)
+ return;
+
+ connect_queue = connect_queue->p_next;
+ GKI_freebuf(p_head);
+}
+
+static bt_status_t queue_int_connect_next()
+{
+ connect_node_t* p_head = connect_queue;
+
+ if (p_head == NULL)
+ return BT_STATUS_FAIL;
+
+ /* If the queue is currently busy, we return success anyway,
+ * since the connection has been queued... */
+ if (p_head->busy != FALSE)
+ return BT_STATUS_SUCCESS;
+
+ p_head->busy = TRUE;
+ return (*(btif_connect_cb_t*)p_head->p_cb)(&p_head->bda);
+}
+
+static void queue_int_handle_evt(UINT16 event, char *p_param)
+{
+ switch(event)
+ {
+ case BTIF_QUEUE_CONNECT_EVT:
+ queue_int_add((connect_node_t*)p_param);
+ break;
+
+ case BTIF_QUEUE_ADVANCE_EVT:
+ queue_int_advance();
+ break;
+ }
+
+ queue_int_connect_next();
+}
+
+/*******************************************************************************
+**
+** Function btif_queue_connect
+**
+** Description Add a new connection to the queue and trigger the next
+** scheduled connection.
+**
+** Returns BT_STATUS_SUCCESS if successful
+**
+*******************************************************************************/
+bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda,
+ btif_connect_cb_t *connect_cb)
+{
+ connect_node_t node;
+ memset(&node, 0, sizeof(connect_node_t));
+ memcpy(&(node.bda), bda, sizeof(bt_bdaddr_t));
+ node.uuid = uuid;
+ node.p_cb = connect_cb;
+
+ return btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CONNECT_EVT,
+ (char*)&node, sizeof(connect_node_t), NULL);
+}
+
+/*******************************************************************************
+**
+** Function btif_queue_advance
+**
+** Description Clear the queue's busy status and advance to the next
+** scheduled connection.
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_queue_advance()
+{
+ btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_ADVANCE_EVT,
+ NULL, 0, NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function btif_queue_release
+**
+** Description Free up all the queue nodes and set the queue head to NULL
+**
+** Returns void
+**
+*******************************************************************************/
+void btif_queue_release()
+{
+ connect_node_t *current = connect_queue;
+
+ while (current != NULL)
+ {
+ connect_node_t *next = current->p_next;
+ GKI_freebuf(current);
+ current = next;
+ }
+
+ connect_queue = NULL;
+}
+
diff --git a/btif/src/btif_rc.c b/btif/src/btif_rc.c
new file mode 100644
index 0000000..68ddf5b
--- /dev/null
+++ b/btif/src/btif_rc.c
@@ -0,0 +1,492 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Filename: btif_rc.c
+ *
+ * Description: Bluetooth AVRC implementation
+ *
+ *****************************************************************************/
+#include <hardware/bluetooth.h>
+#include <fcntl.h>
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "avrc_defs.h"
+#include "bd.h"
+#include "gki.h"
+
+#define LOG_TAG "BTIF_RC"
+#include "btif_common.h"
+
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+#define BTIF_RC_USE_UINPUT TRUE
+#include "uinput.h"
+
+/* cod value for Headsets */
+#define COD_AV_HEADSETS 0x0404
+
+
+/*****************************************************************************
+** Local type definitions
+******************************************************************************/
+typedef struct {
+ BOOLEAN rc_connected;
+ UINT8 rc_handle;
+ BD_ADDR rc_addr;
+ UINT16 rc_pending_play;
+} btif_rc_cb_t;
+
+#ifdef BTIF_RC_USE_UINPUT
+#define MAX_UINPUT_PATHS 3
+static const char* uinput_dev_path[] =
+ {"/dev/uinput", "/dev/input/uinput", "/dev/misc/uinput" };
+static int uinput_fd = -1;
+
+static int send_event (int fd, uint16_t type, uint16_t code, int32_t value);
+static void send_key (int fd, uint16_t key, int pressed);
+static int uinput_driver_check();
+static int uinput_create(char *name);
+static int init_uinput (void);
+static void close_uinput (void);
+
+static struct {
+ const char *name;
+ uint8_t avrcp;
+ uint16_t mapped_id;
+ uint8_t release_quirk;
+} key_map[] = {
+ { "PLAY", AVRC_ID_PLAY, KEY_PLAYCD, 1 },
+ { "STOP", AVRC_ID_STOP, KEY_STOPCD, 0 },
+ { "PAUSE", AVRC_ID_PAUSE, KEY_PAUSECD, 1 },
+ { "FORWARD", AVRC_ID_FORWARD, KEY_NEXTSONG, 0 },
+ { "BACKWARD", AVRC_ID_BACKWARD, KEY_PREVIOUSSONG, 0 },
+ { "REWIND", AVRC_ID_REWIND, KEY_REWIND, 0 },
+ { "FAST FORWARD", AVRC_ID_FAST_FOR, KEY_FORWARD, 0 },
+ { NULL, 0, 0, 0 }
+};
+#endif /* BTIF_RC_USE_UINPUT */
+
+
+/*****************************************************************************
+** Static variables
+******************************************************************************/
+static btif_rc_cb_t btif_rc_cb;
+
+/*****************************************************************************
+** Static functions
+******************************************************************************/
+
+/*****************************************************************************
+** Externs
+******************************************************************************/
+extern BOOLEAN btif_hf_call_terminated_recently();
+extern BOOLEAN check_cod(const bt_bdaddr_t *remote_bdaddr, uint32_t cod);
+extern BOOLEAN btif_av_is_connected(void);
+
+/*****************************************************************************
+** Functions
+******************************************************************************/
+
+
+#ifdef BTIF_RC_USE_UINPUT
+/*****************************************************************************
+** Local uinput helper functions
+******************************************************************************/
+int send_event (int fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct uinput_event event;
+
+ memset(&event, 0, sizeof(event));
+ event.type = type;
+ event.code = code;
+ event.value = value;
+
+ return write(fd, &event, sizeof(event));
+}
+
+void send_key (int fd, uint16_t key, int pressed)
+{
+ if (fd < 0) {
+ return;
+ }
+
+ BTIF_TRACE_DEBUG3("AVRCP: Send key %d (%d) fd=%d", key, pressed, fd);
+ send_event(fd, EV_KEY, key, pressed);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+/************** uinput related functions **************/
+int uinput_driver_check()
+{
+ uint32_t i;
+ for (i=0; i < MAX_UINPUT_PATHS; i++)
+ {
+ if (access(uinput_dev_path[i], O_RDWR) == 0) {
+ return 0;
+ }
+ }
+ BTIF_TRACE_ERROR1("%s ERROR: uinput device is not in the system", __FUNCTION__);
+ return -1;
+}
+
+int uinput_create(char *name)
+{
+ struct uinput_dev dev;
+ int fd, err, x = 0;
+
+ for(x=0; x < MAX_UINPUT_PATHS; x++)
+ {
+ fd = open(uinput_dev_path[x], O_RDWR);
+ if (fd < 0)
+ continue;
+ break;
+ }
+ if (x == MAX_UINPUT_PATHS) {
+ BTIF_TRACE_ERROR1("%s ERROR: uinput device open failed", __FUNCTION__);
+ return -1;
+ }
+ memset(&dev, 0, sizeof(dev));
+ if (name)
+ strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
+
+ dev.id.bustype = BUS_BLUETOOTH;
+ dev.id.vendor = 0x0000;
+ dev.id.product = 0x0000;
+ dev.id.version = 0x0000;
+
+ if (write(fd, &dev, sizeof(dev)) < 0) {
+ BTIF_TRACE_ERROR1("%s Unable to write device information", __FUNCTION__);
+ close(fd);
+ return -1;
+ }
+
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_EVBIT, EV_REL);
+ ioctl(fd, UI_SET_EVBIT, EV_SYN);
+
+ for (x = 0; key_map[x].name != NULL; x++)
+ ioctl(fd, UI_SET_KEYBIT, key_map[x].mapped_id);
+
+ for(x = 0; x < KEY_MAX; x++)
+ ioctl(fd, UI_SET_KEYBIT, x);
+
+ if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
+ BTIF_TRACE_ERROR1("%s Unable to create uinput device", __FUNCTION__);
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+int init_uinput (void)
+{
+ char *name = "AVRCP";
+
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ uinput_fd = uinput_create(name);
+ if (uinput_fd < 0) {
+ BTIF_TRACE_ERROR3("%s AVRCP: Failed to initialize uinput for %s (%d)",
+ __FUNCTION__, name, uinput_fd);
+ } else {
+ BTIF_TRACE_DEBUG3("%s AVRCP: Initialized uinput for %s (fd=%d)",
+ __FUNCTION__, name, uinput_fd);
+ }
+ return uinput_fd;
+}
+
+void close_uinput (void)
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ if (uinput_fd > 0) {
+ ioctl(uinput_fd, UI_DEV_DESTROY);
+
+ close(uinput_fd);
+ uinput_fd = -1;
+ }
+}
+#endif // BTA_AVRCP_FORCE_USE_UINPUT
+
+const char *dump_rc_event_name(tBTA_AV_EVT event)
+{
+ switch(event) {
+ case BTA_AV_RC_OPEN_EVT: return "BTA_AV_RC_OPEN_EVT";
+ case BTA_AV_RC_CLOSE_EVT: return "BTA_AV_RC_CLOSE_EVT";
+ case BTA_AV_REMOTE_CMD_EVT: return "BTA_AV_REMOTE_CMD_EVT";
+ case BTA_AV_REMOTE_RSP_EVT: return "BTA_AV_REMOTE_RSP_EVT";
+ case BTA_AV_VENDOR_CMD_EVT: return "BTA_AV_VENDOR_CMD_EVT";
+ case BTA_AV_VENDOR_RSP_EVT: return "BTA_AV_VENDOR_RSP_EVT";
+ default: return "UNKNOWN_EVENT";
+ }
+}
+
+/***************************************************************************
+ * Function handle_rc_connect
+ *
+ * - Argument: tBTA_AV_RC_OPEN RC open data structure
+ *
+ * - Description: RC connection event handler
+ *
+ ***************************************************************************/
+void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open)
+{
+ BTIF_TRACE_DEBUG2("%s: rc_handle: %d", __FUNCTION__, p_rc_open->rc_handle);
+
+#ifdef BTIF_RC_USE_UINPUT
+ init_uinput();
+#endif
+
+ memcpy(btif_rc_cb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
+ btif_rc_cb.rc_connected = TRUE;
+ btif_rc_cb.rc_handle = p_rc_open->rc_handle;
+}
+
+/***************************************************************************
+ * Function handle_rc_disconnect
+ *
+ * - Argument: tBTA_AV_RC_CLOSE RC close data structure
+ *
+ * - Description: RC disconnection event handler
+ *
+ ***************************************************************************/
+void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close)
+{
+ BTIF_TRACE_DEBUG2("%s: rc_handle: %d", __FUNCTION__, p_rc_close->rc_handle);
+
+ btif_rc_cb.rc_handle = 0;
+ btif_rc_cb.rc_connected = FALSE;
+ memset(btif_rc_cb.rc_addr, 0, sizeof(BD_ADDR));
+#ifdef BTIF_RC_USE_UINPUT
+ close_uinput();
+#endif /* BTIF_RC_USE_UINPUT */
+}
+
+/***************************************************************************
+ * Function handle_rc_passthrough_cmd
+ *
+ * - Argument: tBTA_AV_RC rc_id remote control command ID
+ * tBTA_AV_STATE key_state status of key press
+ *
+ * - Description: Remote control command handler
+ *
+ ***************************************************************************/
+void handle_rc_passthrough_cmd ( tBTA_AV_REMOTE_CMD *p_remote_cmd)
+{
+ const char *status;
+ int pressed, i;
+
+ btif_rc_cb.rc_handle = p_remote_cmd->rc_handle;
+
+ /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up this PLAY */
+ if (p_remote_cmd)
+ {
+ /* queue AVRC PLAY if GAVDTP Open notification to app is pending (2 second timer) */
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) && (!btif_av_is_connected()))
+ {
+ if (p_remote_cmd->key_state == AVRC_STATE_PRESS)
+ {
+ APPL_TRACE_WARNING1("%s: AVDT not open, queuing the PLAY command", __FUNCTION__);
+ btif_rc_cb.rc_pending_play = TRUE;
+ }
+ return;
+ }
+
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (btif_rc_cb.rc_pending_play))
+ {
+ APPL_TRACE_WARNING1("%s: Clear the pending PLAY on PAUSE received", __FUNCTION__);
+ btif_rc_cb.rc_pending_play = FALSE;
+ return;
+ }
+ }
+ if (p_remote_cmd->key_state == AVRC_STATE_RELEASE) {
+ status = "released";
+ pressed = 0;
+ } else {
+ status = "pressed";
+ pressed = 1;
+ }
+
+ /* If this is Play/Pause command (press or release) before processing, check the following
+ * a voice call has ended recently
+ * the remote device is not of type headset
+ * If the above conditions meet, drop the Play/Pause command
+ * This fix is to interop with certain carkits which sends an automatic PLAY or PAUSE
+ * commands right after call ends
+ */
+ if((p_remote_cmd->rc_id == BTA_AV_RC_PLAY || p_remote_cmd->rc_id == BTA_AV_RC_PAUSE)&&
+ (btif_hf_call_terminated_recently() == TRUE) &&
+ (check_cod( (const bt_bdaddr_t*)&(btif_rc_cb.rc_addr), COD_AV_HEADSETS) != TRUE))
+ {
+ BTIF_TRACE_DEBUG2("%s:Dropping the play/Pause command received right after call end cmd:%d",
+ __FUNCTION__,p_remote_cmd->rc_id);
+ return;
+ }
+
+ for (i = 0; key_map[i].name != NULL; i++) {
+ if (p_remote_cmd->rc_id == key_map[i].avrcp) {
+ BTIF_TRACE_DEBUG3("%s: %s %s", __FUNCTION__, key_map[i].name, status);
+
+ /* MusicPlayer uses a long_press_timeout of 1 second for PLAYPAUSE button
+ * and maps that to autoshuffle. So if for some reason release for PLAY/PAUSE
+ * comes 1 second after the press, the MediaPlayer UI goes into a bad state.
+ * The reason for the delay could be sniff mode exit or some AVDTP procedure etc.
+ * The fix is to generate a release right after the press and drown the 'actual'
+ * release.
+ */
+ if ((key_map[i].release_quirk == 1) && (pressed == 0))
+ {
+ BTIF_TRACE_DEBUG2("%s: AVRC %s Release Faked earlier, drowned now",
+ __FUNCTION__, key_map[i].name);
+ return;
+ }
+#ifdef BTIF_RC_USE_UINPUT
+ send_key(uinput_fd, key_map[i].mapped_id, pressed);
+#endif
+ if ((key_map[i].release_quirk == 1) && (pressed == 1))
+ {
+ GKI_delay(30); // 30ms
+ BTIF_TRACE_DEBUG2("%s: AVRC %s Release quirk enabled, send release now",
+ __FUNCTION__, key_map[i].name);
+#ifdef BTIF_RC_USE_UINPUT
+ send_key(uinput_fd, key_map[i].mapped_id, 0);
+#endif
+ }
+ break;
+ }
+ }
+
+ if (key_map[i].name == NULL)
+ BTIF_TRACE_ERROR3("%s AVRCP: unknown button 0x%02X %s", __FUNCTION__,
+ p_remote_cmd->rc_id, status);
+}
+
+/*****************************************************************************
+**
+** Function btif_rc_init
+**
+** Description Initialize RC
+**
+** Returns Returns 0 on success, -1 otherwise
+**
+*******************************************************************************/
+int btif_rc_init()
+{
+ BTIF_TRACE_DEBUG1("%s", __FUNCTION__);
+ memset (&btif_rc_cb, 0, sizeof(btif_rc_cb));
+
+#ifdef BTIF_RC_USE_UINPUT
+ return uinput_driver_check();
+#endif /* BTIF_RC_USE_UINPUT */
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_handler
+ **
+ ** Description RC event handler
+ **
+ ***************************************************************************/
+void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data)
+{
+ BTIF_TRACE_DEBUG2 ("%s event:%s", __FUNCTION__, dump_rc_event_name(event));
+ switch (event)
+ {
+ case BTA_AV_RC_OPEN_EVT:
+ {
+ BTIF_TRACE_DEBUG1("Peer_features:%x", p_data->rc_open.peer_features);
+ handle_rc_connect( &(p_data->rc_open) );
+ }break;
+
+ case BTA_AV_RC_CLOSE_EVT:
+ {
+ handle_rc_disconnect( &(p_data->rc_close) );
+ }break;
+
+ case BTA_AV_REMOTE_CMD_EVT:
+ {
+ BTIF_TRACE_DEBUG2("rc_id:0x%x key_state:%d", p_data->remote_cmd.rc_id,
+ p_data->remote_cmd.key_state);
+ handle_rc_passthrough_cmd( (&p_data->remote_cmd) );
+ }break;
+ default:
+ BTIF_TRACE_DEBUG0("Unhandled RC event");
+ }
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_get_connected_peer
+ **
+ ** Description Fetches the connected headset's BD_ADDR if any
+ **
+ ***************************************************************************/
+BOOLEAN btif_rc_get_connected_peer(BD_ADDR peer_addr)
+{
+ if (btif_rc_cb.rc_connected == TRUE) {
+ bdcpy(peer_addr, btif_rc_cb.rc_addr);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_check_handle_pending_play
+ **
+ ** Description Clears the queued PLAY command. if bSend is TRUE, forwards to app
+ **
+ ***************************************************************************/
+
+/* clear the queued PLAY command. if bSend is TRUE, forward to app */
+void btif_rc_check_handle_pending_play (BD_ADDR peer_addr, BOOLEAN bSendToApp)
+{
+ ALOGV("btapp_rc_check_handle_pending_play: bSendToApp=%d", bSendToApp);
+ if (btif_rc_cb.rc_pending_play)
+ {
+ if (bSendToApp)
+ {
+ tBTA_AV_REMOTE_CMD remote_cmd;
+ APPL_TRACE_DEBUG1("%s: Sending queued PLAYED event to app", __FUNCTION__);
+
+ memset (&remote_cmd, 0, sizeof(tBTA_AV_REMOTE_CMD));
+ remote_cmd.rc_handle = btif_rc_cb.rc_handle;
+ remote_cmd.rc_id = AVRC_ID_PLAY;
+ remote_cmd.hdr.ctype = AVRC_CMD_CTRL;
+ remote_cmd.hdr.opcode = AVRC_OP_PASS_THRU;
+
+ /* delay sending to app, else there is a timing issue in the framework,
+ ** which causes the audio to be on th device's speaker. Delay between
+ ** OPEN & RC_PLAYs
+ */
+ GKI_delay (200);
+ /* send to app - both PRESSED & RELEASED */
+ remote_cmd.key_state = AVRC_STATE_PRESS;
+ handle_rc_passthrough_cmd( &remote_cmd );
+
+ GKI_delay (100);
+
+ remote_cmd.key_state = AVRC_STATE_RELEASE;
+ handle_rc_passthrough_cmd( &remote_cmd );
+ }
+ btif_rc_cb.rc_pending_play = FALSE;
+ }
+}
+
diff --git a/btif/src/btif_sm.c b/btif/src/btif_sm.c
new file mode 100644
index 0000000..cb4e5ad
--- /dev/null
+++ b/btif/src/btif_sm.c
@@ -0,0 +1,205 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Filename: btif_sm.c
+ *
+ * Description: Generic BTIF state machine API
+ *
+ *****************************************************************************/
+#include <hardware/bluetooth.h>
+
+#define LOG_TAG "BTIF_SM"
+#include "btif_common.h"
+#include "btif_sm.h"
+#include "gki.h"
+
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+
+/*****************************************************************************
+** Local type definitions
+******************************************************************************/
+typedef struct {
+ btif_sm_state_t state;
+ btif_sm_handler_t *p_handlers;
+} btif_sm_cb_t;
+
+/*****************************************************************************
+** Static variables
+******************************************************************************/
+
+/*****************************************************************************
+** Static functions
+******************************************************************************/
+
+/*****************************************************************************
+** Externs
+******************************************************************************/
+
+/*****************************************************************************
+** Functions
+******************************************************************************/
+
+/*****************************************************************************
+**
+** Function btif_sm_init
+**
+** Description Initializes the state machine with the state handlers
+** The caller should ensure that the table and the corresponding
+** states match. The location that 'p_handlers' points to shall
+** be available until the btif_sm_shutdown API is invoked.
+**
+** Returns Returns a pointer to the initialized state machine handle.
+**
+******************************************************************************/
+
+btif_sm_handle_t btif_sm_init(const btif_sm_handler_t *p_handlers, btif_sm_state_t initial_state)
+{
+ btif_sm_cb_t *p_cb;
+
+ if (p_handlers == NULL)
+ {
+ BTIF_TRACE_ERROR1("%s : p_handlers is NULL", __FUNCTION__);
+ return NULL;
+ }
+
+ p_cb = (btif_sm_cb_t*) GKI_os_malloc(sizeof(btif_sm_cb_t));
+ p_cb->state = initial_state;
+ p_cb->p_handlers = (btif_sm_handler_t*)p_handlers;
+
+ /* Send BTIF_SM_ENTER_EVT to the initial state */
+ p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL);
+
+ return (btif_sm_handle_t)p_cb;
+}
+
+/*****************************************************************************
+**
+** Function btif_sm_shutdown
+**
+** Description Tears down the state machine
+**
+** Returns None
+**
+******************************************************************************/
+void btif_sm_shutdown(btif_sm_handle_t handle)
+{
+ btif_sm_cb_t *p_cb = (btif_sm_cb_t*)handle;
+
+ if (p_cb == NULL)
+ {
+ BTIF_TRACE_ERROR1("%s : Invalid handle", __FUNCTION__);
+ return;
+ }
+ GKI_os_free((void*)p_cb);
+}
+
+/*****************************************************************************
+**
+** Function btif_sm_get_state
+**
+** Description Fetches the current state of the state machine
+**
+** Returns Current state
+**
+******************************************************************************/
+btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle)
+{
+ btif_sm_cb_t *p_cb = (btif_sm_cb_t*)handle;
+
+ if (p_cb == NULL)
+ {
+ BTIF_TRACE_ERROR1("%s : Invalid handle", __FUNCTION__);
+ return 0;
+ }
+
+ return p_cb->state;
+}
+
+/*****************************************************************************
+**
+** Function btif_sm_dispatch
+**
+** Description Dispatches the 'event' along with 'data' to the current state handler
+**
+** Returns BT_STATUS_SUCCESS on success
+** BT_STATUS_UNHANDLED if event was not processed
+** BT_STATUS_FAIL otherwise
+**
+******************************************************************************/
+bt_status_t btif_sm_dispatch(btif_sm_handle_t handle, btif_sm_event_t event,
+ void *data)
+{
+ bt_status_t status = BT_STATUS_SUCCESS;
+
+ btif_sm_cb_t *p_cb = (btif_sm_cb_t*)handle;
+
+ if (p_cb == NULL)
+ {
+ BTIF_TRACE_ERROR1("%s : Invalid handle", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+
+ if (p_cb->p_handlers[p_cb->state](event, data) == FALSE)
+ return BT_STATUS_UNHANDLED;
+
+ return status;
+}
+
+/*****************************************************************************
+**
+** Function btif_sm_change_state
+**
+** Description Make a transition to the new 'state'. The 'BTIF_SM_EXIT_EVT'
+** shall be invoked before exiting the current state. The
+** 'BTIF_SM_ENTER_EVT' shall be invoked before entering the new state
+**
+** Returns BT_STATUS_SUCCESS on success
+** BT_STATUS_UNHANDLED if event was not processed
+** BT_STATUS_FAIL otherwise
+**
+******************************************************************************/
+bt_status_t btif_sm_change_state(btif_sm_handle_t handle, btif_sm_state_t state)
+{
+ bt_status_t status = BT_STATUS_SUCCESS;
+ btif_sm_cb_t *p_cb = (btif_sm_cb_t*)handle;
+
+ if (p_cb == NULL)
+ {
+ BTIF_TRACE_ERROR1("%s : Invalid handle", __FUNCTION__);
+ return BT_STATUS_FAIL;
+ }
+
+ /* Send exit event to the current state */
+ if (p_cb->p_handlers[p_cb->state](BTIF_SM_EXIT_EVT, NULL) == FALSE)
+ status = BT_STATUS_UNHANDLED;
+
+ /* Change to the new state */
+ p_cb->state = state;
+
+ /* Send enter event to the new state */
+ if (p_cb->p_handlers[p_cb->state](BTIF_SM_ENTER_EVT, NULL) == FALSE)
+ status = BT_STATUS_UNHANDLED;
+
+ return status;
+}
diff --git a/btif/src/btif_sock.c b/btif/src/btif_sock.c
new file mode 100644
index 0000000..a2c799a
--- /dev/null
+++ b/btif/src/btif_sock.c
@@ -0,0 +1,182 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+
+/************************************************************************************
+ *
+ * Filename: btif_sock.c
+ *
+ * Description: Bluetooth Socket Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_rfc.h"
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("btif_sock: %s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("btif_sock: %s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("btif_sock: ## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("btif_sock: ## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
+ const uint8_t* uuid, int channel, int* sock_fd, int flags);
+static bt_status_t btsock_connect(const bt_bdaddr_t *bd_addr, btsock_type_t type,
+ const uint8_t* uuid, int channel, int* sock_fd, int flags);
+
+static void btsock_signaled(int fd, int type, int flags, uint32_t user_id);
+
+/*******************************************************************************
+**
+** Function btsock_ini
+**
+** Description initializes the bt socket interface
+**
+** Returns bt_status_t
+**
+*******************************************************************************/
+static btsock_interface_t sock_if = {
+ sizeof(sock_if),
+ btsock_listen,
+ btsock_connect
+ };
+btsock_interface_t *btif_sock_get_interface()
+{
+ return &sock_if;
+}
+bt_status_t btif_sock_init()
+{
+ debug("");
+
+
+ static volatile int binit;
+ if(!binit)
+ {
+ //fix me, the process doesn't exit right now. don't set the init flag for now
+ //binit = 1;
+ debug("btsock initializing...");
+ btsock_thread_init();
+ int handle = btsock_thread_create(btsock_signaled, NULL);
+ if(handle >= 0 && btsock_rfc_init(handle) == BT_STATUS_SUCCESS)
+ {
+ debug("btsock successfully initialized");
+ return BT_STATUS_SUCCESS;
+ }
+ }
+ else error("btsock interface already initialized");
+ return BT_STATUS_FAIL;
+}
+void btif_sock_cleanup()
+{
+ debug("");
+ btsock_rfc_cleanup();
+ debug("leaving");
+}
+
+static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
+ const uint8_t* service_uuid, int channel, int* sock_fd, int flags)
+{
+ if((service_uuid == NULL && channel <= 0) || sock_fd == NULL)
+ {
+ error("invalid parameters, uuid:%p, channel:%d, sock_fd:%p", service_uuid, channel, sock_fd);
+ return BT_STATUS_PARM_INVALID;
+ }
+ *sock_fd = -1;
+ bt_status_t status = BT_STATUS_FAIL;
+ switch(type)
+ {
+ case BTSOCK_RFCOMM:
+ status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd, flags);
+ break;
+ case BTSOCK_L2CAP:
+ error("bt l2cap socket type not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ case BTSOCK_SCO:
+ error("bt sco socket not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ default:
+ error("unknown bt socket type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ }
+ return status;
+}
+static bt_status_t btsock_connect(const bt_bdaddr_t *bd_addr, btsock_type_t type,
+ const uint8_t* uuid, int channel, int* sock_fd, int flags)
+{
+ if((uuid == NULL && channel <= 0) || bd_addr == NULL || sock_fd == NULL)
+ {
+ error("invalid parameters, bd_addr:%p, uuid:%p, channel:%d, sock_fd:%p",
+ bd_addr, uuid, channel, sock_fd);
+ return BT_STATUS_PARM_INVALID;
+ }
+ *sock_fd = -1;
+ bt_status_t status = BT_STATUS_FAIL;
+ switch(type)
+ {
+ case BTSOCK_RFCOMM:
+ status = btsock_rfc_connect(bd_addr, uuid, channel, sock_fd, flags);
+ break;
+ case BTSOCK_L2CAP:
+ error("bt l2cap socket type not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ case BTSOCK_SCO:
+ error("bt sco socket not supported, type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ default:
+ error("unknown bt socket type:%d", type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ }
+ return status;
+}
+static void btsock_signaled(int fd, int type, int flags, uint32_t user_id)
+{
+ switch(type)
+ {
+ case BTSOCK_RFCOMM:
+ btsock_rfc_signaled(fd, flags, user_id);
+ break;
+ case BTSOCK_L2CAP:
+ error("bt l2cap socket type not supported, fd:%d, flags:%d", fd, flags);
+ break;
+ case BTSOCK_SCO:
+ error("bt sco socket type not supported, fd:%d, flags:%d", fd, flags);
+ break;
+ default:
+ error("unknown socket type:%d, fd:%d, flags:%d", type, fd, flags);
+ break;
+ }
+}
+
+
+
diff --git a/btif/src/btif_sock_rfc.c b/btif/src/btif_sock_rfc.c
new file mode 100644
index 0000000..650549f
--- /dev/null
+++ b/btif/src/btif_sock_rfc.c
@@ -0,0 +1,985 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_sock_rfc.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ ***********************************************************************************/
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_util.h"
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "sdp_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "port_api.h"
+
+#include <cutils/log.h>
+#include <hardware/bluetooth.h>
+#define asrt(s) if(!(s)) APPL_TRACE_ERROR3("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+extern void uuid_to_string(bt_uuid_t *p_uuid, char *str);
+static inline void logu(const char* title, const uint8_t * p_uuid)
+{
+ char uuids[128];
+ uuid_to_string((bt_uuid_t*)p_uuid, uuids);
+ ALOGD("%s: %s", title, uuids);
+}
+
+
+
+#define MAX_RFC_CHANNEL 30
+#define MAX_RFC_SESSION BTA_JV_MAX_RFC_SR_SESSION //3 by default
+typedef struct {
+ int outgoing_congest : 1;
+ int pending_sdp_request : 1;
+ int doing_sdp_request : 1;
+ int server : 1;
+ int connected : 1;
+ int closing : 1;
+} flags_t;
+
+typedef struct {
+ flags_t f;
+ uint32_t id;
+ int security;
+ int scn;
+ bt_bdaddr_t addr;
+ uint8_t service_uuid[16];
+ char service_name[256];
+ int fd, app_fd;
+ int mtu;
+ uint8_t* packet;
+ int sdp_handle;
+ int rfc_handle;
+ int rfc_port_handle;
+ int role;
+ BUFFER_Q incoming_que;
+} rfc_slot_t;
+
+static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL];
+static uint32_t rfc_slot_id;
+static volatile int pth = -1; //poll thread handle
+static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
+static void cleanup_rfc_slot(rfc_slot_t* rs);
+static inline void close_rfc_connection(int rfc_handle, int server);
+static bt_status_t dm_get_remote_service_record(bt_bdaddr_t *remote_addr,
+ bt_uuid_t *uuid);
+static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data);
+static inline BOOLEAN send_app_scn(rfc_slot_t* rs);
+static pthread_mutex_t slot_lock;
+#define is_init_done() (pth != -1)
+static inline void clear_slot_flag(flags_t* f)
+{
+ memset(f, 0, sizeof(*f));
+}
+
+static inline void bd_copy(UINT8* dest, UINT8* src, BOOLEAN swap)
+{
+ if (swap)
+ {
+ int i;
+ for (i =0; i < 6 ;i++)
+ dest[i]= src[5-i];
+ }
+ else memcpy(dest, src, 6);
+}
+static inline void free_gki_que(BUFFER_Q* q)
+{
+ while(!GKI_queue_is_empty(q))
+ GKI_freebuf(GKI_dequeue(q));
+}
+static void init_rfc_slots()
+{
+ int i;
+ memset(rfc_slots, 0, sizeof(rfc_slot_t)*MAX_RFC_CHANNEL);
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ rfc_slots[i].scn = -1;
+ rfc_slots[i].sdp_handle = 0;
+ rfc_slots[i].fd = rfc_slots[i].app_fd = -1;
+ GKI_init_q(&rfc_slots[i].incoming_que);
+ }
+ BTA_JvEnable(jv_dm_cback);
+ init_slot_lock(&slot_lock);
+}
+bt_status_t btsock_rfc_init(int poll_thread_handle)
+{
+ pth = poll_thread_handle;
+ init_rfc_slots();
+ return BT_STATUS_SUCCESS;
+}
+void btsock_rfc_cleanup()
+{
+ int curr_pth = pth;
+ pth = -1;
+ btsock_thread_exit(curr_pth);
+ lock_slot(&slot_lock);
+ int i;
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].id)
+ cleanup_rfc_slot(&rfc_slots[i]);
+ }
+ unlock_slot(&slot_lock);
+}
+static inline rfc_slot_t* find_free_slot()
+{
+ int i;
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].fd == -1)
+ {
+ return &rfc_slots[i];
+ }
+ }
+ return NULL;
+}
+static inline rfc_slot_t* find_rfc_slot_by_id(uint32_t id)
+{
+ int i;
+ if(id)
+ {
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].id == id)
+ {
+ return &rfc_slots[i];
+ }
+ }
+ }
+ APPL_TRACE_WARNING1("invalid rfc slot id: %d", id);
+ return NULL;
+}
+static inline rfc_slot_t* find_rfc_slot_by_pending_sdp()
+{
+ uint32_t min_id = (uint32_t)-1;
+ int slot = -1;
+ int i;
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].id && rfc_slots[i].f.pending_sdp_request)
+ {
+ if(rfc_slots[i].id < min_id)
+ {
+ min_id = rfc_slots[i].id;
+ slot = i;
+ }
+ }
+ }
+ if(0<= slot && slot < MAX_RFC_CHANNEL)
+ return &rfc_slots[slot];
+ return NULL;
+}
+static inline rfc_slot_t* find_rfc_slot_requesting_sdp()
+{
+ int i;
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].id && rfc_slots[i].f.doing_sdp_request)
+ return &rfc_slots[i];
+ }
+ APPL_TRACE_DEBUG0("can not find any slot is requesting sdp");
+ return NULL;
+}
+
+static inline rfc_slot_t* find_rfc_slot_by_fd(int fd)
+{
+ int i;
+ if(fd >= 0)
+ {
+ for(i = 0; i < MAX_RFC_CHANNEL; i++)
+ {
+ if(rfc_slots[i].fd == fd)
+ {
+ if(rfc_slots[i].id)
+ return &rfc_slots[i];
+ else
+ {
+ APPL_TRACE_ERROR0("invalid rfc slot id, cannot be 0");
+ break;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+static rfc_slot_t* alloc_rfc_slot(const bt_bdaddr_t *addr, const char* name, const uint8_t* uuid, int channel, int flags, BOOLEAN server)
+{
+ int security = 0;
+ if(flags & BTSOCK_FLAG_ENCRYPT)
+ security |= server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT;
+ if(flags & BTSOCK_FLAG_AUTH)
+ security |= server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE;
+
+ rfc_slot_t* rs = find_free_slot();
+ if(rs)
+ {
+ int fds[2] = {-1, -1};
+ if(socketpair(AF_LOCAL, SOCK_STREAM, 0, fds))
+ {
+ APPL_TRACE_ERROR1("socketpair failed, errno:%d", errno);
+ return NULL;
+ }
+ rs->fd = fds[0];
+ rs->app_fd = fds[1];
+ rs->security = security;
+ rs->scn = channel;
+ if(uuid)
+ memcpy(rs->service_uuid, uuid, sizeof(rs->service_uuid));
+ else memset(rs->service_uuid, 0, sizeof(rs->service_uuid));
+ if(name && *name)
+ strncpy(rs->service_name, name, sizeof(rs->service_name) -1);
+ if(addr)
+ rs->addr = *addr;
+ ++rfc_slot_id;
+ if(rfc_slot_id == 0)
+ rfc_slot_id = 1; //skip 0 when wrapped
+ rs->id = rfc_slot_id;
+ rs->f.server = server;
+ }
+ return rs;
+}
+// rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, p_open->rem_bda,p_opne->handle, p_open->new_listen_handle);
+static inline rfc_slot_t* create_srv_accept_rfc_slot(rfc_slot_t* srv_rs, const bt_bdaddr_t* addr,
+ int open_handle, int new_listen_handle)
+{
+ rfc_slot_t *accept_rs = alloc_rfc_slot(addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, FALSE);
+ clear_slot_flag(&accept_rs->f);
+ accept_rs->f.server = FALSE;
+ accept_rs->f.connected = TRUE;
+ accept_rs->security = srv_rs->security;
+ accept_rs->mtu = srv_rs->mtu;
+ accept_rs->role = srv_rs->role;
+ accept_rs->rfc_handle = open_handle;
+ accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle);
+ asrt(accept_rs->rfc_handle == srv_rs->rfc_handle);
+ asrt(accept_rs->rfc_port_handle == srv_rs->rfc_port_handle);
+ //now update listen handle of server slot
+ srv_rs->rfc_handle = new_listen_handle;
+ srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle);
+ //now swap the slot id
+ uint32_t new_listen_id = accept_rs->id;
+ accept_rs->id = srv_rs->id;
+ srv_rs->id = new_listen_id;
+ return accept_rs;
+}
+bt_status_t btsock_rfc_listen(const char* service_name, const uint8_t* service_uuid, int channel,
+ int* sock_fd, int flags)
+{
+ if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30)))
+ {
+ APPL_TRACE_ERROR3("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid);
+ return BT_STATUS_PARM_INVALID;
+ }
+ *sock_fd = -1;
+ if(!is_init_done())
+ return BT_STATUS_NOT_READY;
+ if(is_uuid_empty(service_uuid))
+ service_uuid = UUID_SPP; //use serial port profile to listen to specified channel
+ else
+ {
+ //Check the service_uuid. overwrite the channel # if reserved
+ int reserved_channel = get_reserved_rfc_channel(service_uuid);
+ if(reserved_channel > 0)
+ {
+ channel = reserved_channel;
+ }
+ }
+ int status = BT_STATUS_FAIL;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, TRUE);
+ if(rs)
+ {
+ BTA_JvCreateRecordByUser((void *)rs->id);
+ *sock_fd = rs->app_fd;
+ rs->app_fd = -1; //the fd ownership is transferred to app
+ status = BT_STATUS_SUCCESS;
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, rs->id);
+ }
+ unlock_slot(&slot_lock);
+ return status;
+}
+bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, const uint8_t* service_uuid,
+ int channel, int* sock_fd, int flags)
+{
+ if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30)))
+ {
+ APPL_TRACE_ERROR3("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd,
+ service_uuid);
+ return BT_STATUS_PARM_INVALID;
+ }
+ *sock_fd = -1;
+ if(!is_init_done())
+ return BT_STATUS_NOT_READY;
+ int status = BT_STATUS_FAIL;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, FALSE);
+ if(rs)
+ {
+ if(is_uuid_empty(service_uuid))
+ {
+ APPL_TRACE_DEBUG1("connecting to rfcomm channel:%d without service discovery", channel);
+ if(BTA_JvRfcommConnect(rs->security, rs->role, rs->scn, rs->addr.address,
+ rfcomm_cback, (void*)rs->id) == BTA_JV_SUCCESS)
+ {
+ if(send_app_scn(rs))
+ {
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM,
+ SOCK_THREAD_FD_RD, rs->id);
+ *sock_fd = rs->app_fd;
+ rs->app_fd = -1; //the fd ownership is transferred to app
+ status = BT_STATUS_SUCCESS;
+ }
+ else cleanup_rfc_slot(rs);
+ }
+ else cleanup_rfc_slot(rs);
+ }
+ else
+ {
+ tSDP_UUID sdp_uuid;
+ sdp_uuid.len = 16;
+ memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128));
+ logu("service_uuid", service_uuid);
+ *sock_fd = rs->app_fd;
+ rs->app_fd = -1; //the fd ownership is transferred to app
+ status = BT_STATUS_SUCCESS;
+ rfc_slot_t* rs_doing_sdp = find_rfc_slot_requesting_sdp();
+ if(rs_doing_sdp == NULL)
+ {
+ BTA_JvStartDiscovery((UINT8*)bd_addr->address, 1, &sdp_uuid, (void*)rs->id);
+ rs->f.pending_sdp_request = FALSE;
+ rs->f.doing_sdp_request = TRUE;
+ }
+ else
+ {
+ rs->f.pending_sdp_request = TRUE;
+ rs->f.doing_sdp_request = FALSE;
+ }
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
+ }
+ }
+ unlock_slot(&slot_lock);
+ return status;
+}
+
+static int create_server_sdp_record(rfc_slot_t* rs)
+{
+ int scn = rs->scn;
+ if(rs->scn > 0)
+ {
+ if(BTM_TryAllocateSCN(rs->scn) == FALSE)
+ {
+ APPL_TRACE_ERROR1("rfc channel:%d already in use", scn);
+ return FALSE;
+ }
+ }
+ else if((rs->scn = BTM_AllocateSCN()) == 0)
+ {
+ APPL_TRACE_ERROR0("run out of rfc channels");
+ return FALSE;
+ }
+ if((rs->sdp_handle = add_rfc_sdp_rec(rs->service_name, rs->service_uuid, rs->scn)) <= 0)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+const char * jv_evt[] = {
+ "BTA_JV_ENABLE_EVT",
+ "BTA_JV_SET_DISCOVER_EVT",
+ "BTA_JV_LOCAL_ADDR_EVT",
+ "BTA_JV_LOCAL_NAME_EVT",
+ "BTA_JV_REMOTE_NAME_EVT",
+ "BTA_JV_SET_ENCRYPTION_EVT",
+ "BTA_JV_GET_SCN_EVT",
+ "BTA_JV_GET_PSM_EVT",
+ "BTA_JV_DISCOVERY_COMP_EVT",
+ "BTA_JV_SERVICES_LEN_EVT",
+ "BTA_JV_SERVICE_SEL_EVT",
+ "BTA_JV_CREATE_RECORD_EVT",
+ "BTA_JV_UPDATE_RECORD_EVT",
+ "BTA_JV_ADD_ATTR_EVT",
+ "BTA_JV_DELETE_ATTR_EVT",
+ "BTA_JV_CANCEL_DISCVRY_EVT",
+
+ "BTA_JV_L2CAP_OPEN_EVT",
+ "BTA_JV_L2CAP_CLOSE_EVT",
+ "BTA_JV_L2CAP_START_EVT",
+ "BTA_JV_L2CAP_CL_INIT_EVT",
+ "BTA_JV_L2CAP_DATA_IND_EVT",
+ "BTA_JV_L2CAP_CONG_EVT",
+ "BTA_JV_L2CAP_READ_EVT",
+ "BTA_JV_L2CAP_RECEIVE_EVT",
+ "BTA_JV_L2CAP_WRITE_EVT",
+
+ "BTA_JV_RFCOMM_OPEN_EVT",
+ "BTA_JV_RFCOMM_CLOSE_EVT",
+ "BTA_JV_RFCOMM_START_EVT",
+ "BTA_JV_RFCOMM_CL_INIT_EVT",
+ "BTA_JV_RFCOMM_DATA_IND_EVT",
+ "BTA_JV_RFCOMM_CONG_EVT",
+ "BTA_JV_RFCOMM_READ_EVT",
+ "BTA_JV_RFCOMM_WRITE_EVT",
+ "BTA_JV_RFCOMM_SRV_OPEN_EVT", // 33 /* open status of Server RFCOMM connection */
+ "BTA_JV_MAX_EVT"
+};
+static inline void free_rfc_slot_scn(rfc_slot_t* rs)
+{
+ if(rs->scn > 0)
+ {
+ if(rs->f.server && !rs->f.closing)
+ {
+ BTA_JvRfcommStopServer(rs->rfc_handle);
+ rs->rfc_handle = 0;
+ }
+ BTM_FreeSCN(rs->scn);
+ rs->scn = 0;
+ }
+}
+static void cleanup_rfc_slot(rfc_slot_t* rs)
+{
+ APPL_TRACE_DEBUG3("cleanup slot:%d, fd:%d, scn:%d", rs->id, rs->fd, rs->scn);
+ if(rs->fd != -1)
+ {
+ shutdown(rs->fd, 2);
+ close(rs->fd);
+ rs->fd = -1;
+ }
+ if(rs->app_fd != -1)
+ {
+ close(rs->app_fd);
+ rs->app_fd = -1;
+ }
+ if(rs->sdp_handle > 0)
+ {
+ del_rfc_sdp_rec(rs->sdp_handle);
+ rs->sdp_handle = 0;
+ }
+ if(rs->rfc_handle && !rs->f.closing && !rs->f.server)
+ {
+ APPL_TRACE_DEBUG1("closing rfcomm connection, rfc_handle:%d", rs->rfc_handle);
+ BTA_JvRfcommClose(rs->rfc_handle);
+ rs->rfc_handle = 0;
+ }
+ free_rfc_slot_scn(rs);
+ free_gki_que(&rs->incoming_que);
+
+ rs->rfc_port_handle = 0;
+ //cleanup the flag
+ memset(&rs->f, 0, sizeof(rs->f));
+ rs->id = 0;
+}
+static inline BOOLEAN send_app_scn(rfc_slot_t* rs)
+{
+ if(sock_send_all(rs->fd, (const uint8_t*)&rs->scn, sizeof(rs->scn)) == sizeof(rs->scn))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+static BOOLEAN send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel, int status, int send_fd)
+{
+/*
+ typedef struct {
+ short size;
+ bt_bdaddr_t bd_addr;
+ int channel;
+ int status;
+} __attribute__((packed)) sock_connect_signal_t;
+*/
+ sock_connect_signal_t cs;
+ cs.size = sizeof(cs);
+ cs.bd_addr = *addr;
+ cs.channel = channel;
+ cs.status = status;
+ if(send_fd != -1)
+ {
+ if(sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) == sizeof(cs))
+ return TRUE;
+ else APPL_TRACE_ERROR2("sock_send_fd failed, fd:%d, send_fd:%d", fd, send_fd);
+ }
+ else if(sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT *p_init, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ if (p_init->status != BTA_JV_SUCCESS)
+ cleanup_rfc_slot(rs);
+ else
+ {
+ rs->rfc_handle = p_init->handle;
+ }
+ }
+ unlock_slot(&slot_lock);
+}
+static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START *p_start, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ if (p_start->status != BTA_JV_SUCCESS)
+ cleanup_rfc_slot(rs);
+ else
+ {
+ rs->rfc_handle = p_start->handle;
+
+ if(!send_app_scn(rs))
+ {
+ //closed
+ APPL_TRACE_DEBUG1("send_app_scn() failed, close rs->id:%d", rs->id);
+ cleanup_rfc_slot(rs);
+ }
+ }
+ }
+ unlock_slot(&slot_lock);
+}
+static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN *p_open, uint32_t id)
+{
+ uint32_t new_listen_slot_id = 0;
+ lock_slot(&slot_lock);
+ rfc_slot_t* srv_rs = find_rfc_slot_by_id(id);
+ if(srv_rs)
+ {
+ rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, (const bt_bdaddr_t*)p_open->rem_bda,
+ p_open->handle, p_open->new_listen_handle);
+ if(accept_rs)
+ {
+ //start monitor the socket
+ btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id);
+ btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, accept_rs->id);
+ APPL_TRACE_DEBUG1("sending connect signal & app fd:%dto app server to accept() the connection",
+ accept_rs->app_fd);
+ APPL_TRACE_DEBUG2("server fd:%d, scn:%d", srv_rs->fd, srv_rs->scn);
+ send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd);
+ accept_rs->app_fd = -1; //the fd is closed after sent to app
+ new_listen_slot_id = srv_rs->id;
+ }
+ }
+ unlock_slot(&slot_lock);
+ return new_listen_slot_id;
+}
+static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN *p_open, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs && p_open->status == BTA_JV_SUCCESS)
+ {
+ rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
+ bd_copy(rs->addr.address, p_open->rem_bda, 0);
+ //notify app rfc is connected
+ APPL_TRACE_DEBUG4("call send_app_connect_signal, slot id:%d, fd:%d, rfc scn:%d, server:%d",
+ rs->id, rs->fd, rs->scn, rs->f.server);
+ if(send_app_connect_signal(rs->fd, &rs->addr, rs->scn, 0, -1))
+ {
+ //start monitoring the socketpair to get call back when app writing data
+ APPL_TRACE_DEBUG3("on_rfc_connect_ind, connect signal sent, slot id:%d, rfc scn:%d, server:%d",
+ rs->id, rs->scn, rs->f.server);
+ rs->f.connected = TRUE;
+ }
+ else APPL_TRACE_ERROR0("send_app_connect_signal failed");
+ }
+ else if(rs)
+ cleanup_rfc_slot(rs);
+ unlock_slot(&slot_lock);
+}
+static void on_rfc_close(tBTA_JV_RFCOMM_CLOSE * p_close, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ APPL_TRACE_DEBUG4("on_rfc_close, slot id:%d, fd:%d, rfc scn:%d, server:%d",
+ rs->id, rs->fd, rs->scn, rs->f.server);
+ free_rfc_slot_scn(rs);
+ //rfc_handle already closed when receiving rfcomm close event from stack.
+ rs->rfc_handle = 0;
+ rs->f.connected = FALSE;
+ cleanup_rfc_slot(rs);
+ }
+ unlock_slot(&slot_lock);
+}
+static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE *p, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs && !rs->f.outgoing_congest)
+ {
+ //mointer the fd for any outgoing data
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
+ }
+ unlock_slot(&slot_lock);
+}
+static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG *p, uint32_t id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ rs->f.outgoing_congest = p->cong ? 1 : 0;
+ //mointer the fd for any outgoing data
+ if(!rs->f.outgoing_congest)
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id);
+ }
+ unlock_slot(&slot_lock);
+}
+
+static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
+{
+ int rc;
+ void* new_user_data = NULL;
+ APPL_TRACE_DEBUG1("event=%s", jv_evt[event]);
+
+ switch (event)
+ {
+ case BTA_JV_RFCOMM_START_EVT:
+ on_srv_rfc_listen_started(&p_data->rfc_start, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_CL_INIT_EVT:
+ on_cl_rfc_init(&p_data->rfc_cl_init, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_OPEN_EVT:
+ on_cli_rfc_connect(&p_data->rfc_open, (uint32_t)user_data);
+ break;
+ case BTA_JV_RFCOMM_SRV_OPEN_EVT:
+ new_user_data = (void*)on_srv_rfc_connect(&p_data->rfc_srv_open, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_CLOSE_EVT:
+ on_rfc_close(&p_data->rfc_close, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_READ_EVT:
+ APPL_TRACE_DEBUG0("BTA_JV_RFCOMM_READ_EVT not used");
+ break;
+
+ case BTA_JV_RFCOMM_WRITE_EVT:
+ on_rfc_write_done(&p_data->rfc_write, (uint32_t)user_data);
+ break;
+
+ case BTA_JV_RFCOMM_DATA_IND_EVT:
+ APPL_TRACE_DEBUG0("BTA_JV_RFCOMM_DATA_IND_EVT not used");
+ break;
+
+ case BTA_JV_RFCOMM_CONG_EVT:
+ //on_rfc_cong(&p_data->rfc_cong);
+ on_rfc_outgoing_congest(&p_data->rfc_cong, (uint32_t)user_data);
+ break;
+ default:
+ APPL_TRACE_ERROR2("unhandled event %d, slot id:%d", event, (uint32_t)user_data);
+ break;
+ }
+ return new_user_data;
+}
+
+static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
+{
+ uint32_t id = (uint32_t)user_data;
+ APPL_TRACE_DEBUG2("event:%d, slot id:%d", event, id);
+ switch(event)
+ {
+ case BTA_JV_CREATE_RECORD_EVT:
+ {
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs && create_server_sdp_record(rs))
+ {
+ //now start the rfcomm server after sdp & channel # assigned
+ BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION, rfcomm_cback,
+ (void*)rs->id);
+ }
+ unlock_slot(&slot_lock);
+ break;
+ }
+ case BTA_JV_DISCOVERY_COMP_EVT:
+ {
+ rfc_slot_t* rs = NULL;
+ lock_slot(&slot_lock);
+ if(p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn)
+ {
+ APPL_TRACE_DEBUG3("BTA_JV_DISCOVERY_COMP_EVT, slot id:%d, status:%d, scn:%d",
+ id, p_data->disc_comp.status, p_data->disc_comp.scn);
+
+ rs = find_rfc_slot_by_id(id);
+ if(rs && rs->f.doing_sdp_request)
+ {
+ if(BTA_JvRfcommConnect(rs->security, rs->role, p_data->disc_comp.scn, rs->addr.address,
+ rfcomm_cback, (void*)rs->id) == BTA_JV_SUCCESS)
+ {
+ rs->scn = p_data->disc_comp.scn;
+ rs->f.doing_sdp_request = FALSE;
+ if(!send_app_scn(rs))
+ cleanup_rfc_slot(rs);
+ }
+ else cleanup_rfc_slot(rs);
+ }
+ else if(rs)
+ {
+ APPL_TRACE_ERROR3("DISCOVERY_COMP_EVT no pending sdp request, slot id:%d, \
+ flag sdp pending:%d, flag sdp doing:%d",
+ id, rs->f.pending_sdp_request, rs->f.doing_sdp_request);
+ }
+ }
+ else
+ {
+ APPL_TRACE_ERROR3("DISCOVERY_COMP_EVT slot id:%d, failed to find channle, \
+ status:%d, scn:%d", id, p_data->disc_comp.status,
+ p_data->disc_comp.scn);
+ rs = find_rfc_slot_by_id(id);
+ if(rs)
+ cleanup_rfc_slot(rs);
+ }
+ rs = find_rfc_slot_by_pending_sdp();
+ if(rs)
+ {
+ APPL_TRACE_DEBUG0("BTA_JV_DISCOVERY_COMP_EVT, start another pending scn sdp request");
+ tSDP_UUID sdp_uuid;
+ sdp_uuid.len = 16;
+ memcpy(sdp_uuid.uu.uuid128, rs->service_uuid, sizeof(sdp_uuid.uu.uuid128));
+ BTA_JvStartDiscovery((UINT8*)rs->addr.address, 1, &sdp_uuid, (void*)rs->id);
+ rs->f.pending_sdp_request = FALSE;
+ rs->f.doing_sdp_request = TRUE;
+ }
+ unlock_slot(&slot_lock);
+ break;
+ }
+ default:
+ APPL_TRACE_DEBUG2("unhandled event:%d, slot id:%d", event, id);
+ break;
+ }
+
+}
+#define SENT_ALL 2
+#define SENT_PARTIAL 1
+#define SENT_NONE 0
+#define SENT_FAILED (-1)
+static int send_data_to_app(int fd, BT_HDR *p_buf)
+{
+ if(p_buf->len == 0)
+ return SENT_ALL;
+ int sent = send(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len, MSG_DONTWAIT);
+ if(sent == p_buf->len)
+ return SENT_ALL;
+
+ if(sent > 0 && sent < p_buf->len)
+ {
+ //sent partial
+ APPL_TRACE_ERROR2("send partial, sent:%d, p_buf->len:%d", sent, p_buf->len);
+ p_buf->offset += sent;
+ p_buf->len -= sent;
+ return SENT_PARTIAL;
+
+ }
+ if(sent < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))
+ {
+ APPL_TRACE_ERROR1("send none, EAGAIN or EWOULDBLOCK, errno:%d", errno);
+ return SENT_NONE;
+ }
+ APPL_TRACE_ERROR3("unknown send() error, sent:%d, p_buf->len:%d, errno:%d", sent, p_buf->len, errno);
+ return SENT_FAILED;
+}
+static BOOLEAN flush_incoming_que_on_wr_signal(rfc_slot_t* rs)
+{
+ while(!GKI_queue_is_empty(&rs->incoming_que))
+ {
+ BT_HDR *p_buf = GKI_dequeue(&rs->incoming_que);
+ int sent = send_data_to_app(rs->fd, p_buf);
+ switch(sent)
+ {
+ case SENT_NONE:
+ case SENT_PARTIAL:
+ //add it back to the queue at same position
+ GKI_enqueue_head (&rs->incoming_que, p_buf);
+ //monitor the fd to get callback when app is ready to receive data
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id);
+ return TRUE;
+ case SENT_ALL:
+ GKI_freebuf(p_buf);
+ break;
+ case SENT_FAILED:
+ GKI_freebuf(p_buf);
+ return FALSE;
+ }
+ }
+
+ //app is ready to receive data, tell stack to start the data flow
+ //fix me: need a jv flow control api to serialize the call in stack
+ PORT_FlowControl(rs->rfc_port_handle, TRUE);
+ return TRUE;
+}
+void btsock_rfc_signaled(int fd, int flags, uint32_t user_id)
+{
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(user_id);
+ if(rs)
+ {
+ APPL_TRACE_DEBUG3("rfc slot id:%d, fd:%d, flags:%x", rs->id, fd, flags);
+ BOOLEAN need_close = FALSE;
+ if(flags & SOCK_THREAD_FD_RD)
+ {
+ //data available from app, tell stack we have outgoing data
+ if(!rs->f.server)
+ {
+ if(rs->f.connected)
+ BTA_JvRfcommWrite(rs->rfc_handle, (UINT32)rs->id);
+ else
+ {
+ APPL_TRACE_ERROR2("SOCK_THREAD_FD_RD signaled when rfc is not connected, \
+ slot id:%d, channel:%d", rs->id, rs->scn);
+ need_close = TRUE;
+ }
+ }
+ }
+ if(flags & SOCK_THREAD_FD_WR)
+ {
+ //app is ready to receive more data, tell stack to enable the data flow
+ if(!rs->f.connected || !flush_incoming_que_on_wr_signal(rs))
+ {
+ need_close = TRUE;
+ APPL_TRACE_ERROR2("SOCK_THREAD_FD_WR signaled when rfc is not connected \
+ or app closed fd, slot id:%d, channel:%d", rs->id, rs->scn);
+ }
+
+ }
+ if(need_close || (flags & SOCK_THREAD_FD_EXCEPTION))
+ {
+ APPL_TRACE_DEBUG1("SOCK_THREAD_FD_EXCEPTION, flags:%x", flags);
+ rs->f.closing = TRUE;
+ if(rs->f.server)
+ BTA_JvRfcommStopServer(rs->rfc_handle);
+ else
+ BTA_JvRfcommClose(rs->rfc_handle);
+ }
+ }
+ unlock_slot(&slot_lock);
+}
+//stack rfcomm callout functions
+//[
+int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
+{
+ uint32_t id = (uint32_t)user_data;
+ int ret = 0;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+
+ int sent = send_data_to_app(rs->fd, p_buf);
+ switch(sent)
+ {
+ case SENT_NONE:
+ case SENT_PARTIAL:
+ //add it to the end of the queue
+ GKI_enqueue(&rs->incoming_que, p_buf);
+ //monitor the fd to get callback when app is ready to receive data
+ btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id);
+ break;
+ case SENT_ALL:
+ GKI_freebuf(p_buf);
+ ret = 1;//enable the data flow
+ break;
+ case SENT_FAILED:
+ GKI_freebuf(p_buf);
+ cleanup_rfc_slot(rs);
+ break;
+ }
+ }
+ unlock_slot(&slot_lock);
+ return ret;//return 0 to disable data flow
+}
+int bta_co_rfc_data_outgoing_size(void *user_data, int *size)
+{
+ uint32_t id = (uint32_t)user_data;
+ int ret = FALSE;
+ *size = 0;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ if(ioctl(rs->fd, FIONREAD, size) == 0)
+ {
+ APPL_TRACE_DEBUG2("ioctl read avaiable size:%d, fd:%d", *size, rs->fd);
+ ret = TRUE;
+ }
+ else
+ {
+ APPL_TRACE_ERROR2("ioctl FIONREAD error, errno:%d, fd:%d", errno, rs->fd);
+ cleanup_rfc_slot(rs);
+ }
+ }
+ unlock_slot(&slot_lock);
+ return ret;
+}
+int bta_co_rfc_data_outgoing(void *user_data, UINT8* buf, UINT16 size)
+{
+ uint32_t id = (uint32_t)user_data;
+ int ret = FALSE;
+ lock_slot(&slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ if(rs)
+ {
+ int received = recv(rs->fd, buf, size, 0);
+ if(received == size)
+ ret = TRUE;
+ else
+ {
+ APPL_TRACE_ERROR4("recv error, errno:%d, fd:%d, size:%d, received:%d",
+ errno, rs->fd, size, received);
+ cleanup_rfc_slot(rs);
+ }
+ }
+ unlock_slot(&slot_lock);
+ return ret;
+}
+//]
+
diff --git a/btif/src/btif_sock_sdp.c b/btif/src/btif_sock_sdp.c
new file mode 100644
index 0000000..cf55e8a
--- /dev/null
+++ b/btif/src/btif_sock_sdp.c
@@ -0,0 +1,443 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#define LOG_TAG "BTIF_SOCK_SDP"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "sdp_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btif_sock_sdp.h"
+#include "utl.h"
+#include "../bta/pb/bta_pbs_int.h"
+#include "../include/bta_op_api.h"
+#include <cutils/log.h>
+
+#define RESERVED_SCN_PBS 19
+#define RESERVED_SCN_OPS 12
+
+#define UUID_MAX_LENGTH 16
+
+
+#define IS_UUID(u1,u2) !memcmp(u1,u2,UUID_MAX_LENGTH)
+
+
+#define BTM_NUM_PROTO_ELEMS 2
+static int add_sdp_by_uuid(const char *name, const uint8_t *service_uuid, UINT16 channel)
+{
+
+ UINT32 btm_sdp_handle;
+
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTM_NUM_PROTO_ELEMS];
+
+ /* register the service */
+ if ((btm_sdp_handle = SDP_CreateRecord()) != FALSE)
+ {
+ /*** Fill out the protocol element sequence for SDP ***/
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+
+ proto_elem_list[1].params[0] = channel;
+
+ if (SDP_AddProtocolList(btm_sdp_handle, BTM_NUM_PROTO_ELEMS,
+ proto_elem_list))
+ {
+ UINT8 buff[48];
+ UINT8 *p, *type_buf[1];
+ UINT8 type[1], type_len[1];
+ p = type_buf[0] = buff;
+ type[0] = UUID_DESC_TYPE;
+
+// UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
+ ARRAY_TO_BE_STREAM (p, service_uuid, 16);
+ type_len[0] = 16;
+ if( SDP_AddSequence(btm_sdp_handle, (UINT16) ATTR_ID_SERVICE_CLASS_ID_LIST,
+ 1, type, type_len, type_buf) )
+// if (SDP_AddServiceClassIdList(btm_sdp_handle, 1, &service_uuid))
+ {
+ if ((SDP_AddAttribute(btm_sdp_handle, ATTR_ID_SERVICE_NAME,
+ TEXT_STR_DESC_TYPE, (UINT32)(strlen(name)+1),
+ (UINT8 *)name)) )
+ {
+ UINT16 list[1];
+
+ /* Make the service browseable */
+ list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ if ((SDP_AddUuidSequence (btm_sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
+ 1, list)) )
+
+ return btm_sdp_handle;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* Realm Character Set */
+#define BTA_PBS_REALM_CHARSET 0 /* ASCII */
+
+/* Specifies whether or not client's user id is required during obex authentication */
+#define BTA_PBS_USERID_REQ FALSE
+extern const tBTA_PBS_CFG bta_pbs_cfg;
+const tBTA_PBS_CFG bta_pbs_cfg =
+{
+ BTA_PBS_REALM_CHARSET, /* Server only */
+ BTA_PBS_USERID_REQ, /* Server only */
+ (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE),
+ BTA_PBS_REPOSIT_LOCAL,
+};
+
+static int add_pbap_sdp(const char* p_service_name, int scn)
+{
+
+ tSDP_PROTOCOL_ELEM protoList [3];
+ UINT16 pbs_service = UUID_SERVCLASS_PBAP_PSE;
+ UINT16 browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ BOOLEAN status = FALSE;
+ UINT32 sdp_handle = 0;
+ tBTA_PBS_CFG *p_bta_pbs_cfg = (tBTA_PBS_CFG *)&bta_pbs_cfg;
+
+ APPL_TRACE_DEBUG2("scn %d, service name %s", scn, p_service_name);
+
+ if ((sdp_handle = SDP_CreateRecord()) == 0)
+ {
+ APPL_TRACE_ERROR0("PBS SDP: Unable to register PBS Service");
+ return sdp_handle;
+ }
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(sdp_handle, 1, &pbs_service))
+ {
+ memset( protoList, 0 , 3*sizeof(tSDP_PROTOCOL_ELEM) );
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = scn;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+
+ if (SDP_AddProtocolList(sdp_handle, 3, protoList))
+ {
+ status = TRUE; /* All mandatory fields were successful */
+
+ /* optional: if name is not "", add a name entry */
+ if (*p_service_name != '\0')
+ SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name) + 1),
+ (UINT8 *)p_service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_PHONE_ACCESS,
+ BTA_PBS_DEFAULT_VERSION);
+
+ } /* end of setting mandatory protocol list */
+ } /* end of setting mandatory service class */
+
+ /* add supported feature and repositories */
+ if (status)
+ {
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&p_bta_pbs_cfg->supported_features);
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE,
+ (UINT32)1, (UINT8*)&p_bta_pbs_cfg->supported_repositories);
+
+ /* Make the service browseable */
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+ }
+
+ if (!status)
+ {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR0("bta_pbs_sdp_register FAILED");
+ }
+ else
+ {
+ bta_sys_add_uuid(pbs_service); /* UUID_SERVCLASS_PBAP_PSE */
+ APPL_TRACE_DEBUG1("PBS: SDP Registered (handle 0x%08x)", sdp_handle);
+ }
+
+ return sdp_handle;
+}
+
+
+/* object format lookup table */
+static const tBTA_OP_FMT bta_ops_obj_fmt[] =
+{
+ BTA_OP_VCARD21_FMT,
+ BTA_OP_VCARD30_FMT,
+ BTA_OP_VCAL_FMT,
+ BTA_OP_ICAL_FMT,
+ BTA_OP_VNOTE_FMT,
+ BTA_OP_VMSG_FMT,
+ BTA_OP_OTHER_FMT
+};
+
+#define BTA_OPS_NUM_FMTS 7
+#define BTA_OPS_PROTOCOL_COUNT 3
+
+#ifndef BTUI_OPS_FORMATS
+#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_VCARD30_MASK | \
+ BTA_OP_VCAL_MASK | BTA_OP_ICAL_MASK | \
+ BTA_OP_VNOTE_MASK | BTA_OP_VMSG_MASK | \
+ BTA_OP_ANY_MASK )
+#endif
+
+static int add_ops_sdp(const char *p_service_name,int scn)
+{
+
+
+ tSDP_PROTOCOL_ELEM protoList [BTA_OPS_PROTOCOL_COUNT];
+ UINT16 servclass = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ int i, j;
+ tBTA_UTL_COD cod;
+ UINT8 desc_type[BTA_OPS_NUM_FMTS];
+ UINT8 type_len[BTA_OPS_NUM_FMTS];
+ UINT8 *type_value[BTA_OPS_NUM_FMTS];
+ UINT16 browse;
+ UINT32 sdp_handle;
+ tBTA_OP_FMT_MASK formats = BTUI_OPS_FORMATS;
+
+ APPL_TRACE_DEBUG2("scn %d, service name %s", scn, p_service_name);
+
+ sdp_handle = SDP_CreateRecord();
+
+ /* add service class */
+ if (SDP_AddServiceClassIdList(sdp_handle, 1, &servclass))
+ {
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = scn;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+
+ if (SDP_AddProtocolList(sdp_handle, BTA_OPS_PROTOCOL_COUNT, protoList))
+ {
+ SDP_AddAttribute(sdp_handle,
+ (UINT16)ATTR_ID_SERVICE_NAME,
+ (UINT8)TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name) + 1),
+ (UINT8 *)p_service_name);
+
+ SDP_AddProfileDescriptorList(sdp_handle,
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ 0x0100);
+ }
+ }
+
+ /* Make the service browseable */
+ browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ /* add sequence for supported types */
+ for (i = 0, j = 0; i < BTA_OPS_NUM_FMTS; i++)
+ {
+ if ((formats >> i) & 1)
+ {
+ type_value[j] = (UINT8 *) &bta_ops_obj_fmt[i];
+ desc_type[j] = UINT_DESC_TYPE;
+ type_len[j++] = 1;
+ }
+ }
+
+ SDP_AddSequence(sdp_handle, (UINT16) ATTR_ID_SUPPORTED_FORMATS_LIST,
+ (UINT8) j, desc_type, type_len, type_value);
+
+ /* set class of device */
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+ bta_sys_add_uuid(servclass); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
+
+ return sdp_handle;
+}
+#define SPP_NUM_PROTO_ELEMS 2
+static int add_spp_sdp(const char *service_name, int scn)
+{
+ UINT16 serviceclassid = UUID_SERVCLASS_SERIAL_PORT;
+ tSDP_PROTOCOL_ELEM proto_elem_list[SPP_NUM_PROTO_ELEMS];
+ int sdp_handle;
+
+ APPL_TRACE_DEBUG2("scn %d, service name %s", scn, service_name);
+
+ /* register the service */
+ if ((sdp_handle = SDP_CreateRecord()) != FALSE)
+ {
+ /*** Fill out the protocol element sequence for SDP ***/
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+
+ proto_elem_list[1].params[0] = scn;
+
+ if (SDP_AddProtocolList(sdp_handle, SPP_NUM_PROTO_ELEMS, proto_elem_list))
+ {
+ if (SDP_AddServiceClassIdList(sdp_handle, 1, &serviceclassid))
+ {
+ if ((SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME,
+ TEXT_STR_DESC_TYPE, (UINT32)(strlen(service_name)+1),
+ (UINT8 *)service_name)))
+ {
+ UINT16 list[1];
+ /* Make the service browseable */
+ list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ SDP_AddUuidSequence (sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
+ 1, list);
+ }
+ }
+ }
+ }
+ return sdp_handle;
+}
+
+
+
+static int add_rfc_sdp_by_uuid(const char* name, const uint8_t* uuid, int scn)
+{
+ int handle = 0;
+
+ APPL_TRACE_DEBUG2("name:%s, scn:%d", name, scn);
+
+ /*
+ Bluetooth Socket API relies on having preregistered bluez sdp records for HSAG, HFAG, OPP & PBAP
+ that are mapped to rc chan 10, 11,12 & 19. Today HSAG and HFAG is routed to BRCM AG and are not
+ using BT socket API so for now we will need to support OPP and PBAP to enable 3rd party developer
+ apps running on BRCM Android.
+
+ To do this we will check the UUID for the requested service and mimic the SDP records of bluez
+ upon reception. See functions add_opush() and add_pbap() in sdptool.c for actual records
+ */
+
+ /* special handling for preregistered bluez services (OPP, PBAP) that we need to mimic */
+
+ int final_scn = get_reserved_rfc_channel(uuid);
+ if (final_scn == -1)
+ {
+ final_scn=scn;
+ }
+ if (IS_UUID(UUID_OBEX_OBJECT_PUSH,uuid))
+ {
+ handle = add_ops_sdp(name,final_scn);
+ }
+ else if (IS_UUID(UUID_PBAP_PSE,uuid))
+ {
+ handle = add_pbap_sdp(name, final_scn); //PBAP Server is always 19
+ }
+ else if (IS_UUID(UUID_SPP, uuid))
+ {
+ handle = add_spp_sdp(name, final_scn);
+ }
+ else
+ {
+ handle = add_sdp_by_uuid(name, uuid, final_scn);
+ }
+ return handle;
+}
+
+BOOLEAN is_reserved_rfc_channel(int scn)
+{
+ switch(scn)
+ {
+ case RESERVED_SCN_PBS:
+ case RESERVED_SCN_OPS:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+int get_reserved_rfc_channel (const uint8_t* uuid)
+{
+ if (IS_UUID(UUID_PBAP_PSE,uuid))
+ {
+ return RESERVED_SCN_PBS;
+ }
+ else if (IS_UUID(UUID_OBEX_OBJECT_PUSH,uuid))
+ {
+ return RESERVED_SCN_OPS;
+ }
+ return -1;
+}
+
+int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, int scn)
+{
+ int sdp_handle = 0;
+ if(is_uuid_empty(uuid))
+ {
+ switch(scn)
+ {
+ case RESERVED_SCN_PBS: // PBAP Reserved port
+ uuid = UUID_PBAP_PSE;
+ break;
+ case RESERVED_SCN_OPS:
+ uuid = UUID_OBEX_OBJECT_PUSH;
+ break;
+ default:
+ uuid = UUID_SPP;
+ break;
+ }
+ }
+ sdp_handle = add_rfc_sdp_by_uuid(name, uuid, scn);
+ return sdp_handle;
+}
+
+void del_rfc_sdp_rec(int handle)
+{
+ if(handle != -1 && handle != 0)
+ SDP_DeleteRecord( handle );
+}
+
diff --git a/btif/src/btif_sock_thread.c b/btif/src/btif_sock_thread.c
new file mode 100644
index 0000000..475b8de
--- /dev/null
+++ b/btif/src/btif_sock_thread.c
@@ -0,0 +1,593 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_sock_thread.c
+ *
+ * Description: socket select thread
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+//bta_jv_co_rfc_data
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <ctype.h>
+
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <cutils/sockets.h>
+#include <alloca.h>
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+#include "btif_sock.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+
+#include <cutils/log.h>
+#define asrt(s) if(!(s)) APPL_TRACE_ERROR3("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+#define print_events(events) do { \
+ APPL_TRACE_DEBUG1("print poll event:%x", events); \
+ if (events & POLLIN) APPL_TRACE_DEBUG0( " POLLIN "); \
+ if (events & POLLPRI) APPL_TRACE_DEBUG0( " POLLPRI "); \
+ if (events & POLLOUT) APPL_TRACE_DEBUG0( " POLLOUT "); \
+ if (events & POLLERR) APPL_TRACE_DEBUG0( " POLLERR "); \
+ if (events & POLLHUP) APPL_TRACE_DEBUG0( " POLLHUP "); \
+ if (events & POLLNVAL) APPL_TRACE_DEBUG0(" POLLNVAL "); \
+ if (events & POLLRDHUP) APPL_TRACE_DEBUG0(" POLLRDHUP"); \
+ } while(0)
+
+#define MAX_THREAD 8
+#define MAX_POLL 64
+#define POLL_EXCEPTION_EVENTS (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)
+#define IS_EXCEPTION(e) ((e) & POLL_EXCEPTION_EVENTS)
+#define IS_READ(e) ((e) & POLLIN)
+#define IS_WRITE(e) ((e) & POLLOUT)
+/*cmd executes in socket poll thread */
+#define CMD_WAKEUP 1
+#define CMD_EXIT 2
+#define CMD_ADD_FD 3
+#define CMD_USER_PRIVATE 4
+
+typedef struct {
+ struct pollfd pfd;
+ uint32_t user_id;
+ int type;
+ int flags;
+} poll_slot_t;
+typedef struct {
+ int cmd_fdr, cmd_fdw;
+ int poll_count;
+ poll_slot_t ps[MAX_POLL];
+ int psi[MAX_POLL]; //index of poll slot
+ volatile pid_t thread_id;
+ btsock_signaled_cb callback;
+ btsock_cmd_cb cmd_callback;
+ int used;
+} thread_slot_t;
+static thread_slot_t ts[MAX_THREAD];
+
+
+
+static void *sock_poll_thread(void *arg);
+static inline void close_cmd_fd(int h);
+
+static inline void add_poll(int h, int fd, int type, int flags, uint32_t user_id);
+
+static pthread_mutex_t thread_slot_lock;
+
+
+static inline void set_socket_blocking(int s, int blocking)
+{
+ int opts;
+ opts = fcntl(s, F_GETFL);
+ if (opts<0) APPL_TRACE_ERROR1("set blocking (%s)", strerror(errno));
+ if(blocking)
+ opts &= ~O_NONBLOCK;
+ else opts |= O_NONBLOCK;
+ fcntl(s, F_SETFL, opts);
+}
+
+static inline int create_server_socket(const char* name)
+{
+ int s = socket(AF_LOCAL, SOCK_STREAM, 0);
+ APPL_TRACE_DEBUG1("covert name to android abstract name:%s", name);
+ if(socket_local_server_bind(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) >= 0)
+ {
+ if(listen(s, 5) == 0)
+ {
+ APPL_TRACE_DEBUG2("listen to local socket:%s, fd:%d", name, s);
+ return s;
+ }
+ else APPL_TRACE_ERROR3("listen to local socket:%s, fd:%d failed, errno:%d", name, s, errno);
+ }
+ else APPL_TRACE_ERROR3("create local socket:%s fd:%d, failed, errno:%d", name, s, errno);
+ close(s);
+ return -1;
+}
+static inline int connect_server_socket(const char* name)
+{
+ int s = socket(AF_LOCAL, SOCK_STREAM, 0);
+ set_socket_blocking(s, TRUE);
+ if(socket_local_client_connect(s, name, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) >= 0)
+ {
+ APPL_TRACE_DEBUG2("connected to local socket:%s, fd:%d", name, s);
+ return s;
+ }
+ else APPL_TRACE_ERROR3("connect to local socket:%s, fd:%d failed, errno:%d", name, s, errno);
+ close(s);
+ return -1;
+}
+static inline int accept_server_socket(int s)
+{
+ struct sockaddr_un client_address;
+ socklen_t clen;
+ int fd = accept(s, (struct sockaddr*)&client_address, &clen);
+ APPL_TRACE_DEBUG2("accepted fd:%d for server fd:%d", fd, s);
+ return fd;
+}
+static inline pthread_t create_thread(void *(*start_routine)(void *), void * arg)
+{
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ pthread_t thread_id = -1;
+ if( pthread_create(&thread_id, &thread_attr, start_routine, arg)!=0 )
+ {
+ APPL_TRACE_ERROR1("pthread_create : %s", strerror(errno));
+ return -1;
+ }
+ return thread_id;
+}
+static void init_poll(int cmd_fd);
+static int alloc_thread_slot()
+{
+ int i;
+ //revserd order to save guard uninitialized access to 0 index
+ for(i = MAX_THREAD - 1; i >=0; i--)
+ {
+ APPL_TRACE_DEBUG2("ts[%d].used:%d", i, ts[i].used);
+ if(!ts[i].used)
+ {
+ ts[i].used = 1;
+ return i;
+ }
+ }
+ APPL_TRACE_ERROR0("execeeded max thread count");
+ return -1;
+}
+static void free_thread_slot(int h)
+{
+ if(0 <= h && h < MAX_THREAD)
+ {
+ close_cmd_fd(h);
+ ts[h].used = 0;
+ }
+ else APPL_TRACE_ERROR1("invalid thread handle:%d", h);
+}
+int btsock_thread_init()
+{
+ static int initialized;
+ APPL_TRACE_DEBUG1("in initialized:%d", initialized);
+ if(!initialized)
+ {
+ initialized = 1;
+ init_slot_lock(&thread_slot_lock);
+ int h;
+ for(h = 0; h < MAX_THREAD; h++)
+ {
+ ts[h].cmd_fdr = ts[h].cmd_fdw = -1;
+ ts[h].used = 0;
+ ts[h].thread_id = -1;
+ ts[h].poll_count = 0;
+ ts[h].callback = NULL;
+ ts[h].cmd_callback = NULL;
+ }
+ }
+ return TRUE;
+}
+int btsock_thread_create(btsock_signaled_cb callback, btsock_cmd_cb cmd_callback)
+{
+ int ret = FALSE;
+ asrt(callback || cmd_callback);
+ lock_slot(&thread_slot_lock);
+ int h = alloc_thread_slot();
+ unlock_slot(&thread_slot_lock);
+ APPL_TRACE_DEBUG1("alloc_thread_slot ret:%d", h);
+ if(h >= 0)
+ {
+ init_poll(h);
+ if((ts[h].thread_id = create_thread(sock_poll_thread, (void*)h)) != -1)
+ {
+ APPL_TRACE_DEBUG2("h:%d, thread id:%d", h, ts[h].thread_id);
+ ts[h].callback = callback;
+ ts[h].cmd_callback = cmd_callback;
+ }
+ else
+ {
+ free_thread_slot(h);
+ h = -1;
+ }
+ }
+ return h;
+}
+
+/* create dummy socket pair used to wake up select loop */
+static inline void init_cmd_fd(int h)
+{
+ asrt(ts[h].cmd_fdr == -1 && ts[h].cmd_fdw == -1);
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, &ts[h].cmd_fdr) < 0)
+ {
+ APPL_TRACE_ERROR1("socketpair failed: %s", strerror(errno));
+ return;
+ }
+ APPL_TRACE_DEBUG3("h:%d, cmd_fdr:%d, cmd_fdw:%d", h, ts[h].cmd_fdr, ts[h].cmd_fdw);
+ //add the cmd fd for read & write
+ add_poll(h, ts[h].cmd_fdr, 0, SOCK_THREAD_FD_RD, 0);
+}
+static inline void close_cmd_fd(int h)
+{
+ if(ts[h].cmd_fdr != -1)
+ {
+ close(ts[h].cmd_fdr);
+ ts[h].cmd_fdr = -1;
+ }
+ if(ts[h].cmd_fdw != -1)
+ {
+ close(ts[h].cmd_fdw);
+ ts[h].cmd_fdw = -1;
+ }
+}
+typedef struct
+{
+ int id;
+ int fd;
+ int type;
+ int flags;
+ uint32_t user_id;
+} sock_cmd_t;
+int btsock_thread_add_fd(int h, int fd, int type, int flags, uint32_t user_id)
+{
+ if(h < 0 || h >= MAX_THREAD)
+ {
+ APPL_TRACE_ERROR1("invalid bt thread handle:%d", h);
+ return FALSE;
+ }
+ if(ts[h].cmd_fdw == -1)
+ {
+ APPL_TRACE_ERROR0("cmd socket is not created. socket thread may not initialized");
+ return FALSE;
+ }
+ if(flags & SOCK_THREAD_ADD_FD_SYNC)
+ {
+ //must executed in socket poll thread
+ if(ts[h].thread_id == pthread_self())
+ {
+ //cleanup one-time flags
+ flags &= ~SOCK_THREAD_ADD_FD_SYNC;
+ add_poll(h, fd, type, flags, user_id);
+ return TRUE;
+ }
+ APPL_TRACE_DEBUG0("THREAD_ADD_FD_SYNC is not called in poll thread, fallback to async");
+ }
+ sock_cmd_t cmd = {CMD_ADD_FD, fd, type, flags, user_id};
+ APPL_TRACE_DEBUG2("adding fd:%d, flags:0x%x", fd, flags);
+ return send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd);
+}
+int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size, uint32_t user_id)
+{
+ if(h < 0 || h >= MAX_THREAD)
+ {
+ APPL_TRACE_ERROR1("invalid bt thread handle:%d", h);
+ return FALSE;
+ }
+ if(ts[h].cmd_fdw == -1)
+ {
+ APPL_TRACE_ERROR0("cmd socket is not created. socket thread may not initialized");
+ return FALSE;
+ }
+ sock_cmd_t cmd = {CMD_USER_PRIVATE, 0, type, size, user_id};
+ APPL_TRACE_DEBUG3("post cmd type:%d, size:%d, h:%d, ", type, size, h);
+ sock_cmd_t* cmd_send = &cmd;
+ int size_send = sizeof(cmd);
+ if(data && size)
+ {
+ size_send = sizeof(cmd) + size;
+ cmd_send = (sock_cmd_t*)alloca(size_send);
+ if(cmd_send)
+ {
+ *cmd_send = cmd;
+ memcpy(cmd_send + 1, data, size);
+ }
+ else
+ {
+ APPL_TRACE_ERROR3("alloca failed at h:%d, cmd type:%d, size:%d", h, type, size_send);
+ return FALSE;
+ }
+ }
+ return send(ts[h].cmd_fdw, cmd_send, size_send, 0) == size_send;
+}
+int btsock_thread_wakeup(int h)
+{
+ if(h < 0 || h >= MAX_THREAD)
+ {
+ APPL_TRACE_ERROR1("invalid bt thread handle:%d", h);
+ return FALSE;
+ }
+ if(ts[h].cmd_fdw == -1)
+ {
+ APPL_TRACE_ERROR1("thread handle:%d, cmd socket is not created", h);
+ return FALSE;
+ }
+ sock_cmd_t cmd = {CMD_WAKEUP, 0, 0, 0, 0};
+ return send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd);
+}
+int btsock_thread_exit(int h)
+{
+ if(h < 0 || h >= MAX_THREAD)
+ {
+ APPL_TRACE_ERROR1("invalid bt thread handle:%d", h);
+ return FALSE;
+ }
+ if(ts[h].cmd_fdw == -1)
+ {
+ APPL_TRACE_ERROR0("cmd socket is not created");
+ return FALSE;
+ }
+ sock_cmd_t cmd = {CMD_EXIT, 0, 0, 0, 0};
+ if(send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0) == sizeof(cmd))
+ {
+ pthread_join(ts[h].thread_id, 0);
+ lock_slot(&thread_slot_lock);
+ free_thread_slot(h);
+ unlock_slot(&thread_slot_lock);
+ return TRUE;
+ }
+ return FALSE;
+}
+static void init_poll(int h)
+{
+ int i;
+ ts[h].poll_count = 0;
+ ts[h].thread_id = -1;
+ ts[h].callback = NULL;
+ ts[h].cmd_callback = NULL;
+ for(i = 0; i < MAX_POLL; i++)
+ {
+ ts[h].ps[i].pfd.fd = -1;
+ ts[h].psi[i] = -1;
+ }
+ init_cmd_fd(h);
+}
+static inline unsigned int flags2pevents(int flags)
+{
+ unsigned int pevents = 0;
+ if(flags & SOCK_THREAD_FD_WR)
+ pevents |= POLLOUT;
+ if(flags & SOCK_THREAD_FD_RD)
+ pevents |= POLLIN;
+ pevents |= POLL_EXCEPTION_EVENTS;
+ return pevents;
+}
+
+static inline void set_poll(poll_slot_t* ps, int fd, int type, int flags, uint32_t user_id)
+{
+ ps->pfd.fd = fd;
+ ps->user_id = user_id;
+ if(ps->type != 0 && ps->type != type)
+ APPL_TRACE_ERROR2("poll socket type should not changed! type was:%d, type now:%d", ps->type, type);
+ ps->type = type;
+ ps->flags = flags;
+ ps->pfd.events = flags2pevents(flags);
+ ps->pfd.revents = 0;
+}
+static inline void add_poll(int h, int fd, int type, int flags, uint32_t user_id)
+{
+ asrt(fd != -1);
+ int i;
+ int empty = -1;
+ poll_slot_t* ps = ts[h].ps;
+
+ for(i = 0; i < MAX_POLL; i++)
+ {
+ if(ps[i].pfd.fd == fd)
+ {
+ asrt(ts[h].poll_count < MAX_POLL);
+
+ set_poll(&ps[i], fd, type, flags | ps[i].flags, user_id);
+ return;
+ }
+ else if(empty < 0 && ps[i].pfd.fd == -1)
+ empty = i;
+ }
+ if(empty >= 0)
+ {
+ asrt(ts[h].poll_count < MAX_POLL);
+ set_poll(&ps[empty], fd, type, flags, user_id);
+ ++ts[h].poll_count;
+ return;
+ }
+ APPL_TRACE_ERROR1("exceeded max poll slot:%d!", MAX_POLL);
+}
+static inline void remove_poll(int h, poll_slot_t* ps, int flags)
+{
+ if(flags == ps->flags)
+ {
+ //all monitored events signaled. To remove it, just clear the slot
+ --ts[h].poll_count;
+ memset(ps, 0, sizeof(*ps));
+ ps->pfd.fd = -1;
+ }
+ else
+ {
+ //one read or one write monitor event signaled, removed the accordding bit
+ ps->flags &= ~flags;
+ //update the poll events mask
+ ps->pfd.events = flags2pevents(ps->flags);
+ }
+}
+static int process_cmd_sock(int h)
+{
+ sock_cmd_t cmd = {-1, 0, 0, 0, 0};
+ int fd = ts[h].cmd_fdr;
+ if(recv(fd, &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
+ {
+ APPL_TRACE_ERROR1("recv cmd errno:%d", errno);
+ return FALSE;
+ }
+ APPL_TRACE_DEBUG1("cmd.id:%d", cmd.id);
+ switch(cmd.id)
+ {
+ case CMD_ADD_FD:
+ add_poll(h, cmd.fd, cmd.type, cmd.flags, cmd.user_id);
+ break;
+ case CMD_WAKEUP:
+ break;
+ case CMD_USER_PRIVATE:
+ asrt(ts[h].cmd_callback);
+ if(ts[h].cmd_callback)
+ ts[h].cmd_callback(fd, cmd.type, cmd.flags, cmd.user_id);
+ break;
+ case CMD_EXIT:
+ return FALSE;
+ default:
+ APPL_TRACE_DEBUG1("unknown cmd: %d", cmd.id);
+ break;
+ }
+ return TRUE;
+}
+static void process_data_sock(int h, struct pollfd *pfds, int count)
+{
+ asrt(count <= ts[h].poll_count);
+ int i;
+ for( i= 1; i < ts[h].poll_count; i++)
+ {
+ if(pfds[i].revents)
+ {
+ int ps_i = ts[h].psi[i];
+ asrt(pfds[i].fd == ts[h].ps[ps_i].pfd.fd);
+ uint32_t user_id = ts[h].ps[ps_i].user_id;
+ int type = ts[h].ps[ps_i].type;
+ int flags = 0;
+ print_events(pfds[i].revents);
+ if(IS_READ(pfds[i].revents))
+ {
+ flags |= SOCK_THREAD_FD_RD;
+ }
+ if(IS_WRITE(pfds[i].revents))
+ {
+ flags |= SOCK_THREAD_FD_WR;
+ }
+ if(IS_EXCEPTION(pfds[i].revents))
+ {
+ flags |= SOCK_THREAD_FD_EXCEPTION;
+ //remove the whole slot not flags
+ remove_poll(h, &ts[h].ps[ps_i], ts[h].ps[ps_i].flags);
+ }
+ else if(flags)
+ remove_poll(h, &ts[h].ps[ps_i], flags); //remove the monitor flags that already processed
+ if(flags)
+ ts[h].callback(pfds[i].fd, type, flags, user_id);
+ }
+ }
+}
+
+static void prepare_poll_fds(int h, struct pollfd* pfds)
+{
+ int count = 0;
+ int ps_i = 0;
+ int pfd_i = 0;
+ asrt(ts[h].poll_count <= MAX_POLL);
+ memset(pfds, 0, sizeof(pfds[0])*ts[h].poll_count);
+ while(count < ts[h].poll_count)
+ {
+ if(ps_i >= MAX_POLL)
+ {
+ APPL_TRACE_ERROR4("exceed max poll range, ps_i:%d, MAX_POLL:%d, count:%d, ts[h].poll_count:%d",
+ ps_i, MAX_POLL, count, ts[h].poll_count);
+ return;
+ }
+ if(ts[h].ps[ps_i].pfd.fd >= 0)
+ {
+ pfds[pfd_i] = ts[h].ps[ps_i].pfd;
+ ts[h].psi[pfd_i] = ps_i;
+ count++;
+ pfd_i++;
+ }
+ ps_i++;
+ }
+}
+static void *sock_poll_thread(void *arg)
+{
+ struct pollfd pfds[MAX_POLL];
+ memset(pfds, 0, sizeof(pfds));
+ int h = (int)arg;
+ for(;;)
+ {
+ prepare_poll_fds(h, pfds);
+ int ret = poll(pfds, ts[h].poll_count, -1);
+ if(ret == -1)
+ {
+ APPL_TRACE_ERROR2("poll ret -1, exit the thread, errno:%d, err:%s", errno, strerror(errno));
+ break;
+ }
+ if(ret != 0)
+ {
+ int need_process_data_fd = TRUE;
+ if(pfds[0].revents) //cmd fd always is the first one
+ {
+ asrt(pfds[0].fd == ts[h].cmd_fdr);
+ if(!process_cmd_sock(h))
+ {
+ APPL_TRACE_DEBUG1("h:%d, process_cmd_sock return false, exit...", h);
+ break;
+ }
+ if(ret == 1)
+ need_process_data_fd = FALSE;
+ else ret--; //exclude the cmd fd
+ }
+ if(need_process_data_fd)
+ process_data_sock(h, pfds, ret);
+ }
+ else {APPL_TRACE_DEBUG1("no data, select ret: %d", ret)};
+ }
+ ts[h].thread_id = -1;
+ APPL_TRACE_DEBUG1("socket poll thread exiting, h:%d", h);
+ return 0;
+}
+
diff --git a/btif/src/btif_sock_util.c b/btif/src/btif_sock_util.c
new file mode 100644
index 0000000..09df03e
--- /dev/null
+++ b/btif/src/btif_sock_util.c
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+
+/************************************************************************************
+ *
+ * Filename: btif_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <cutils/sockets.h>
+#include <netinet/tcp.h>
+
+
+#define LOG_TAG "BTIF_SOCK"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bd.h"
+
+#include "bta_api.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_sdp.h"
+
+#include "bt_target.h"
+#include "gki.h"
+#include "hcimsgs.h"
+#include "sdp_api.h"
+#include "btu.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "port_api.h"
+
+#include <cutils/log.h>
+
+#define info(fmt, ...) ALOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+
+int sock_send_all(int sock_fd, const uint8_t* buf, int len)
+{
+ int s = len;
+ int ret;
+ while(s)
+ {
+ do ret = send(sock_fd, buf, s, 0);
+ while(ret < 0 && errno == EINTR);
+ if(ret <= 0)
+ {
+ error("sock fd:%d send errno:%d, ret:%d", sock_fd, errno, ret);
+ return -1;
+ }
+ buf += ret;
+ s -= ret;
+ }
+ return len;
+}
+int sock_recv_all(int sock_fd, uint8_t* buf, int len)
+{
+ int r = len;
+ int ret = -1;
+ while(r)
+ {
+ do ret = recv(sock_fd, buf, r, MSG_WAITALL);
+ while(ret < 0 && errno == EINTR);
+ if(ret <= 0)
+ {
+ error("sock fd:%d recv errno:%d, ret:%d", sock_fd, errno, ret);
+ return -1;
+ }
+ buf += ret;
+ r -= ret;
+ }
+ return len;
+}
+
+int sock_send_fd(int sock_fd, const uint8_t* buf, int len, int send_fd)
+{
+ ssize_t ret;
+ struct msghdr msg;
+ unsigned char *buffer = (unsigned char *)buf;
+ memset(&msg, 0, sizeof(msg));
+
+ struct cmsghdr *cmsg;
+ char msgbuf[CMSG_SPACE(1)];
+ asrt(send_fd != -1);
+ if(sock_fd == -1 || send_fd == -1)
+ return -1;
+ // Add any pending outbound file descriptors to the message
+ // See "man cmsg" really
+ msg.msg_control = msgbuf;
+ msg.msg_controllen = sizeof msgbuf;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof send_fd);
+ memcpy(CMSG_DATA(cmsg), &send_fd, sizeof send_fd);
+
+ // We only write our msg_control during the first write
+ int ret_len = len;
+ while (len > 0) {
+ struct iovec iv;
+ memset(&iv, 0, sizeof(iv));
+
+ iv.iov_base = buffer;
+ iv.iov_len = len;
+
+ msg.msg_iov = &iv;
+ msg.msg_iovlen = 1;
+
+ do {
+ ret = sendmsg(sock_fd, &msg, MSG_NOSIGNAL);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ error("fd:%d, send_fd:%d, sendmsg ret:%d, errno:%d, %s",
+ sock_fd, send_fd, (int)ret, errno, strerror(errno));
+ ret_len = -1;
+ break;
+ }
+
+ buffer += ret;
+ len -= ret;
+
+ // Wipes out any msg_control too
+ memset(&msg, 0, sizeof(msg));
+ }
+ debug("close fd:%d after sent", send_fd);
+ close(send_fd);
+ return ret_len;
+}
+
+
+#define PRINT(s) __android_log_write(ANDROID_LOG_DEBUG, NULL, s)
+static const char* hex_table = "0123456789abcdef";
+static inline void byte2hex(const char* data, char** str)
+{
+ **str = hex_table[(*data >> 4) & 0xf];
+ ++*str;
+ **str = hex_table[*data & 0xf];
+ ++*str;
+}
+static inline void byte2char(const char* data, char** str)
+{
+ **str = *data < ' ' ? '.' : *data > '~' ? '.' : *data;
+ ++(*str);
+}
+static inline void word2hex(const char* data, char** hex)
+{
+ byte2hex(&data[1], hex);
+ byte2hex(&data[0], hex);
+}
+void dump_bin(const char* title, const char* data, int size)
+{
+ char line_buff[256];
+ char *line;
+ int i, j, addr;
+ const int width = 16;
+ ALOGD("%s, size:%d, dump started {", title, size);
+ if(size <= 0)
+ return;
+ //write offset
+ line = line_buff;
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ for(j = 0; j < width; j++)
+ {
+ byte2hex((const char*)&j, &line);
+ *line++ = ' ';
+ }
+ *line = 0;
+ PRINT(line_buff);
+
+ for(i = 0; i < size / width; i++)
+ {
+ line = line_buff;
+ //write address:
+ addr = i*width;
+ word2hex((const char*)&addr, &line);
+ *line++ = ':'; *line++ = ' ';
+ //write hex of data
+ for(j = 0; j < width; j++)
+ {
+ byte2hex(&data[j], &line);
+ *line++ = ' ';
+ }
+ //write char of data
+ for(j = 0; j < width; j++)
+ byte2char(data++, &line);
+ //wirte the end of line
+ *line = 0;
+ //output the line
+ PRINT(line_buff);
+ }
+ //last line of left over if any
+ int leftover = size % width;
+ if(leftover > 0)
+ {
+ line = line_buff;
+ //write address:
+ addr = i*width;
+ word2hex((const char*)&addr, &line);
+ *line++ = ':'; *line++ = ' ';
+ //write hex of data
+ for(j = 0; j < leftover; j++) {
+ byte2hex(&data[j], &line);
+ *line++ = ' ';
+ }
+ //write hex padding
+ for(; j < width; j++) {
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ }
+ //write char of data
+ for(j = 0; j < leftover; j++)
+ byte2char(data++, &line);
+ //write the end of line
+ *line = 0;
+ //output the line
+ PRINT(line_buff);
+ }
+ ALOGD("%s, size:%d, dump ended }", title, size);
+}
+
diff --git a/btif/src/btif_storage.c b/btif/src/btif_storage.c
new file mode 100755
index 0000000..6d702a7
--- /dev/null
+++ b/btif/src/btif_storage.c
@@ -0,0 +1,1410 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_storage.c
+ *
+ * Description: Stores the local BT adapter and remote device properties in
+ * NVRAM storage, typically as xml file in the
+ * mobile's filesystem
+ *
+ *
+ */
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+#include <alloca.h>
+
+
+#include <hardware/bluetooth.h>
+#include "btif_config.h"
+#define LOG_TAG "BTIF_STORAGE"
+
+#include "btif_api.h"
+
+#include "btif_util.h"
+#include "bd.h"
+#include "gki.h"
+#include "bta_hh_api.h"
+#include "btif_hh.h"
+
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define warn(fmt, ...) ALOGW ("## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+
+#define BTIF_STORAGE_PATH_BLUEDROID "/data/misc/bluedroid"
+
+//#define BTIF_STORAGE_PATH_ADAPTER_INFO "adapter_info"
+//#define BTIF_STORAGE_PATH_REMOTE_DEVICES "remote_devices"
+#define BTIF_STORAGE_PATH_REMOTE_DEVTIME "Timestamp"
+#define BTIF_STORAGE_PATH_REMOTE_DEVCLASS "DevClass"
+#define BTIF_STORAGE_PATH_REMOTE_DEVTYPE "DevType"
+#define BTIF_STORAGE_PATH_REMOTE_NAME "Name"
+//#define BTIF_STORAGE_PATH_REMOTE_LINKKEYS "remote_linkkeys"
+#define BTIF_STORAGE_PATH_REMOTE_ALIASE "Aliase"
+#define BTIF_STORAGE_PATH_REMOTE_SERVICE "Service"
+#define BTIF_STORAGE_PATH_REMOTE_HIDINFO "HidInfo"
+#define BTIF_STORAGE_KEY_ADAPTER_NAME "Name"
+#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode"
+#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout"
+
+
+#define BTIF_AUTO_PAIR_CONF_FILE "/etc/bluetooth/auto_pair_devlist.conf"
+#define BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST "AutoPairBlacklist"
+#define BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_ADDR "AddressBlacklist"
+#define BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_EXACTNAME "ExactNameBlacklist"
+#define BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_PARTIALNAME "PartialNameBlacklist"
+#define BTIF_STORAGE_KEY_AUTOPAIR_FIXPIN_KBLIST "FixedPinZerosKeyboardBlacklist"
+#define BTIF_STORAGE_KEY_AUTOPAIR_DYNAMIC_BLACKLIST_ADDR "DynamicAddressBlacklist"
+
+#define BTIF_AUTO_PAIR_CONF_VALUE_SEPARATOR ","
+#define BTIF_AUTO_PAIR_CONF_SPACE ' '
+#define BTIF_AUTO_PAIR_CONF_COMMENT '#'
+#define BTIF_AUTO_PAIR_CONF_KEY_VAL_DELIMETER "="
+
+
+/* This is a local property to add a device found */
+#define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
+
+#define BTIF_STORAGE_GET_ADAPTER_PROP(t,v,l,p) \
+ {p.type=t;p.val=v;p.len=l; btif_storage_get_adapter_property(&p);}
+
+#define BTIF_STORAGE_GET_REMOTE_PROP(b,t,v,l,p) \
+ {p.type=t;p.val=v;p.len=l;btif_storage_get_remote_device_property(b,&p);}
+
+#define STORAGE_BDADDR_STRING_SZ (18) /* 00:11:22:33:44:55 */
+#define STORAGE_UUID_STRING_SIZE (36+1) /* 00001200-0000-1000-8000-00805f9b34fb; */
+#define STORAGE_PINLEN_STRING_MAX_SIZE (2) /* ascii pinlen max chars */
+#define STORAGE_KEYTYPE_STRING_MAX_SIZE (1) /* ascii keytype max chars */
+
+#define STORAGE_KEY_TYPE_MAX (10)
+
+#define STORAGE_HID_ATRR_MASK_SIZE (4)
+#define STORAGE_HID_SUB_CLASS_SIZE (2)
+#define STORAGE_HID_APP_ID_SIZE (2)
+#define STORAGE_HID_VENDOR_ID_SIZE (4)
+#define STORAGE_HID_PRODUCT_ID_SIZE (4)
+#define STORAGE_HID_VERSION_SIZE (4)
+#define STORAGE_HID_CTRY_CODE_SIZE (2)
+#define STORAGE_HID_DESC_LEN_SIZE (4)
+#define STORAGE_HID_DESC_MAX_SIZE (2*512)
+
+/* <18 char bd addr> <space> LIST< <36 char uuid> <;> > <keytype (dec)> <pinlen> */
+#define BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX (STORAGE_BDADDR_STRING_SZ + 1 +\
+ STORAGE_UUID_STRING_SIZE*BT_MAX_NUM_UUIDS + \
+ STORAGE_PINLEN_STRING_MAX_SIZE +\
+ STORAGE_KEYTYPE_STRING_MAX_SIZE)
+
+#define STORAGE_REMOTE_LINKKEYS_ENTRY_SIZE (LINK_KEY_LEN*2 + 1 + 2 + 1 + 2)
+
+/* <18 char bd addr> <space>LIST <attr_mask> <space> > <sub_class> <space> <app_id> <space>
+ <vendor_id> <space> > <product_id> <space> <version> <space>
+ <ctry_code> <space> > <desc_len> <space> <desc_list> <space> */
+#define BTIF_HID_INFO_ENTRY_SIZE_MAX (STORAGE_BDADDR_STRING_SZ + 1 +\
+ STORAGE_HID_ATRR_MASK_SIZE + 1 +\
+ STORAGE_HID_SUB_CLASS_SIZE + 1 +\
+ STORAGE_HID_APP_ID_SIZE+ 1 +\
+ STORAGE_HID_VENDOR_ID_SIZE+ 1 +\
+ STORAGE_HID_PRODUCT_ID_SIZE+ 1 +\
+ STORAGE_HID_VERSION_SIZE+ 1 +\
+ STORAGE_HID_CTRY_CODE_SIZE+ 1 +\
+ STORAGE_HID_DESC_LEN_SIZE+ 1 +\
+ STORAGE_HID_DESC_MAX_SIZE+ 1 )
+
+
+/* currently remote services is the potentially largest entry */
+#define BTIF_STORAGE_MAX_LINE_SZ BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX
+
+
+/* check against unv max entry size at compile time */
+#if (BTIF_STORAGE_ENTRY_MAX_SIZE > UNV_MAXLINE_LENGTH)
+ #error "btif storage entry size exceeds unv max line size"
+#endif
+
+
+#define BTIF_STORAGE_HL_APP "hl_app"
+#define BTIF_STORAGE_HL_APP_CB "hl_app_cb"
+#define BTIF_STORAGE_HL_APP_DATA "hl_app_data_"
+#define BTIF_STORAGE_HL_APP_MDL_DATA "hl_app_mdl_data_"
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+typedef struct
+{
+ uint32_t num_devices;
+ bt_bdaddr_t devices[BTM_SEC_MAX_DEVICE_RECORDS];
+} btif_bonded_devices_t;
+
+/************************************************************************************
+** Extern variables
+************************************************************************************/
+extern UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID];
+extern bt_bdaddr_t btif_local_bd_addr;
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+/*******************************************************************************
+**
+** Function btif_in_make_filename
+**
+** Description Internal helper function to create NVRAM file path
+** from address and filename
+**
+** Returns NVRAM file path if successfull, NULL otherwise
+**
+*******************************************************************************/
+static char* btif_in_make_filename(bt_bdaddr_t *bd_addr, char *fname)
+{
+ static char path[256];
+ bdstr_t bdstr;
+
+ if (fname == NULL)return NULL;
+ if (bd_addr)
+ {
+ sprintf(path, "%s/%s/%s", BTIF_STORAGE_PATH_BLUEDROID,
+ bd2str(bd_addr, &bdstr), fname);
+ }
+ else
+ {
+ /* local adapter */
+ sprintf(path, "%s/LOCAL/%s", BTIF_STORAGE_PATH_BLUEDROID, fname);
+ }
+
+ return(char*)path;
+}
+/*******************************************************************************
+**
+** Function btif_in_split_uuids_string_to_list
+**
+** Description Internal helper function to split the string of UUIDs
+** read from the NVRAM to an array
+**
+** Returns None
+**
+*******************************************************************************/
+static void btif_in_split_uuids_string_to_list(char *str, bt_uuid_t *p_uuid,
+ uint32_t *p_num_uuid)
+{
+ char buf[64];
+ char *p_start = str;
+ char *p_needle;
+ uint32_t num = 0;
+ do
+ {
+ //p_needle = strchr(p_start, ';');
+ p_needle = strchr(p_start, ' ');
+ if (p_needle < p_start) break;
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, p_start, (p_needle-p_start));
+ string_to_uuid(buf, p_uuid + num);
+ num++;
+ p_start = ++p_needle;
+
+ } while (*p_start != 0);
+ *p_num_uuid = num;
+}
+static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
+{
+ bdstr_t bdstr = {0};
+ if(remote_bd_addr)
+ bd2str(remote_bd_addr, &bdstr);
+ debug("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type, prop->len);
+ char value[1024];
+ if(prop->len <= 0 || prop->len > (int)sizeof(value) - 1)
+ {
+ error("property type:%d, len:%d is invalid", prop->type, prop->len);
+ return FALSE;
+ }
+ switch(prop->type)
+ {
+ case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+ btif_config_set_int("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_DEVTIME, (int)time(NULL));
+ break;
+ case BT_PROPERTY_BDNAME:
+ strncpy(value, (char*)prop->val, prop->len);
+ value[prop->len]='\0';
+ if(remote_bd_addr)
+ btif_config_set_str("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_NAME, value);
+ else btif_config_set_str("Local", "Adapter",
+ BTIF_STORAGE_KEY_ADAPTER_NAME, value);
+ break;
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ strncpy(value, (char*)prop->val, prop->len);
+ value[prop->len]='\0';
+ btif_config_set_str("Remote", bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE, value);
+ break;
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ btif_config_set_int("Local", "Adapter",
+ BTIF_STORAGE_KEY_ADAPTER_SCANMODE, *(int*)prop->val);
+ break;
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ btif_config_set_int("Local", "Adapter",
+ BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT, *(int*)prop->val);
+ break;
+ case BT_PROPERTY_CLASS_OF_DEVICE:
+ btif_config_set_int("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_DEVCLASS, *(int*)prop->val);
+ break;
+ case BT_PROPERTY_TYPE_OF_DEVICE:
+ btif_config_set_int("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_DEVTYPE, *(int*)prop->val);
+ break;
+ case BT_PROPERTY_UUIDS:
+ {
+ uint32_t i;
+ char buf[64];
+ value[0] = 0;
+ for (i=0; i < (prop->len)/sizeof(bt_uuid_t); i++)
+ {
+ bt_uuid_t *p_uuid = (bt_uuid_t*)prop->val + i;
+ memset(buf, 0, sizeof(buf));
+ uuid_to_string(p_uuid, buf);
+ strcat(value, buf);
+ //strcat(value, ";");
+ strcat(value, " ");
+ }
+ btif_config_set_str("Remote", bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value);
+ btif_config_save();
+ break;
+ }
+ default:
+ error("Unknow prop type:%d", prop->type);
+ return FALSE;
+ }
+ return TRUE;
+}
+static int cfg2prop(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
+{
+ bdstr_t bdstr = {0};
+ if(remote_bd_addr)
+ bd2str(remote_bd_addr, &bdstr);
+ debug("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type, prop->len);
+ if(prop->len <= 0)
+ {
+ error("property type:%d, len:%d is invalid", prop->type, prop->len);
+ return FALSE;
+ }
+ int ret = FALSE;
+ switch(prop->type)
+ {
+ case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+ if(prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_DEVTIME, (int*)prop->val);
+ break;
+ case BT_PROPERTY_BDNAME:
+ {
+ int len = prop->len;
+ if(remote_bd_addr)
+ ret = btif_config_get_str("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_NAME, (char*)prop->val, &len);
+ else ret = btif_config_get_str("Local", "Adapter",
+ BTIF_STORAGE_KEY_ADAPTER_NAME, (char*)prop->val, &len);
+ if(ret && len && len <= prop->len)
+ prop->len = len - 1;
+ else
+ {
+ prop->len = 0;
+ ret = FALSE;
+ }
+ break;
+ }
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ {
+ int len = prop->len;
+ ret = btif_config_get_str("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_ALIASE, (char*)prop->val, &len);
+ if(ret && len && len <= prop->len)
+ prop->len = len - 1;
+ else
+ {
+ prop->len = 0;
+ ret = FALSE;
+ }
+ break;
+ }
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ if(prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Local", "Adapter",
+ BTIF_STORAGE_KEY_ADAPTER_SCANMODE, (int*)prop->val);
+ break;
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ if(prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Local", "Adapter",
+ BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT, (int*)prop->val);
+ break;
+ case BT_PROPERTY_CLASS_OF_DEVICE:
+ if(prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_DEVCLASS, (int*)prop->val);
+ break;
+ case BT_PROPERTY_TYPE_OF_DEVICE:
+ if(prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Remote",
+ bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE, (int*)prop->val);
+ break;
+ case BT_PROPERTY_UUIDS:
+ {
+ char value[1280];
+ int size = sizeof(value);
+ if(btif_config_get_str("Remote", bdstr,
+ BTIF_STORAGE_PATH_REMOTE_SERVICE, value, &size))
+ {
+ bt_uuid_t *p_uuid = (bt_uuid_t*)prop->val;
+ uint32_t num_uuids = 0;
+ btif_in_split_uuids_string_to_list(value, p_uuid, &num_uuids);
+ prop->len = num_uuids * sizeof(bt_uuid_t);
+ ret = TRUE;
+ }
+ break;
+ }
+ default:
+ error("Unknow prop type:%d", prop->type);
+ return FALSE;
+ }
+ return ret;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_in_fetch_bonded_devices
+**
+** Description Internal helper function to fetch the bonded devices
+** from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+static bt_status_t btif_in_fetch_bonded_devices(btif_bonded_devices_t *p_bonded_devices, int add)
+{
+ debug("in add:%d", add);
+ memset(p_bonded_devices, 0, sizeof(btif_bonded_devices_t));
+
+ char kname[128], vname[128];
+ short kpos;
+ int kname_size;
+ kname_size = sizeof(kname);
+ kname[0] = 0;
+ kpos = 0;
+ do
+ {
+ kpos = btif_config_next_key(kpos, "Remote", kname, &kname_size);
+ debug("Remote device:%s, size:%d", kname, kname_size);
+ int type = BTIF_CFG_TYPE_BIN;
+ LINK_KEY link_key;
+ int size = sizeof(link_key);
+ if(btif_config_get("Remote", kname, "LinkKey", (char*)link_key, &size, &type))
+ {
+ int linkkey_type;
+ if(btif_config_get_int("Remote", kname, "LinkKeyType", &linkkey_type))
+ {
+ //int pin_len;
+ //btif_config_get_int("Remote", kname, "PinLength", &pin_len))
+ bt_bdaddr_t bd_addr;
+ str2bd(kname, &bd_addr);
+ if(add)
+ {
+ DEV_CLASS dev_class = {0, 0, 0};
+ int cod;
+ if(btif_config_get_int("Remote", kname, "DevClass", &cod))
+ uint2devclass((UINT32)cod, dev_class);
+ BTA_DmAddDevice(bd_addr.address, dev_class, link_key, 0, 0, (UINT8)linkkey_type, 0);
+ }
+ memcpy(&p_bonded_devices->devices[p_bonded_devices->num_devices++], &bd_addr, sizeof(bt_bdaddr_t));
+ }
+ else error("bounded device:%s, LinkKeyType or PinLength is invalid", kname);
+ }
+ else debug("Remote device:%s, no link key", kname);
+ kname_size = sizeof(kname);
+ kname[0] = 0;
+ } while(kpos != -1);
+ debug("out");
+ return BT_STATUS_SUCCESS;
+}
+
+static int hex_str_to_int(const char* str, int size)
+{
+ int n = 0;
+ char c = *str++;
+ while (size-- != 0)
+ {
+ n <<= 4;
+ if (c >= '0' && c <= '9') {
+ n |= c - '0';
+ }
+ else if (c >= 'a' && c <= 'z') {
+ n |= c - 'a' + 10;
+ }
+ else // (c >= 'A' && c <= 'Z')
+ {
+ n |= c - 'A' + 10;
+ }
+
+ c = *str++;
+ }
+ return n;
+}
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/** functions are synchronous.
+ * functions can be called by both internal modules such as BTIF_DM and by external entiries from HAL via BTIF_context_switch
+ * For OUT parameters, caller is expected to provide the memory.
+ * Caller is expected to provide a valid pointer to 'property->value' based on the property->type
+ */
+/*******************************************************************************
+**
+** Function btif_storage_get_adapter_property
+**
+** Description BTIF storage API - Fetches the adapter property->type
+** from NVRAM and fills property->val.
+** Caller should provide memory for property->val and
+** set the property->val
+**
+** Returns BT_STATUS_SUCCESS if the fetch was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_get_adapter_property(bt_property_t *property)
+{
+
+ /* Special handling for adapter BD_ADDR and BONDED_DEVICES */
+ if (property->type == BT_PROPERTY_BDADDR)
+ {
+ BD_ADDR addr;
+ bt_bdaddr_t *bd_addr = (bt_bdaddr_t*)property->val;
+ /* This has been cached in btif. Just fetch it from there */
+ memcpy(bd_addr, &btif_local_bd_addr, sizeof(bt_bdaddr_t));
+ property->len = sizeof(bt_bdaddr_t);
+ return BT_STATUS_SUCCESS;
+ }
+ else if (property->type == BT_PROPERTY_ADAPTER_BONDED_DEVICES)
+ {
+ btif_bonded_devices_t bonded_devices;
+
+ btif_in_fetch_bonded_devices(&bonded_devices, 0);
+
+ BTIF_TRACE_DEBUG2("%s: Number of bonded devices: %d Property:BT_PROPERTY_ADAPTER_BONDED_DEVICES", __FUNCTION__, bonded_devices.num_devices);
+
+ if (bonded_devices.num_devices > 0)
+ {
+ property->len = bonded_devices.num_devices * sizeof(bt_bdaddr_t);
+ memcpy(property->val, bonded_devices.devices, property->len);
+ }
+
+ /* if there are no bonded_devices, then length shall be 0 */
+ return BT_STATUS_SUCCESS;
+ }
+ else if (property->type == BT_PROPERTY_UUIDS)
+ {
+ /* publish list of local supported services */
+ bt_uuid_t *p_uuid = (bt_uuid_t*)property->val;
+ uint32_t num_uuids = 0;
+ uint32_t i;
+
+ tBTA_SERVICE_MASK service_mask = btif_get_enabled_services_mask();
+ BTIF_TRACE_ERROR2("%s service_mask:0x%x", __FUNCTION__, service_mask);
+ for (i=0; i < BTA_MAX_SERVICE_ID; i++)
+ {
+ /* This should eventually become a function when more services are enabled */
+ if (service_mask
+ &(tBTA_SERVICE_MASK)(1 << i))
+ {
+ switch (i)
+ {
+ case BTA_HFP_SERVICE_ID:
+ {
+ uuid16_to_uuid128(UUID_SERVCLASS_AG_HANDSFREE,
+ p_uuid+num_uuids);
+ num_uuids++;
+ }
+ /* intentional fall through: Send both BFP & HSP UUIDs if HFP is enabled */
+ case BTA_HSP_SERVICE_ID:
+ {
+ uuid16_to_uuid128(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+ p_uuid+num_uuids);
+ num_uuids++;
+ }break;
+ case BTA_A2DP_SERVICE_ID:
+ {
+ uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SOURCE,
+ p_uuid+num_uuids);
+ num_uuids++;
+ }break;
+ }
+ }
+ }
+ property->len = (num_uuids)*sizeof(bt_uuid_t);
+ return BT_STATUS_SUCCESS;
+ }
+
+ /* fall through for other properties */
+ if(!cfg2prop(NULL, property))
+ {
+ return btif_dm_get_adapter_property(property);
+ }
+ return BT_STATUS_SUCCESS;
+ }
+
+/*******************************************************************************
+**
+** Function btif_storage_set_adapter_property
+**
+** Description BTIF storage API - Stores the adapter property
+** to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_set_adapter_property(bt_property_t *property)
+{
+ return prop2cfg(NULL, property) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_get_remote_device_property
+**
+** Description BTIF storage API - Fetches the remote device property->type
+** from NVRAM and fills property->val.
+** Caller should provide memory for property->val and
+** set the property->val
+**
+** Returns BT_STATUS_SUCCESS if the fetch was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_get_remote_device_property(bt_bdaddr_t *remote_bd_addr,
+ bt_property_t *property)
+{
+ return cfg2prop(remote_bd_addr, property) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+/*******************************************************************************
+**
+** Function btif_storage_set_remote_device_property
+**
+** Description BTIF storage API - Stores the remote device property
+** to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t *remote_bd_addr,
+ bt_property_t *property)
+{
+ return prop2cfg(remote_bd_addr, property) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_add_remote_device
+**
+** Description BTIF storage API - Adds a newly discovered device to NVRAM
+** along with the timestamp. Also, stores the various
+** properties - RSSI, BDADDR, NAME (if found in EIR)
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_remote_device(bt_bdaddr_t *remote_bdaddr,
+ uint32_t num_properties,
+ bt_property_t *properties)
+{
+ uint32_t i = 0;
+ /* TODO: If writing a property, fails do we go back undo the earlier
+ * written properties? */
+ for (i=0; i < num_properties; i++)
+ {
+ /* Ignore the RSSI as this is not stored in DB */
+ if (properties[i].type == BT_PROPERTY_REMOTE_RSSI)
+ continue;
+
+ /* BD_ADDR for remote device needs special handling as we also store timestamp */
+ if (properties[i].type == BT_PROPERTY_BDADDR)
+ {
+ bt_property_t addr_prop;
+ memcpy(&addr_prop, &properties[i], sizeof(bt_property_t));
+ addr_prop.type = BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP;
+ btif_storage_set_remote_device_property(remote_bdaddr,
+ &addr_prop);
+ }
+ else
+ {
+ btif_storage_set_remote_device_property(remote_bdaddr,
+ &properties[i]);
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_add_bonded_device
+**
+** Description BTIF storage API - Adds the newly bonded device to NVRAM
+** along with the link-key, Key type and Pin key length
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+
+bt_status_t btif_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr,
+ LINK_KEY link_key,
+ uint8_t key_type,
+ uint8_t pin_length)
+{
+ bdstr_t bdstr;
+ bd2str(remote_bd_addr, &bdstr);
+ int ret = btif_config_set_int("Remote", bdstr, "LinkKeyType", (int)key_type);
+ ret &= btif_config_set_int("Remote", bdstr, "PinLength", (int)pin_length);
+ ret &= btif_config_set("Remote", bdstr, "LinkKey", (const char*)link_key, sizeof(LINK_KEY), BTIF_CFG_TYPE_BIN);
+ btif_config_save();
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_remove_bonded_device
+**
+** Description BTIF storage API - Deletes the bonded device from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the deletion was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t *remote_bd_addr)
+{
+ bdstr_t bdstr;
+ bd2str(remote_bd_addr, &bdstr);
+ debug("in bd addr:%s", bdstr);
+ int ret = btif_config_remove("Remote", bdstr, "LinkKeyType");
+ ret &= btif_config_remove("Remote", bdstr, "PinLength");
+ ret &= btif_config_remove("Remote", bdstr, "LinkKey");
+ btif_config_save();
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_load_bonded_devices
+**
+** Description BTIF storage API - Loads all the bonded devices from NVRAM
+** and adds to the BTA.
+** Additionally, this API also invokes the adaper_properties_cb
+** and remote_device_properties_cb for each of the bonded devices.
+**
+** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_load_bonded_devices(void)
+{
+ char *fname;
+ btif_bonded_devices_t bonded_devices;
+ uint32_t i = 0;
+ bt_property_t adapter_props[6];
+ uint32_t num_props = 0;
+ bt_property_t remote_properties[8];
+ bt_bdaddr_t addr;
+ bt_bdname_t name, alias;
+ bt_scan_mode_t mode;
+ uint32_t disc_timeout;
+ bt_bdaddr_t *devices_list;
+ bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+ bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+ uint32_t cod, devtype;
+
+ btif_in_fetch_bonded_devices(&bonded_devices, 1);
+
+ /* Now send the adapter_properties_cb with all adapter_properties */
+ {
+ memset(adapter_props, 0, sizeof(adapter_props));
+
+ /* BD_ADDR */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_BDADDR, &addr, sizeof(addr),
+ adapter_props[num_props]);
+ num_props++;
+
+ /* BD_NAME */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_BDNAME, &name, sizeof(name),
+ adapter_props[num_props]);
+ num_props++;
+
+ /* SCAN_MODE */
+ /* TODO: At the time of BT on, always report the scan mode as 0 irrespective
+ of the scan_mode during the previous enable cycle.
+ This needs to be re-visited as part of the app/stack enable sequence
+ synchronization */
+ mode = BT_SCAN_MODE_NONE;
+ adapter_props[num_props].type = BT_PROPERTY_ADAPTER_SCAN_MODE;
+ adapter_props[num_props].len = sizeof(mode);
+ adapter_props[num_props].val = &mode;
+ num_props++;
+
+ /* DISC_TIMEOUT */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ &disc_timeout, sizeof(disc_timeout),
+ adapter_props[num_props]);
+ num_props++;
+
+ /* BONDED_DEVICES */
+ devices_list = (bt_bdaddr_t*)malloc(sizeof(bt_bdaddr_t)*bonded_devices.num_devices);
+ adapter_props[num_props].type = BT_PROPERTY_ADAPTER_BONDED_DEVICES;
+ adapter_props[num_props].len = bonded_devices.num_devices * sizeof(bt_bdaddr_t);
+ adapter_props[num_props].val = devices_list;
+ for (i=0; i < bonded_devices.num_devices; i++)
+ {
+ memcpy(devices_list + i, &bonded_devices.devices[i], sizeof(bt_bdaddr_t));
+ }
+ num_props++;
+
+ /* LOCAL UUIDs */
+ BTIF_STORAGE_GET_ADAPTER_PROP(BT_PROPERTY_UUIDS,
+ local_uuids, sizeof(local_uuids),
+ adapter_props[num_props]);
+ num_props++;
+
+ btif_adapter_properties_evt(BT_STATUS_SUCCESS, num_props, adapter_props);
+
+ free(devices_list);
+ }
+
+ BTIF_TRACE_EVENT2("%s: %d bonded devices found", __FUNCTION__, bonded_devices.num_devices);
+
+ {
+ for (i = 0; i < bonded_devices.num_devices; i++)
+ {
+ bt_bdaddr_t *p_remote_addr;
+
+ num_props = 0;
+ p_remote_addr = &bonded_devices.devices[i];
+ memset(remote_properties, 0, sizeof(remote_properties));
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_BDNAME,
+ &name, sizeof(name),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_REMOTE_FRIENDLY_NAME,
+ &alias, sizeof(alias),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_CLASS_OF_DEVICE,
+ &cod, sizeof(cod),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_TYPE_OF_DEVICE,
+ &devtype, sizeof(devtype),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_UUIDS,
+ remote_uuids, sizeof(remote_uuids),
+ remote_properties[num_props]);
+ num_props++;
+
+ btif_remote_properties_evt(BT_STATUS_SUCCESS, p_remote_addr,
+ num_props, remote_properties);
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_add_hid_device_info
+**
+** Description BTIF storage API - Adds the hid information of bonded hid devices-to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the store was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+
+bt_status_t btif_storage_add_hid_device_info(bt_bdaddr_t *remote_bd_addr,
+ UINT16 attr_mask, UINT8 sub_class,
+ UINT8 app_id, UINT16 vendor_id,
+ UINT16 product_id, UINT16 version,
+ UINT8 ctry_code, UINT16 dl_len, UINT8 *dsc_list)
+{
+ bdstr_t bdstr;
+ bd2str(remote_bd_addr, &bdstr);
+ btif_config_set_int("Remote", bdstr, "HidAttrMask", attr_mask);
+ btif_config_set_int("Remote", bdstr, "HidSubClass", sub_class);
+ btif_config_set_int("Remote", bdstr, "HidAppId", app_id);
+ btif_config_set_int("Remote", bdstr, "HidVendorId", vendor_id);
+ btif_config_set_int("Remote", bdstr, "HidProductId", product_id);
+ btif_config_set_int("Remote", bdstr, "HidVersion", version);
+ btif_config_set_int("Remote", bdstr, "HidCountryCode", ctry_code);
+ if(dl_len > 0)
+ btif_config_set("Remote", bdstr, "HidDescriptor", (const char*)dsc_list, dl_len, BTIF_CFG_TYPE_BIN);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_load_bonded_hid_info
+**
+** Description BTIF storage API - Loads hid info for all the bonded devices from NVRAM
+** and adds those devices to the BTA_HH.
+**
+** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_load_bonded_hid_info(void)
+{
+ debug("in");
+ bt_bdaddr_t bd_addr;
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+ uint32_t i;
+ uint16_t attr_mask;
+ uint8_t sub_class;
+ uint8_t app_id;
+
+ char kname[128], vname[128];
+ short kpos;
+ int kname_size;
+ kname_size = sizeof(kname);
+ kname[0] = 0;
+ kpos = 0;
+ memset(&dscp_info, 0, sizeof(dscp_info));
+ do
+ {
+ kpos = btif_config_next_key(kpos, "Remote", kname, &kname_size);
+ debug("Remote device:%s, size:%d", kname, kname_size);
+ int value;
+ if(btif_config_get_int("Remote", kname, "HidAttrMask", &value))
+ {
+ attr_mask = (uint16_t)value;
+
+ btif_config_get_int("Remote", kname, "HidSubClass", &value);
+ sub_class = (uint8_t)value;
+
+ btif_config_get_int("Remote", kname, "HidAppId", &value);
+ app_id = (uint8_t)value;
+
+ btif_config_get_int("Remote", kname, "HidVendorId", &value);
+ dscp_info.vendor_id = (uint16_t) value;
+
+ btif_config_get_int("Remote", kname, "HidProductId", &value);
+ dscp_info.product_id = (uint16_t) value;
+
+ btif_config_get_int("Remote", kname, "HidVersion", &value);
+ dscp_info.version = (uint8_t) value;
+
+ btif_config_get_int("Remote", kname, "HidCountryCode", &value);
+ dscp_info.ctry_code = (uint8_t) value;
+
+ int len = 0;
+ int type;
+ btif_config_get("Remote", kname, "HidDescriptor", NULL, &len, &type);
+ if(len > 0)
+ {
+ dscp_info.descriptor.dl_len = (uint16_t)len;
+ dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len);
+ btif_config_get("Remote", kname, "HidDescriptor", (char*)dscp_info.descriptor.dsc_list, &len, &type);
+ }
+ str2bd(kname, &bd_addr);
+ // add extracted information to BTA HH
+ if (btif_hh_add_added_dev(bd_addr,attr_mask))
+ {
+ BTA_HhAddDev(bd_addr.address, attr_mask, sub_class,
+ app_id, dscp_info);
+ }
+ }
+ } while(kpos != -1);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_remove_hid_info
+**
+** Description BTIF storage API - Deletes the bonded hid device info from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the deletion was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_remove_hid_info(bt_bdaddr_t *remote_bd_addr)
+{
+ char *fname;
+ int ret;
+ bdstr_t bdstr;
+ bd2str(remote_bd_addr, &bdstr);
+
+ btif_config_remove("Remote", bdstr, "HidAttrMask");
+ btif_config_remove("Remote", bdstr, "HidSubClass");
+ btif_config_remove("Remote", bdstr, "HidAppId");
+ btif_config_remove("Remote", bdstr, "HidVendorId");
+ btif_config_remove("Remote", bdstr, "HidProductId");
+ btif_config_remove("Remote", bdstr, "HidVersion");
+ btif_config_remove("Remote", bdstr, "HidCountryCode");
+ btif_config_remove("Remote", bdstr, "HidDescriptor");
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_read_hl_apps_cb
+**
+** Description BTIF storage API - Read HL application control block from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_read_hl_apps_cb(char *value, int value_size)
+{
+ bt_status_t bt_status = BT_STATUS_SUCCESS;
+ int read_size=value_size, read_type=BTIF_CFG_TYPE_BIN;
+
+ if (!btif_config_exist("Local", BTIF_STORAGE_HL_APP, BTIF_STORAGE_HL_APP_CB))
+ {
+ memset(value, value_size, 0);
+ if (!btif_config_set("Local", BTIF_STORAGE_HL_APP,BTIF_STORAGE_HL_APP_CB,
+ value, value_size, BTIF_CFG_TYPE_BIN))
+ {
+ bt_status = BT_STATUS_FAIL;
+ }
+ else
+ {
+ btif_config_save();
+ }
+ }
+ else
+ {
+ if (!btif_config_get("Local", BTIF_STORAGE_HL_APP, BTIF_STORAGE_HL_APP_CB,
+ value, &read_size, &read_type))
+ {
+ bt_status = BT_STATUS_FAIL;
+ }
+ else
+ {
+ if ((read_size != value_size) || (read_type != BTIF_CFG_TYPE_BIN) )
+ {
+ BTIF_TRACE_ERROR4("%s value_size=%d read_size=%d read_type=%d",
+ __FUNCTION__, value_size, read_size, read_type);
+ bt_status = BT_STATUS_FAIL;
+ }
+ }
+
+ }
+
+ BTIF_TRACE_DEBUG3("%s status=%d value_size=%d", __FUNCTION__, bt_status, value_size);
+ return bt_status;
+}
+
+
+/*******************************************************************************
+**
+** Function btif_storage_write_hl_apps_cb
+**
+** Description BTIF storage API - Write HL application control block to NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_write_hl_apps_cb(char *value, int value_size)
+{
+ bt_status_t bt_status = BT_STATUS_SUCCESS;
+
+ if (!btif_config_set("Local", BTIF_STORAGE_HL_APP, BTIF_STORAGE_HL_APP_CB,
+ value, value_size, BTIF_CFG_TYPE_BIN))
+ {
+ bt_status = BT_STATUS_FAIL;
+ }
+ else
+ {
+ btif_config_save();
+ }
+ BTIF_TRACE_DEBUG3("%s status=%d value_size=%d", __FUNCTION__, bt_status, value_size);
+
+ return bt_status;
+}
+
+bt_status_t btif_storage_read_hl_data(char *fname, char *value, int value_size)
+{
+ bt_status_t bt_status = BT_STATUS_SUCCESS;
+ int read_size=value_size, read_type=BTIF_CFG_TYPE_BIN;
+
+ if (!btif_config_get("Local", BTIF_STORAGE_HL_APP, fname, value, &read_size, &read_type))
+ {
+ bt_status = BT_STATUS_FAIL;
+ }
+ else
+ {
+ if ((read_size != value_size) || (read_type != BTIF_CFG_TYPE_BIN) )
+ {
+ BTIF_TRACE_ERROR4("%s value_size=%d read_size=%d read_type=%d",
+ __FUNCTION__, value_size, read_size, read_type);
+ bt_status = BT_STATUS_FAIL;
+ }
+ }
+
+ return bt_status;
+}
+
+bt_status_t btif_storage_write_hl_data(char *fname, char *value, int value_size)
+{
+ bt_status_t bt_status = BT_STATUS_SUCCESS;
+
+ if (!btif_config_set("Local", BTIF_STORAGE_HL_APP, fname, value, value_size, BTIF_CFG_TYPE_BIN))
+ {
+ bt_status = BT_STATUS_FAIL;
+ }
+ else
+ {
+ btif_config_save();
+ }
+ BTIF_TRACE_DEBUG3("%s status=%d value_size=%d", __FUNCTION__, bt_status, value_size);
+
+ return bt_status;
+
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_read_hl_app_data
+**
+** Description BTIF storage API - Read HL application configuration from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_read_hl_app_data(UINT8 app_idx, char *value, int value_size)
+{
+ char fname[256];
+ bt_status_t bt_status = BT_STATUS_SUCCESS;
+
+ BTIF_TRACE_DEBUG1("%s ", __FUNCTION__);
+ sprintf(fname, "%s%d", BTIF_STORAGE_HL_APP_DATA, app_idx);
+ bt_status = btif_storage_read_hl_data(fname, value, value_size);
+ BTIF_TRACE_DEBUG3("%s read item:(%s) bt_status=%d", __FUNCTION__, fname, bt_status);
+
+ return bt_status;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_write_hl_app_data
+**
+** Description BTIF storage API - Write HL application MDL configuration from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_write_hl_app_data(UINT8 app_idx, char *value, int value_size)
+{
+ char fname[256];
+ bt_status_t bt_status = BT_STATUS_SUCCESS;
+
+
+ BTIF_TRACE_DEBUG1("%s ", __FUNCTION__);
+ sprintf(fname, "%s%d", BTIF_STORAGE_HL_APP_DATA, app_idx);
+ bt_status = btif_storage_write_hl_data(fname, value, value_size);
+ BTIF_TRACE_DEBUG3("%s write item:(%s) bt_status=%d", __FUNCTION__, fname, bt_status);
+
+ return bt_status;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_read_hl_mdl_data
+**
+** Description BTIF storage API - Read HL application MDL configuration from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_read_hl_mdl_data(UINT8 app_idx, char *value, int value_size)
+{
+ char fname[256], tmp[3];
+ bt_status_t bt_status = BT_STATUS_SUCCESS;
+ int status, i, buf_size;
+ char *p_buf;
+
+ BTIF_TRACE_DEBUG1("%s ", __FUNCTION__);
+ sprintf(fname, "%s%d", BTIF_STORAGE_HL_APP_MDL_DATA, app_idx);
+ bt_status = btif_storage_read_hl_data(fname, value, value_size);
+ BTIF_TRACE_DEBUG3("%s read item:(%s) bt_status=%d", __FUNCTION__, fname, bt_status);
+
+ return bt_status;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_write_hl_mdl_data
+**
+** Description BTIF storage API - Write HL application MDL configuration from NVRAM
+**
+** Returns BT_STATUS_SUCCESS if the operation was successful,
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_write_hl_mdl_data(UINT8 app_idx, char *value, int value_size)
+{
+ char fname[256];
+ bt_status_t bt_status = BT_STATUS_SUCCESS;
+ int status, i, buf_size;
+ char *p_buf;
+
+ BTIF_TRACE_DEBUG1("%s ", __FUNCTION__);
+ sprintf(fname, "%s%d", BTIF_STORAGE_HL_APP_MDL_DATA, app_idx);
+ bt_status = btif_storage_write_hl_data(fname, value, value_size);
+ BTIF_TRACE_DEBUG3("%s write item:(%s) bt_status=%d", __FUNCTION__, fname, bt_status);
+
+ return bt_status;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_load_autopair_device_list
+**
+** Description BTIF storage API - Populates auto pair device list
+**
+** Returns BT_STATUS_SUCCESS if the auto pair blacklist is successfully populated
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+
+bt_status_t btif_storage_load_autopair_device_list()
+{
+ char *key_name, *key_value;
+ int i=0;
+ char linebuf[BTIF_STORAGE_MAX_LINE_SZ];
+ char *line;
+ FILE *fp;
+
+ if(!btif_config_exist("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST, NULL))
+ {
+ /* first time loading of auto pair blacklist configuration */
+
+ fp = fopen (BTIF_AUTO_PAIR_CONF_FILE, "r");
+
+ if (fp == NULL)
+ {
+ ALOGE("%s: Failed to open auto pair blacklist conf file at %s", __FUNCTION__,BTIF_AUTO_PAIR_CONF_FILE );
+ return BT_STATUS_FAIL;
+ }
+
+ /* read through auto_pairing.conf file and create the key value pairs specific to auto pair blacklist devices */
+ while (fgets(linebuf, BTIF_STORAGE_MAX_LINE_SZ, fp) != NULL)
+ {
+ /* trip leading white spaces */
+ while (linebuf[i] == BTIF_AUTO_PAIR_CONF_SPACE)
+ i++;
+
+ /* skip commented lines */
+ if (linebuf[i] == BTIF_AUTO_PAIR_CONF_COMMENT)
+ continue;
+
+ line = (char*)&(linebuf[i]);
+
+ if (line == NULL)
+ continue;
+
+ key_name = strtok(line, BTIF_AUTO_PAIR_CONF_KEY_VAL_DELIMETER);
+
+ if (key_name == NULL)
+ continue;
+ else if((strcmp(key_name, BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_ADDR) == 0) ||
+ (strcmp(key_name, BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_EXACTNAME) ==0) ||
+ (strcmp(key_name, BTIF_STORAGE_KEY_AUTOPAIR_FIXPIN_KBLIST) ==0 ) ||
+ (strcmp(key_name, BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_PARTIALNAME) == 0) ||
+ (strcmp(key_name, BTIF_STORAGE_KEY_AUTOPAIR_DYNAMIC_BLACKLIST_ADDR) == 0))
+ {
+ key_value = strtok(NULL, BTIF_AUTO_PAIR_CONF_KEY_VAL_DELIMETER);
+ btif_config_set_str("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST, key_name, key_value);
+ }
+ }
+ fclose(fp);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_is_device_autopair_blacklisted
+**
+** Description BTIF storage API Checks if the given device is blacklisted for auto pairing
+**
+** Returns TRUE if the device is found in the auto pair blacklist
+** FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btif_storage_is_device_autopair_blacklisted(bt_bdaddr_t *remote_dev_addr)
+{
+ char *token;
+ int ret;
+ bdstr_t bdstr;
+ char *dev_name_str;
+ uint8_t i = 0;
+ char value[BTIF_STORAGE_MAX_LINE_SZ];
+ int value_size = sizeof(value);
+
+ bd2str(remote_dev_addr, &bdstr);
+
+ /* Consider only Lower Address Part from BD Address */
+ bdstr[8] = '\0';
+
+ if(btif_config_get_str("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST,
+ BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_ADDR, value, &value_size))
+ {
+ if (strcasestr(value,bdstr) != NULL)
+ return TRUE;
+ }
+
+ dev_name_str = BTM_SecReadDevName((remote_dev_addr->address));
+
+ if (dev_name_str != NULL)
+ {
+ value_size = sizeof(value);
+ if(btif_config_get_str("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST,
+ BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_EXACTNAME, value, &value_size))
+ {
+ if (strstr(value,dev_name_str) != NULL)
+ return TRUE;
+ }
+ value_size = sizeof(value);
+ if(btif_config_get_str("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST,
+ BTIF_STORAGE_KEY_AUTOPAIR_BLACKLIST_PARTIALNAME, value, &value_size))
+ {
+ token = strtok(value, BTIF_AUTO_PAIR_CONF_VALUE_SEPARATOR);
+ while (token != NULL)
+ {
+ if (strstr(dev_name_str, token) != NULL)
+ return TRUE;
+
+ token = strtok(NULL, BTIF_AUTO_PAIR_CONF_VALUE_SEPARATOR);
+ }
+ }
+ }
+ if(btif_config_get_str("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST,
+ BTIF_STORAGE_KEY_AUTOPAIR_DYNAMIC_BLACKLIST_ADDR, value, &value_size))
+ {
+ if (strstr(value,bdstr) != NULL)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_add_device_to_autopair_blacklist
+**
+** Description BTIF storage API - Add a remote device to the auto pairing blacklist
+**
+** Returns BT_STATUS_SUCCESS if the device is successfully added to the auto pair blacklist
+** BT_STATUS_FAIL otherwise
+**
+*******************************************************************************/
+bt_status_t btif_storage_add_device_to_autopair_blacklist(bt_bdaddr_t *remote_dev_addr)
+{
+ int ret;
+ bdstr_t bdstr;
+ char linebuf[BTIF_STORAGE_MAX_LINE_SZ+20];
+ char input_value [20];
+
+ bd2str(remote_dev_addr, &bdstr);
+ strncpy(input_value, (char*)bdstr, 20);
+ strncat(input_value,BTIF_AUTO_PAIR_CONF_VALUE_SEPARATOR, 20);
+ int line_size = sizeof(linebuf);
+ if(btif_config_get_str("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST,
+ BTIF_STORAGE_KEY_AUTOPAIR_DYNAMIC_BLACKLIST_ADDR, linebuf, &line_size))
+ {
+ /* Append this address to the dynamic List of BD address */
+ strncat (linebuf, input_value, BTIF_STORAGE_MAX_LINE_SZ);
+ }
+ else
+ {
+ strncpy( linebuf,input_value, BTIF_STORAGE_MAX_LINE_SZ);
+ }
+
+ /* Write back the key value */
+ ret = btif_config_set_str("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST,
+ BTIF_STORAGE_KEY_AUTOPAIR_DYNAMIC_BLACKLIST_ADDR, linebuf);
+
+ return ret ? BT_STATUS_SUCCESS:BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+**
+** Function btif_storage_is_fixed_pin_zeros_keyboard
+**
+** Description BTIF storage API - checks if this device has fixed PIN key device list
+**
+** Returns TRUE if the device is found in the fixed pin keyboard device list
+** FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btif_storage_is_fixed_pin_zeros_keyboard(bt_bdaddr_t *remote_dev_addr)
+{
+ int ret;
+ bdstr_t bdstr;
+ char *dev_name_str;
+ uint8_t i = 0;
+ char linebuf[BTIF_STORAGE_MAX_LINE_SZ];
+
+ bd2str(remote_dev_addr, &bdstr);
+
+ /*consider on LAP part of BDA string*/
+ bdstr[8] = '\0';
+
+ int line_size = sizeof(linebuf);
+ if(btif_config_get_str("Local", BTIF_STORAGE_PATH_AUTOPAIR_BLACKLIST,
+ BTIF_STORAGE_KEY_AUTOPAIR_FIXPIN_KBLIST, linebuf, &line_size))
+ {
+ if (strcasestr(linebuf,bdstr) != NULL)
+ return TRUE;
+ }
+ return FALSE;
+
+}
diff --git a/btif/src/btif_util.c b/btif/src/btif_util.c
new file mode 100644
index 0000000..5539c11
--- /dev/null
+++ b/btif/src/btif_util.c
@@ -0,0 +1,462 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-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.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_util.c
+ *
+ * Description: Miscellaneous helper functions
+ *
+ *
+ ***********************************************************************************/
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <hardware/bt_av.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+
+#define LOG_TAG "BTIF_UTIL"
+#include "btif_common.h"
+#include "bta_api.h"
+#include "gki.h"
+#include "btu.h"
+#include "bte.h"
+#include "bd.h"
+#include "btif_dm.h"
+#include "btif_util.h"
+#include "bta_ag_api.h"
+#include "bta_hh_api.h"
+
+
+
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+#define ISDIGIT(a) ((a>='0') && (a<='9'))
+#define ISXDIGIT(a) (((a>='0') && (a<='9'))||((a>='A') && (a<='F'))||((a>='a') && (a<='f')))
+
+/************************************************************************************
+** Local type definitions
+************************************************************************************/
+
+/************************************************************************************
+** Static variables
+************************************************************************************/
+
+/************************************************************************************
+** Static functions
+************************************************************************************/
+
+/************************************************************************************
+** Externs
+************************************************************************************/
+
+/************************************************************************************
+** Functions
+************************************************************************************/
+
+/*****************************************************************************
+** Logging helper functions
+*****************************************************************************/
+
+int str2bd(char *str, bt_bdaddr_t *addr)
+{
+ int32_t i = 0;
+ for (i = 0; i < 6; i++) {
+ addr->address[i] = (uint8_t) strtoul(str, (char **)&str, 16);
+ str++;
+ }
+ return 0;
+}
+
+char *bd2str(bt_bdaddr_t *bdaddr, bdstr_t *bdstr)
+{
+ char *addr = (char *) bdaddr->address;
+
+ sprintf((char*)bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (int)addr[0],(int)addr[1],(int)addr[2],
+ (int)addr[3],(int)addr[4],(int)addr[5]);
+ return (char *)bdstr;
+}
+
+UINT32 devclass2uint(DEV_CLASS dev_class)
+{
+ UINT32 cod = 0;
+
+ /* if COD is 0, irrespective of the device type set it to Unclassified device */
+ cod = (dev_class[2]) | (dev_class[1] << 8) | (dev_class[0] << 16);
+
+ return cod;
+}
+void uint2devclass(UINT32 cod, DEV_CLASS dev_class)
+{
+ dev_class[2] = (UINT8)cod;
+ dev_class[1] = (UINT8)(cod >> 8);
+ dev_class[0] = (UINT8)(cod >> 16);
+}
+
+static const UINT8 sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+
+void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128)
+{
+ uint16_t uuid16_bo;
+ memset(uuid128, 0, sizeof(bt_uuid_t));
+
+ memcpy(uuid128->uu, sdp_base_uuid, MAX_UUID_SIZE);
+ uuid16_bo = ntohs(uuid16);
+ memcpy(uuid128->uu + 2, &uuid16_bo, sizeof(uint16_t));
+}
+
+void string_to_uuid(char *str, bt_uuid_t *p_uuid)
+{
+ uint32_t uuid0, uuid4;
+ uint16_t uuid1, uuid2, uuid3, uuid5;
+
+ sscanf(str, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
+ &uuid0, &uuid1, &uuid2, &uuid3, &uuid4, &uuid5);
+
+ uuid0 = htonl(uuid0);
+ uuid1 = htons(uuid1);
+ uuid2 = htons(uuid2);
+ uuid3 = htons(uuid3);
+ uuid4 = htonl(uuid4);
+ uuid5 = htons(uuid5);
+
+ memcpy(&(p_uuid->uu[0]), &uuid0, 4);
+ memcpy(&(p_uuid->uu[4]), &uuid1, 2);
+ memcpy(&(p_uuid->uu[6]), &uuid2, 2);
+ memcpy(&(p_uuid->uu[8]), &uuid3, 2);
+ memcpy(&(p_uuid->uu[10]), &uuid4, 4);
+ memcpy(&(p_uuid->uu[14]), &uuid5, 2);
+
+ return;
+
+}
+
+void uuid_to_string(bt_uuid_t *p_uuid, char *str)
+{
+ uint32_t uuid0, uuid4;
+ uint16_t uuid1, uuid2, uuid3, uuid5;
+
+ memcpy(&uuid0, &(p_uuid->uu[0]), 4);
+ memcpy(&uuid1, &(p_uuid->uu[4]), 2);
+ memcpy(&uuid2, &(p_uuid->uu[6]), 2);
+ memcpy(&uuid3, &(p_uuid->uu[8]), 2);
+ memcpy(&uuid4, &(p_uuid->uu[10]), 4);
+ memcpy(&uuid5, &(p_uuid->uu[14]), 2);
+
+ sprintf((char *)str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
+ ntohl(uuid0), ntohs(uuid1),
+ ntohs(uuid2), ntohs(uuid3),
+ ntohl(uuid4), ntohs(uuid5));
+ return;
+}
+
+/*****************************************************************************
+** Function ascii_2_hex
+**
+** Description This function converts an ASCII string into HEX
+**
+** Returns the number of hex bytes filled.
+*/
+int ascii_2_hex (char *p_ascii, int len, UINT8 *p_hex)
+{
+ int x;
+ UINT8 c;
+
+ for (x = 0; (x < len) && (*p_ascii); x++)
+ {
+ if (ISDIGIT (*p_ascii))
+ c = (*p_ascii - '0') << 4;
+ else
+ c = (toupper(*p_ascii) - 'A' + 10) << 4;
+
+ p_ascii++;
+ if (*p_ascii)
+ {
+ if (ISDIGIT (*p_ascii))
+ c |= (*p_ascii - '0');
+ else
+ c |= (toupper(*p_ascii) - 'A' + 10);
+
+ p_ascii++;
+ }
+ *p_hex++ = c;
+ }
+
+ return (x);
+}
+
+
+const char* dump_dm_search_event(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTA_DM_INQ_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_INQ_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_BLE_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_DI_DISC_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_SEARCH_CANCEL_CMPL_EVT)
+
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+
+const char* dump_property_type(bt_property_type_t type)
+{
+ switch(type)
+ {
+ CASE_RETURN_STR(BT_PROPERTY_BDNAME)
+ CASE_RETURN_STR(BT_PROPERTY_BDADDR)
+ CASE_RETURN_STR(BT_PROPERTY_UUIDS)
+ CASE_RETURN_STR(BT_PROPERTY_CLASS_OF_DEVICE)
+ CASE_RETURN_STR(BT_PROPERTY_TYPE_OF_DEVICE)
+ CASE_RETURN_STR(BT_PROPERTY_REMOTE_RSSI)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_BONDED_DEVICES)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_SCAN_MODE)
+ CASE_RETURN_STR(BT_PROPERTY_REMOTE_FRIENDLY_NAME)
+
+ default:
+ return "UNKNOWN PROPERTY ID";
+ }
+}
+
+const char* dump_dm_event(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTA_DM_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_DM_DISABLE_EVT)
+ CASE_RETURN_STR(BTA_DM_PIN_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_AUTH_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_AUTHORIZE_EVT)
+ CASE_RETURN_STR(BTA_DM_LINK_UP_EVT)
+ CASE_RETURN_STR(BTA_DM_LINK_DOWN_EVT)
+ CASE_RETURN_STR(BTA_DM_SIG_STRENGTH_EVT)
+ CASE_RETURN_STR(BTA_DM_BUSY_LEVEL_EVT)
+ CASE_RETURN_STR(BTA_DM_BOND_CANCEL_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_SP_CFM_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_SP_KEY_NOTIF_EVT)
+ CASE_RETURN_STR(BTA_DM_SP_RMT_OOB_EVT)
+ CASE_RETURN_STR(BTA_DM_SP_KEYPRESS_EVT)
+ CASE_RETURN_STR(BTA_DM_ROLE_CHG_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_KEY_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_SEC_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_PASSKEY_NOTIF_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_PASSKEY_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_OOB_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_LOCAL_IR_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_LOCAL_ER_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_AUTH_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_DEV_UNPAIRED_EVT)
+ CASE_RETURN_STR(BTA_DM_HW_ERROR_EVT)
+
+ default:
+ return "UNKNOWN DM EVENT";
+ }
+}
+
+const char* dump_hf_event(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTA_AG_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_AG_REGISTER_EVT)
+ CASE_RETURN_STR(BTA_AG_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AG_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AG_CONN_EVT)
+ CASE_RETURN_STR(BTA_AG_AUDIO_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AG_AUDIO_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AG_SPK_EVT)
+ CASE_RETURN_STR(BTA_AG_MIC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CKPD_EVT)
+ CASE_RETURN_STR(BTA_AG_DISABLE_EVT)
+
+ CASE_RETURN_STR(BTA_AG_AT_A_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_D_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CHLD_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CHUP_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CIND_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_VTS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BINP_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BLDN_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BVRA_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_NREC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CNUM_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BTRH_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CLCC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_COPS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_UNAT_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CBC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BAC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BCS_EVT)
+
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hh_event(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTA_HH_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_HH_DISABLE_EVT)
+ CASE_RETURN_STR(BTA_HH_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HH_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HH_GET_DSCP_EVT)
+ CASE_RETURN_STR(BTA_HH_GET_PROTO_EVT)
+ CASE_RETURN_STR(BTA_HH_GET_RPT_EVT)
+ CASE_RETURN_STR(BTA_HH_GET_IDLE_EVT)
+ CASE_RETURN_STR(BTA_HH_SET_PROTO_EVT)
+ CASE_RETURN_STR(BTA_HH_SET_RPT_EVT)
+ CASE_RETURN_STR(BTA_HH_SET_IDLE_EVT)
+ CASE_RETURN_STR(BTA_HH_VC_UNPLUG_EVT)
+ CASE_RETURN_STR(BTA_HH_ADD_DEV_EVT)
+ CASE_RETURN_STR(BTA_HH_RMV_DEV_EVT)
+ CASE_RETURN_STR(BTA_HH_API_ERR_EVT)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+
+const char* dump_hf_conn_state(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTED)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTING)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTED)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_SLC_CONNECTED)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hf_call_state(bthf_call_state_t call_state)
+{
+ switch(call_state)
+ {
+ CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
+ CASE_RETURN_STR(BTHF_CALL_STATE_HELD)
+ CASE_RETURN_STR(BTHF_CALL_STATE_DIALING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_ALERTING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_INCOMING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_WAITING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_ACTIVE)
+ default:
+ return "UNKNOWN CALL STATE";
+ }
+}
+
+const char* dump_thread_evt(bt_cb_thread_evt evt)
+{
+ switch(evt)
+ {
+ CASE_RETURN_STR(ASSOCIATE_JVM)
+ CASE_RETURN_STR(DISASSOCIATE_JVM)
+
+ default:
+ return "unknown thread evt";
+ }
+}
+
+
+const char* dump_hf_audio_state(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTED)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTING)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTED)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+
+ }
+}
+
+const char* dump_av_conn_state(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTAV_CONNECTION_STATE_DISCONNECTED)
+ CASE_RETURN_STR(BTAV_CONNECTION_STATE_CONNECTING)
+ CASE_RETURN_STR(BTAV_CONNECTION_STATE_CONNECTED)
+ CASE_RETURN_STR(BTAV_CONNECTION_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_av_audio_state(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTAV_AUDIO_STATE_REMOTE_SUSPEND)
+ CASE_RETURN_STR(BTAV_AUDIO_STATE_STOPPED)
+ CASE_RETURN_STR(BTAV_AUDIO_STATE_STARTED)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_adapter_scan_mode(bt_scan_mode_t mode)
+{
+ switch(mode)
+ {
+ CASE_RETURN_STR(BT_SCAN_MODE_NONE)
+ CASE_RETURN_STR(BT_SCAN_MODE_CONNECTABLE)
+ CASE_RETURN_STR(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE)
+
+ default:
+ return "unknown scan mode";
+ }
+}
+
+const char* dump_bt_status(bt_status_t status)
+{
+ switch(status)
+ {
+ CASE_RETURN_STR(BT_STATUS_SUCCESS)
+ CASE_RETURN_STR(BT_STATUS_FAIL)
+ CASE_RETURN_STR(BT_STATUS_NOT_READY)
+ CASE_RETURN_STR(BT_STATUS_NOMEM)
+ CASE_RETURN_STR(BT_STATUS_BUSY)
+ CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+
+ default:
+ return "unknown scan mode";
+ }
+}
+
+
+