From 5738f83aeb59361a0a2eda2460113f6dc9194271 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 12 Dec 2012 16:00:35 -0800 Subject: Snapshot cdeccf6fdd8c2d494ea2867cb37a025bf8879baf Change-Id: Ia2de32ccb97a9641462c72363b0a8c4288f4f36d --- btif/co/bta_ag_co.c | 132 + btif/co/bta_av_co.c | 1504 +++++++++++ btif/co/bta_dm_co.c | 417 +++ btif/co/bta_fs_co.c | 1181 +++++++++ btif/co/bta_hh_co.c | 276 ++ btif/co/bta_hl_co.c | 459 ++++ btif/co/bta_pan_co.c | 334 +++ btif/co/bta_sys_co.c | 57 + btif/include/btif_api.h | 328 +++ btif/include/btif_av.h | 116 + btif/include/btif_av_api.h | 210 ++ btif/include/btif_av_co.h | 173 ++ btif/include/btif_common.h | 183 ++ btif/include/btif_config.h | 77 + btif/include/btif_config_util.h | 62 + btif/include/btif_dm.h | 49 + btif/include/btif_hh.h | 102 + btif/include/btif_hl.h | 366 +++ btif/include/btif_media.h | 248 ++ btif/include/btif_pan.h | 36 + btif/include/btif_pan_internal.h | 118 + btif/include/btif_profile_queue.h | 37 + btif/include/btif_sm.h | 118 + btif/include/btif_sock.h | 36 + btif/include/btif_sock_rfc.h | 38 + btif/include/btif_sock_sdp.h | 39 + btif/include/btif_sock_thread.h | 49 + btif/include/btif_sock_util.h | 65 + btif/include/btif_storage.h | 313 +++ btif/include/btif_util.h | 73 + btif/include/uinput.h | 590 +++++ btif/src/bluetooth.c | 413 +++ btif/src/btif_av.c | 970 +++++++ btif/src/btif_config.c | 744 ++++++ btif/src/btif_config_util.cpp | 674 +++++ btif/src/btif_core.c | 1431 ++++++++++ btif/src/btif_dm.c | 1876 +++++++++++++ btif/src/btif_hf.c | 1200 +++++++++ btif/src/btif_hh.c | 1630 ++++++++++++ btif/src/btif_hl.c | 5224 +++++++++++++++++++++++++++++++++++++ btif/src/btif_media_task.c | 2287 ++++++++++++++++ btif/src/btif_pan.c | 668 +++++ btif/src/btif_profile_queue.c | 187 ++ btif/src/btif_rc.c | 492 ++++ btif/src/btif_sm.c | 205 ++ btif/src/btif_sock.c | 182 ++ btif/src/btif_sock_rfc.c | 985 +++++++ btif/src/btif_sock_sdp.c | 443 ++++ btif/src/btif_sock_thread.c | 593 +++++ btif/src/btif_sock_util.c | 266 ++ btif/src/btif_storage.c | 1410 ++++++++++ btif/src/btif_util.c | 462 ++++ 52 files changed, 30128 insertions(+) create mode 100644 btif/co/bta_ag_co.c create mode 100644 btif/co/bta_av_co.c create mode 100644 btif/co/bta_dm_co.c create mode 100644 btif/co/bta_fs_co.c create mode 100644 btif/co/bta_hh_co.c create mode 100644 btif/co/bta_hl_co.c create mode 100644 btif/co/bta_pan_co.c create mode 100644 btif/co/bta_sys_co.c create mode 100644 btif/include/btif_api.h create mode 100644 btif/include/btif_av.h create mode 100644 btif/include/btif_av_api.h create mode 100644 btif/include/btif_av_co.h create mode 100644 btif/include/btif_common.h create mode 100644 btif/include/btif_config.h create mode 100644 btif/include/btif_config_util.h create mode 100644 btif/include/btif_dm.h create mode 100644 btif/include/btif_hh.h create mode 100644 btif/include/btif_hl.h create mode 100644 btif/include/btif_media.h create mode 100644 btif/include/btif_pan.h create mode 100644 btif/include/btif_pan_internal.h create mode 100644 btif/include/btif_profile_queue.h create mode 100644 btif/include/btif_sm.h create mode 100644 btif/include/btif_sock.h create mode 100644 btif/include/btif_sock_rfc.h create mode 100644 btif/include/btif_sock_sdp.h create mode 100644 btif/include/btif_sock_thread.h create mode 100644 btif/include/btif_sock_util.h create mode 100644 btif/include/btif_storage.h create mode 100644 btif/include/btif_util.h create mode 100644 btif/include/uinput.h create mode 100644 btif/src/bluetooth.c create mode 100755 btif/src/btif_av.c create mode 100644 btif/src/btif_config.c create mode 100644 btif/src/btif_config_util.cpp create mode 100755 btif/src/btif_core.c create mode 100755 btif/src/btif_dm.c create mode 100755 btif/src/btif_hf.c create mode 100644 btif/src/btif_hh.c create mode 100644 btif/src/btif_hl.c create mode 100755 btif/src/btif_media_task.c create mode 100644 btif/src/btif_pan.c create mode 100644 btif/src/btif_profile_queue.c create mode 100644 btif/src/btif_rc.c create mode 100644 btif/src/btif_sm.c create mode 100644 btif/src/btif_sock.c create mode 100644 btif/src/btif_sock_rfc.c create mode 100644 btif/src/btif_sock_sdp.c create mode 100644 btif/src/btif_sock_thread.c create mode 100644 btif/src/btif_sock_util.c create mode 100755 btif/src/btif_storage.c create mode 100644 btif/src/btif_util.c (limited to 'btif') 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 +#include +#else +#include +#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 +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gki.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" +#include + +#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 +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; iactive) + { + 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 +#include +#include "btif_pan_internal.h" +#include "bd.h" + + +#include +#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 + +/******************************************************************************* +** 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 +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 +#include +#include +#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 + +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 + +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 + +/******************************************************************************* +** 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 +#include + +/******************************************************************************* +** 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 + +/******************************************************************************* +** 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 +#include +#include + +#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 +#include +#include + +/******************************************************************************* +** 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "btif_config.c" + +#include +#include "btif_config.h" +#include "btif_config_util.h" +#include "btif_sock_thread.h" +#include "btif_sock_util.h" + +#include +#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 = §ion_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 = §ion_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 = §ion_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 = §ion_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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< +#include +#include + +#include + +#include +#include +#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 +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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; isdp.sdp_rec[i].num_mdeps; + for (j=0; jfilter.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; imcb[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;iapp_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; isdp_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; imdl_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, ®_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, ®_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; imdl_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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#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(ð_hdr.h_dest, local_addr, ETH_ADDR_LEN); + //else + memcpy(ð_hdr.h_dest, dst, ETH_ADDR_LEN); + memcpy(ð_hdr.h_src, src, ETH_ADDR_LEN); + eth_hdr.h_proto = htons(proto); + char packet[2000]; + memcpy(packet, ð_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(ð_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(ð_hdr)) + { + forward_bnep(ð_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 + +#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 +#include +#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 + +#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 +#include + +#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 +#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 +#include +#include +#include +#include +#include + +#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 +#include +#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 +#include +#include +#include +#include + +#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 + +#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 +#include + +//bta_jv_co_rfc_data +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#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 + +#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 +#include +#include +#include +#include + + +#include +#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 +#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> LIST< <36 char uuid> <;> > */ +#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> LIST > + > + > */ +#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 +#include +#include +#include +#include +#include +#include +#include + + +#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"; + } +} + + + -- cgit v1.1