diff options
Diffstat (limited to 'btif/co')
-rw-r--r-- | btif/co/bta_ag_co.c | 132 | ||||
-rw-r--r-- | btif/co/bta_av_co.c | 1504 | ||||
-rw-r--r-- | btif/co/bta_dm_co.c | 417 | ||||
-rw-r--r-- | btif/co/bta_fs_co.c | 1181 | ||||
-rw-r--r-- | btif/co/bta_hh_co.c | 276 | ||||
-rw-r--r-- | btif/co/bta_hl_co.c | 459 | ||||
-rw-r--r-- | btif/co/bta_pan_co.c | 334 | ||||
-rw-r--r-- | btif/co/bta_sys_co.c | 57 |
8 files changed, 4360 insertions, 0 deletions
diff --git a/btif/co/bta_ag_co.c b/btif/co/bta_ag_co.c new file mode 100644 index 0000000..cd969f8 --- /dev/null +++ b/btif/co/bta_ag_co.c @@ -0,0 +1,132 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include "gki.h" +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_ag_api.h" +#include "bta_ag_co.h" +#include "bte_appl.h" + +#define LOG_TAG "BTA_AG_CO: " + +#ifndef LINUX_NATIVE +#include <cutils/properties.h> +#include <cutils/log.h> +#else +#include <stdio.h> +#define LOGI(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__) +#define LOGD(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__) +#define LOGV(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__) +#define LOGE(format, ...) fprintf (stderr, LOG_TAG format"\n", ## __VA_ARGS__) +#endif + + +/******************************************************************************* +** +** Function bta_ag_co_init +** +** Description This callout function is executed by AG when it is +** started by calling BTA_AgEnable(). This function can be +** used by the phone to initialize audio paths or for other +** initialization purposes. +** +** +** Returns Void. +** +*******************************************************************************/ +void bta_ag_co_init(void) +{ + BTM_WriteVoiceSettings(AG_VOICE_SETTINGS); +} + + +/******************************************************************************* +** +** Function bta_ag_co_audio_state +** +** Description This function is called by the AG before the audio connection +** is brought up, after it comes up, and after it goes down. +** +** Parameters handle - handle of the AG instance +** state - Audio state +** BTA_AG_CO_AUD_STATE_OFF - Audio has been turned off +** BTA_AG_CO_AUD_STATE_OFF_XFER - Audio has been turned off (xfer) +** BTA_AG_CO_AUD_STATE_ON - Audio has been turned on +** BTA_AG_CO_AUD_STATE_SETUP - Audio is about to be turned on +** +** Returns void +** +*******************************************************************************/ +void bta_ag_co_audio_state(UINT16 handle, UINT8 app_id, UINT8 state) +{ + BTIF_TRACE_DEBUG2("bta_ag_co_audio_state: handle %d, state %d", handle, state); +} + + +/******************************************************************************* +** +** Function bta_ag_co_data_open +** +** Description This function is executed by AG when a service level connection +** is opened. The phone can use this function to set +** up data paths or perform any required initialization or +** set up particular to the connected service. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_co_data_open(UINT16 handle, tBTA_SERVICE_ID service) +{ + BTIF_TRACE_DEBUG2("bta_ag_co_data_open handle:%d service:%d", handle, service); +} + +/******************************************************************************* +** +** Function bta_ag_co_data_close +** +** Description This function is called by AG when a service level +** connection is closed +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_co_data_close(UINT16 handle) +{ + BTIF_TRACE_DEBUG1("bta_ag_co_data_close handle:%d", handle); +} + + +/******************************************************************************* + ** + ** Function bta_ag_co_tx_write + ** + ** Description This function is called by the AG to send data to the + ** phone when the AG is configured for AT command pass-through. + ** The implementation of this function must copy the data to + ** the phones memory. + ** + ** Returns void + ** + *******************************************************************************/ +void bta_ag_co_tx_write(UINT16 handle, UINT8 * p_data, UINT16 len) +{ + BTIF_TRACE_DEBUG2( "bta_ag_co_tx_write: handle: %d, len: %d", handle, len ); +} + diff --git a/btif/co/bta_av_co.c b/btif/co/bta_av_co.c new file mode 100644 index 0000000..6089532 --- /dev/null +++ b/btif/co/bta_av_co.c @@ -0,0 +1,1504 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the advanced audio/video call-out function implementation for + * BTIF. + * + ******************************************************************************/ + +#include "string.h" +#include "a2d_api.h" +#include "a2d_sbc.h" +#include "bta_sys.h" +#include "bta_av_api.h" +#include "bta_av_co.h" +#include "bta_av_ci.h" +#include "bta_av_sbc.h" + +#include "btif_media.h" +#include "sbc_encoder.h" +#include "btif_av_co.h" + + +/***************************************************************************** + ** Constants + *****************************************************************************/ + +#define FUNC_TRACE() APPL_TRACE_DEBUG1("%s", __FUNCTION__); + +/* Macro to retrieve the number of elements in a statically allocated array */ +#define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a)/sizeof((__a)[0])) + +/* MIN and MAX macros */ +#define BTA_AV_CO_MIN(X,Y) ((X) < (Y) ? (X) : (Y)) +#define BTA_AV_CO_MAX(X,Y) ((X) > (Y) ? (X) : (Y)) + +/* Macro to convert audio handle to index and vice versa */ +#define BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl) (((hndl) & (~BTA_AV_CHNL_MSK)) - 1) +#define BTA_AV_CO_AUDIO_INDX_TO_HNDL(indx) (((indx) + 1) | BTA_AV_CHNL_AUDIO) + + +/* Offsets to access codec information in SBC codec */ +#define BTA_AV_CO_SBC_FREQ_CHAN_OFF 3 +#define BTA_AV_CO_SBC_BLOCK_BAND_OFF 4 +#define BTA_AV_CO_SBC_MIN_BITPOOL_OFF 5 +#define BTA_AV_CO_SBC_MAX_BITPOOL_OFF 6 + +#define BTA_AV_CO_SBC_MAX_BITPOOL 53 + +/* SCMS-T protect info */ +const UINT8 bta_av_co_cp_scmst[BTA_AV_CP_INFO_LEN] = "\x02\x02\x00"; + +/* SBC codec capabilities */ +const tA2D_SBC_CIE bta_av_co_sbc_caps = +{ + (A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */ + (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */ + (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */ + (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */ + (A2D_SBC_IE_ALLOC_MD_L | A2D_SBC_IE_ALLOC_MD_S), /* alloc_mthd */ + BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */ + A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ +}; + +#if !defined(BTIF_AV_SBC_DEFAULT_SAMP_FREQ) +#define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_44 +#endif + +/* Default SBC codec configuration */ +const tA2D_SBC_CIE btif_av_sbc_default_config = +{ + BTIF_AV_SBC_DEFAULT_SAMP_FREQ, /* samp_freq */ + A2D_SBC_IE_CH_MD_JOINT, /* ch_mode */ + A2D_SBC_IE_BLOCKS_16, /* block_len */ + A2D_SBC_IE_SUBBAND_8, /* num_subbands */ + A2D_SBC_IE_ALLOC_MD_L, /* alloc_mthd */ + BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */ + A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ +}; + + +/***************************************************************************** +** Local data +*****************************************************************************/ +typedef struct +{ + UINT8 sep_info_idx; /* local SEP index (in BTA tables) */ + UINT8 seid; /* peer SEP index (in peer tables) */ + UINT8 codec_type; /* peer SEP codec type */ + UINT8 codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */ + UINT8 num_protect; /* peer SEP number of CP elements */ + UINT8 protect_info[BTA_AV_CP_INFO_LEN]; /* peer SEP content protection info */ +} tBTA_AV_CO_SINK; + +typedef struct +{ + BD_ADDR addr; /* address of audio/video peer */ + tBTA_AV_CO_SINK snks[BTIF_SV_AV_AA_SEP_INDEX]; /* array of supported sinks */ + UINT8 num_snks; /* total number of sinks at peer */ + UINT8 num_seps; /* total number of seids at peer */ + UINT8 num_rx_snks; /* number of received sinks */ + UINT8 num_sup_snks; /* number of supported sinks in the snks array */ + tBTA_AV_CO_SINK *p_snk; /* currently selected sink */ + UINT8 codec_cfg[AVDT_CODEC_SIZE]; /* current codec configuration */ + BOOLEAN cp_active; /* current CP configuration */ + BOOLEAN acp; /* acceptor */ + BOOLEAN recfg_needed; /* reconfiguration is needed */ + BOOLEAN opened; /* opened */ + UINT16 mtu; /* maximum transmit unit size */ +} tBTA_AV_CO_PEER; + +typedef struct +{ + BOOLEAN active; + UINT8 flag; +} tBTA_AV_CO_CP; + +typedef struct +{ + /* Connected peer information */ + tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS]; + /* Current codec configuration - access to this variable must be protected */ + tBTIF_AV_CODEC_INFO codec_cfg; + tBTIF_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */ + + tBTA_AV_CO_CP cp; +} tBTA_AV_CO_CB; + +/* Control block instance */ +static tBTA_AV_CO_CB bta_av_co_cb; + +static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg); +static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer); +static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo); +static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink); +static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index); +static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg); + + + + +/******************************************************************************* + ** + ** Function bta_av_co_cp_is_active + ** + ** Description Get the current configuration of content protection + ** + ** Returns TRUE if the current streaming has CP, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_cp_is_active(void) +{ + FUNC_TRACE(); + return bta_av_co_cb.cp.active; +} + +/******************************************************************************* + ** + ** Function bta_av_co_cp_get_flag + ** + ** Description Get content protection flag + ** BTA_AV_CP_SCMS_COPY_NEVER + ** BTA_AV_CP_SCMS_COPY_ONCE + ** BTA_AV_CP_SCMS_COPY_FREE + ** + ** Returns The current flag value + ** + *******************************************************************************/ +UINT8 bta_av_co_cp_get_flag(void) +{ + FUNC_TRACE(); + return bta_av_co_cb.cp.flag; +} + +/******************************************************************************* + ** + ** Function bta_av_co_cp_set_flag + ** + ** Description Set content protection flag + ** BTA_AV_CP_SCMS_COPY_NEVER + ** BTA_AV_CP_SCMS_COPY_ONCE + ** BTA_AV_CP_SCMS_COPY_FREE + ** + ** Returns TRUE if setting the SCMS flag is supported else FALSE + ** + *******************************************************************************/ +BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag) +{ + FUNC_TRACE(); + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) +#else + if (cp_flag != BTA_AV_CP_SCMS_COPY_FREE) + { + return FALSE; + } +#endif + bta_av_co_cb.cp.flag = cp_flag; + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_get_peer + ** + ** Description find the peer entry for a given handle + ** + ** Returns the control block + ** + *******************************************************************************/ +static tBTA_AV_CO_PEER *bta_av_co_get_peer(tBTA_AV_HNDL hndl) +{ + UINT8 index; + FUNC_TRACE(); + + index = BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl); + + /* Sanity check */ + if (index >= BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers)) + { + APPL_TRACE_ERROR1("bta_av_co_get_peer peer index out of bounds:%d", index); + return NULL; + } + + return &bta_av_co_cb.peers[index]; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_init + ** + ** Description This callout function is executed by AV when it is + ** started by calling BTA_AvRegister(). This function can be + ** used by the phone to initialize audio paths or for other + ** initialization purposes. + ** + ** + ** Returns Stream codec and content protection capabilities info. + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_num_protect, + UINT8 *p_protect_info, UINT8 index) +{ + FUNC_TRACE(); + + APPL_TRACE_DEBUG1("bta_av_co_audio_init: %d", index); + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + { + UINT8 *p = p_protect_info; + + /* Content protection info - support SCMS-T */ + *p_num_protect = 1; + *p++ = BTA_AV_CP_LOSC; + UINT16_TO_STREAM(p, BTA_AV_CP_SCMS_T_ID); + + } +#else + /* By default - no content protection info */ + *p_num_protect = 0; + *p_protect_info = 0; +#endif + + /* reset remote preference through setconfig */ + bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE; + + switch (index) + { + case BTIF_SV_AV_AA_SBC_INDEX: + /* Set up for SBC codec */ + *p_codec_type = BTA_AV_CODEC_SBC; + + /* This should not fail because we are using constants for parameters */ + A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_caps, p_codec_info); + + /* Codec is valid */ + return TRUE; + + + default: + /* Not valid */ + return FALSE; + } +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_disc_res + ** + ** Description This callout function is executed by AV to report the + ** number of stream end points (SEP) were found during the + ** AVDT stream discovery process. + ** + ** + ** Returns void. + ** + *******************************************************************************/ +BTA_API void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk, + BD_ADDR addr) +{ + tBTA_AV_CO_PEER *p_peer; + + FUNC_TRACE(); + + APPL_TRACE_DEBUG3("bta_av_co_audio_disc_res h:x%x num_seps:%d num_snk:%d", + hndl, num_seps, num_snk); + + /* Find the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) + { + APPL_TRACE_ERROR0("bta_av_co_audio_disc_res could not find peer entry"); + return; + } + + /* Sanity check : this should never happen */ + if (p_peer->opened) + { + APPL_TRACE_ERROR0("bta_av_co_audio_disc_res peer already opened"); + } + + /* Copy the discovery results */ + bdcpy(p_peer->addr, addr); + p_peer->num_snks = num_snk; + p_peer->num_seps = num_seps; + p_peer->num_rx_snks = 0; + p_peer->num_sup_snks = 0; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_getconfig + ** + ** Description This callout function is executed by AV to retrieve the + ** desired codec and content protection configuration for the + ** audio stream. + ** + ** + ** Returns Stream codec and content protection configuration info. + ** + *******************************************************************************/ +BTA_API UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect, + UINT8 *p_protect_info) + +{ + UINT8 result = A2D_FAIL; + BOOLEAN supported; + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_sink; + UINT8 codec_cfg[AVDT_CODEC_SIZE]; + UINT8 index; + + FUNC_TRACE(); + + APPL_TRACE_DEBUG3("bta_av_co_audio_getconfig handle:0x%x codec_type:%d seid:%d", hndl, codec_type, seid); + APPL_TRACE_DEBUG4("num_protect:0x%02x protect_info:0x%02x%02x%02x", + *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) + { + APPL_TRACE_ERROR0("bta_av_co_audio_getconfig could not find peer entry"); + return A2D_FAIL; + } + + APPL_TRACE_DEBUG4("bta_av_co_audio_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", + p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks); + + /* Increment the number of received sinks capabilities */ + p_peer->num_rx_snks++; + + /* Check if this is a supported configuration */ + supported = FALSE; + switch (codec_type) + { + case BTA_AV_CODEC_SBC: + supported = TRUE; + break; + + default: + break; + } + + if (supported) + { + /* If there is room for a new one */ + if (p_peer->num_sup_snks < BTA_AV_CO_NUM_ELEMENTS(p_peer->snks)) + { + p_sink = &p_peer->snks[p_peer->num_sup_snks++]; + + APPL_TRACE_DEBUG6("bta_av_co_audio_getconfig saved caps[%x:%x:%x:%x:%x:%x]", + p_codec_info[1], p_codec_info[2], p_codec_info[3], + p_codec_info[4], p_codec_info[5], p_codec_info[6]); + + memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE); + p_sink->codec_type = codec_type; + p_sink->sep_info_idx = *p_sep_info_idx; + p_sink->seid = seid; + p_sink->num_protect = *p_num_protect; + memcpy(p_sink->protect_info, p_protect_info, BTA_AV_CP_INFO_LEN); + } + else + { + APPL_TRACE_ERROR0("bta_av_co_audio_getconfig no more room for SNK info"); + } + } + + /* If last SNK get capabilities or all supported codec capa retrieved */ + if ((p_peer->num_rx_snks == p_peer->num_snks) || + (p_peer->num_sup_snks == BTA_AV_CO_NUM_ELEMENTS(p_peer->snks))) + { + APPL_TRACE_DEBUG0("bta_av_co_audio_getconfig last sink reached"); + + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_disable(); + + /* Find a sink that matches the codec config */ + if (bta_av_co_audio_peer_supports_codec(p_peer, &index)) + { + /* stop fetching caps once we retrieved a supported codec */ + if (p_peer->acp) + { + *p_sep_info_idx = p_peer->num_seps; + APPL_TRACE_EVENT0("no need to fetch more SEPs"); + } + + p_sink = &p_peer->snks[index]; + + /* Build the codec configuration for this sink */ + if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg)) + { + APPL_TRACE_DEBUG6("bta_av_co_audio_getconfig reconfig p_codec_info[%x:%x:%x:%x:%x:%x]", + codec_cfg[1], codec_cfg[2], codec_cfg[3], + codec_cfg[4], codec_cfg[5], codec_cfg[6]); + + /* Save the new configuration */ + p_peer->p_snk = p_sink; + memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE); + + /* By default, no content protection */ + *p_num_protect = 0; + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + /* Check if this sink supports SCMS */ + if (bta_av_co_audio_sink_has_scmst(p_sink)) + { + p_peer->cp_active = TRUE; + bta_av_co_cb.cp.active = TRUE; + *p_num_protect = BTA_AV_CP_INFO_LEN; + memcpy(p_protect_info, bta_av_co_cp_scmst, BTA_AV_CP_INFO_LEN); + } + else + { + p_peer->cp_active = FALSE; + bta_av_co_cb.cp.active = FALSE; + } +#endif + + /* If acceptor -> reconfig otherwise reply for configuration */ + if (p_peer->acp) + { + if (p_peer->recfg_needed) + { + APPL_TRACE_DEBUG1("bta_av_co_audio_getconfig call BTA_AvReconfig(x%x)", hndl); + BTA_AvReconfig(hndl, TRUE, p_sink->sep_info_idx, p_peer->codec_cfg, *p_num_protect, (UINT8 *)bta_av_co_cp_scmst); + } + } + else + { + *p_sep_info_idx = p_sink->sep_info_idx; + memcpy(p_codec_info, p_peer->codec_cfg, AVDT_CODEC_SIZE); + } + result = A2D_SUCCESS; + } + } + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_enable(); + } + return result; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_setconfig + ** + ** Description This callout function is executed by AV to set the codec and + ** content protection configuration of the audio stream. + ** + ** + ** Returns void + ** + *******************************************************************************/ +BTA_API void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, UINT8 num_protect, UINT8 *p_protect_info) + +{ + tBTA_AV_CO_PEER *p_peer; + UINT8 status = A2D_SUCCESS; + UINT8 category = A2D_SUCCESS; + BOOLEAN recfg_needed = FALSE; + + FUNC_TRACE(); + + APPL_TRACE_DEBUG6("bta_av_co_audio_setconfig p_codec_info[%x:%x:%x:%x:%x:%x]", + p_codec_info[1], p_codec_info[2], p_codec_info[3], + p_codec_info[4], p_codec_info[5], p_codec_info[6]); + APPL_TRACE_DEBUG4("num_protect:0x%02x protect_info:0x%02x%02x%02x", + num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) + { + APPL_TRACE_ERROR0("bta_av_co_audio_setconfig could not find peer entry"); + + /* Call call-in rejecting the configuration */ + bta_av_ci_setconfig(hndl, A2D_BUSY, AVDT_ASC_CODEC, 0, NULL, FALSE); + return; + } + + /* Sanity check: should not be opened at this point */ + if (p_peer->opened) + { + APPL_TRACE_ERROR0("bta_av_co_audio_setconfig peer already in use"); + } + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + if (num_protect != 0) + { + /* If CP is supported */ + if ((num_protect != 1) || + (bta_av_co_cp_is_scmst(p_protect_info) == FALSE)) + { + APPL_TRACE_ERROR0("bta_av_co_audio_setconfig wrong CP configuration"); + status = A2D_BAD_CP_TYPE; + category = AVDT_ASC_PROTECT; + } + } +#else + /* Do not support content protection for the time being */ + if (num_protect != 0) + { + APPL_TRACE_ERROR0("bta_av_co_audio_setconfig wrong CP configuration"); + status = A2D_BAD_CP_TYPE; + category = AVDT_ASC_PROTECT; + } +#endif + if (status == A2D_SUCCESS) + { + /* Check if codec configuration is supported */ + if (bta_av_co_audio_media_supports_config(codec_type, p_codec_info)) + { + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_disable(); + + /* Check if the configuration matches the current codec config */ + switch (bta_av_co_cb.codec_cfg.id) + { + case BTIF_AV_CODEC_SBC: + if ((codec_type != BTA_AV_CODEC_SBC) || memcmp(p_codec_info, bta_av_co_cb.codec_cfg.info, 5)) + { + recfg_needed = TRUE; + } + else if ((num_protect == 1) && (!bta_av_co_cb.cp.active)) + { + recfg_needed = TRUE; + } + + /* if remote side requests a restricted notify sinks preferred bitpool range as all other params are + already checked for validify */ + APPL_TRACE_EVENT2("remote peer setconfig bitpool range [%d:%d]", + p_codec_info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_codec_info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] ); + + bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_SBC; + memcpy(bta_av_co_cb.codec_cfg_setconfig.info, p_codec_info, AVDT_CODEC_SIZE); + break; + + + default: + APPL_TRACE_ERROR1("bta_av_co_audio_setconfig unsupported cid %d", bta_av_co_cb.codec_cfg.id); + recfg_needed = TRUE; + break; + } + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_enable(); + } + else + { + category = AVDT_ASC_CODEC; + status = A2D_WRONG_CODEC; + } + } + + if (status != A2D_SUCCESS) + { + APPL_TRACE_DEBUG2("bta_av_co_audio_setconfig reject s=%d c=%d", status, category); + + /* Call call-in rejecting the configuration */ + bta_av_ci_setconfig(hndl, status, category, 0, NULL, FALSE); + } + else + { + /* Mark that this is an acceptor peer */ + p_peer->acp = TRUE; + p_peer->recfg_needed = recfg_needed; + + APPL_TRACE_DEBUG1("bta_av_co_audio_setconfig accept reconf=%d", recfg_needed); + + /* Call call-in accepting the configuration */ + bta_av_ci_setconfig(hndl, A2D_SUCCESS, A2D_SUCCESS, 0, NULL, recfg_needed); + } +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_open + ** + ** Description This function is called by AV when the audio stream connection + ** is opened. + ** + ** + ** Returns void + ** + *******************************************************************************/ +BTA_API void bta_av_co_audio_open(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu) +{ + tBTA_AV_CO_PEER *p_peer; + + FUNC_TRACE(); + + APPL_TRACE_DEBUG2("bta_av_co_audio_open mtu:%d codec_type:%d", mtu, codec_type); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) + { + APPL_TRACE_ERROR0("bta_av_co_audio_setconfig could not find peer entry"); + } + else + { + p_peer->opened = TRUE; + p_peer->mtu = mtu; + } +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_close + ** + ** Description This function is called by AV when the audio stream connection + ** is closed. + ** + ** + ** Returns void + ** + *******************************************************************************/ +BTA_API void bta_av_co_audio_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu) + +{ + tBTA_AV_CO_PEER *p_peer; + + FUNC_TRACE(); + + APPL_TRACE_DEBUG0("bta_av_co_audio_close"); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer) + { + /* Mark the peer closed and clean the peer info */ + memset(p_peer, 0, sizeof(*p_peer)); + } + else + { + APPL_TRACE_ERROR0("bta_av_co_audio_close could not find peer entry"); + } + + /* reset remote preference through setconfig */ + bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_start + ** + ** Description This function is called by AV when the audio streaming data + ** transfer is started. + ** + ** + ** Returns void + ** + *******************************************************************************/ +BTA_API void bta_av_co_audio_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr) +{ + FUNC_TRACE(); + + APPL_TRACE_DEBUG0("bta_av_co_audio_start"); + +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_stop + ** + ** Description This function is called by AV when the audio streaming data + ** transfer is stopped. + ** + ** + ** Returns void + ** + *******************************************************************************/ +BTA_API extern void bta_av_co_audio_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type) +{ + FUNC_TRACE(); + + APPL_TRACE_DEBUG0("bta_av_co_audio_stop"); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_src_data_path + ** + ** Description This function is called to manage data transfer from + ** the audio codec to AVDTP. + ** + ** Returns Pointer to the GKI buffer to send, NULL if no buffer to send + ** + *******************************************************************************/ +BTA_API void * bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type, UINT32 *p_len, + UINT32 *p_timestamp) +{ + BT_HDR *p_buf; + FUNC_TRACE(); + + p_buf = btif_media_aa_readbuf(); + if (p_buf != NULL) + { + switch (codec_type) + { + case BTA_AV_CODEC_SBC: + /* In media packet SBC, the following information is available: + * p_buf->layer_specific : number of SBC frames in the packet + * p_buf->word[0] : timestamp + */ + /* Retrieve the timestamp information from the media packet */ + *p_timestamp = *((UINT32 *) (p_buf + 1)); + + /* Set up packet header */ + bta_av_sbc_bld_hdr(p_buf, p_buf->layer_specific); + break; + + + default: + APPL_TRACE_ERROR1("bta_av_co_audio_src_data_path Unsupported codec type (%d)", codec_type); + break; + } +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + { + UINT8 *p; + if (bta_av_co_cp_is_active()) + { + p_buf->len++; + p_buf->offset--; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + *p = bta_av_co_cp_get_flag(); + } + } +#endif + } + return p_buf; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_drop + ** + ** Description An Audio packet is dropped. . + ** It's very likely that the connected headset with this handle + ** is moved far away. The implementation may want to reduce + ** the encoder bit rate setting to reduce the packet size. + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_drop(tBTA_AV_HNDL hndl) +{ + FUNC_TRACE(); + + APPL_TRACE_ERROR1("bta_av_co_audio_drop dropped: x%x", hndl); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_delay + ** + ** Description This function is called by AV when the audio stream connection + ** needs to send the initial delay report to the connected SRC. + ** + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, UINT16 delay) +{ + FUNC_TRACE(); + + APPL_TRACE_ERROR2("bta_av_co_audio_delay handle: x%x, delay:0x%x", hndl, delay); +} + + + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_build_config + ** + ** Description Build the codec configuration + ** + ** Returns TRUE if the codec was built successfully, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg) +{ + FUNC_TRACE(); + + memset(p_codec_cfg, 0, AVDT_CODEC_SIZE); + + switch (bta_av_co_cb.codec_cfg.id) + { + case BTIF_AV_CODEC_SBC: + /* only copy the relevant portions for this codec to avoid issues when + comparing codec configs covering larger codec sets than SBC (7 bytes) */ + memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg.info, BTA_AV_CO_SBC_MAX_BITPOOL_OFF+1); + + /* Update the bit pool boundaries with the codec capabilities */ + p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF]; + p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]; + + APPL_TRACE_EVENT2("bta_av_co_audio_codec_build_config : bitpool min %d, max %d", + p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]); + break; + default: + APPL_TRACE_ERROR1("bta_av_co_audio_codec_build_config: unsupported codec id %d", bta_av_co_cb.codec_cfg.id); + return FALSE; + break; + } + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_cfg_matches_caps + ** + ** Description Check if a codec config matches a codec capabilities + ** + ** Returns TRUE if it codec config is supported, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_codec_cfg_matches_caps(UINT8 codec_id, const UINT8 *p_codec_caps, const UINT8 *p_codec_cfg) +{ + FUNC_TRACE(); + + switch(codec_id) + { + case BTIF_AV_CODEC_SBC: + + APPL_TRACE_EVENT4("bta_av_co_audio_codec_cfg_matches_caps : min %d/%d max %d/%d", + p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], + p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]); + + /* Must match all items exactly except bitpool boundaries which can be adjusted */ + if (!((p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF] & p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF]) && + (p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF] & p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]))) + { + APPL_TRACE_EVENT4("FALSE %x %x %x %x", + p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF], + p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF], + p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF], + p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]); + return FALSE; + } + break; + + + default: + APPL_TRACE_ERROR1("bta_av_co_audio_codec_cfg_matches_caps: unsupported codec id %d", codec_id); + return FALSE; + break; + } + APPL_TRACE_EVENT0("TRUE"); + + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_match + ** + ** Description Check if a codec capabilities supports the codec config + ** + ** Returns TRUE if the connection supports this codec, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_codec_match(const UINT8 *p_codec_caps) +{ + FUNC_TRACE(); + + return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg.id, p_codec_caps, bta_av_co_cb.codec_cfg.info); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_peer_reset_config + ** + ** Description Reset the peer codec configuration + ** + ** Returns Nothing + ** + *******************************************************************************/ +static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer) +{ + FUNC_TRACE(); + + /* Indicate that there is no currently selected sink */ + p_peer->p_snk = NULL; +} + +/******************************************************************************* + ** + ** Function bta_av_co_cp_is_scmst + ** + ** Description Check if a content protection service is SCMS-T + ** + ** Returns TRUE if this CP is SCMS-T, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo) +{ + UINT16 cp_id; + FUNC_TRACE(); + + if (*p_protectinfo >= BTA_AV_CP_LOSC) + { + p_protectinfo++; + STREAM_TO_UINT16(cp_id, p_protectinfo); + if (cp_id == BTA_AV_CP_SCMS_T_ID) + { + APPL_TRACE_DEBUG0("bta_av_co_cp_is_scmst: SCMS-T found"); + return TRUE; + } + } + + return FALSE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_sink_has_scmst + ** + ** Description Check if a sink supports SCMS-T + ** + ** Returns TRUE if the sink supports this CP, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink) +{ + UINT8 index; + const UINT8 *p; + FUNC_TRACE(); + + /* Check if sink supports SCMS-T */ + index = p_sink->num_protect; + p = &p_sink->protect_info[0]; + + while (index) + { + if (bta_av_co_cp_is_scmst(p)) + { + return TRUE; + } + /* Move to the next SC */ + p += *p + 1; + /* Decrement the SC counter */ + index--; + } + APPL_TRACE_DEBUG0("bta_av_co_audio_sink_has_scmst: SCMS-T not found"); + return FALSE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_sink_supports_cp + ** + ** Description Check if a sink supports the current content protection + ** + ** Returns TRUE if the sink supports this CP, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_sink_supports_cp(const tBTA_AV_CO_SINK *p_sink) +{ + FUNC_TRACE(); + + /* Check if content protection is enabled for this stream */ + if (bta_av_co_cp_get_flag() != BTA_AV_CP_SCMS_COPY_FREE) + { + return bta_av_co_audio_sink_has_scmst(p_sink); + } + else + { + APPL_TRACE_DEBUG0("bta_av_co_audio_sink_supports_cp: not required"); + return TRUE; + } +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_peer_supports_codec + ** + ** Description Check if a connection supports the codec config + ** + ** Returns TRUE if the connection supports this codec, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index) +{ + int index; + UINT8 codec_type; + FUNC_TRACE(); + + /* Configure the codec type to look for */ + codec_type = bta_av_co_cb.codec_cfg.id; + + + for (index = 0; index < p_peer->num_sup_snks; index++) + { + if (p_peer->snks[index].codec_type == codec_type) + { + switch (bta_av_co_cb.codec_cfg.id) + { + case BTIF_AV_CODEC_SBC: + if (p_snk_index) *p_snk_index = index; + return bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps); + break; + + + default: + APPL_TRACE_ERROR1("bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg.id); + return FALSE; + break; + } + } + } + return FALSE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_media_supports_config + ** + ** Description Check if the media source supports a given configuration + ** + ** Returns TRUE if the media source supports this config, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg) +{ + FUNC_TRACE(); + + switch (codec_type) + { + case BTA_AV_CODEC_SBC: + if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_caps)) + { + return FALSE; + } + break; + + + default: + APPL_TRACE_ERROR1("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type); + return FALSE; + break; + } + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_supported + ** + ** Description Check if all opened connections are compatible with a codec + ** configuration and content protection + ** + ** Returns TRUE if all opened devices support this codec, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_codec_supported(tBTIF_STATUS *p_status) +{ + UINT8 index; + UINT8 snk_index; + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_sink; + UINT8 codec_cfg[AVDT_CODEC_SIZE]; + UINT8 num_protect = 0; +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + BOOLEAN cp_active; +#endif + + FUNC_TRACE(); + + APPL_TRACE_DEBUG0("bta_av_co_audio_codec_supported"); + + /* Check AV feeding is supported */ + *p_status = BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED; + + for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++) + { + p_peer = &bta_av_co_cb.peers[index]; + if (p_peer->opened) + { + if (bta_av_co_audio_peer_supports_codec(p_peer, &snk_index)) + { + p_sink = &p_peer->snks[snk_index]; + + /* Check that this sink is compatible with the CP */ + if (!bta_av_co_audio_sink_supports_cp(p_sink)) + { + APPL_TRACE_DEBUG2("bta_av_co_audio_codec_supported sink %d of peer %d doesn't support cp", + snk_index, index); + *p_status = BTIF_ERROR_SRV_AV_CP_NOT_SUPPORTED; + return FALSE; + } + + /* Build the codec configuration for this sink */ + if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg)) + { +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + /* Check if this sink supports SCMS */ + cp_active = bta_av_co_audio_sink_has_scmst(p_sink); +#endif + /* Check if this is a new configuration (new sink or new config) */ + if ((p_sink != p_peer->p_snk) || + (memcmp(codec_cfg, p_peer->codec_cfg, AVDT_CODEC_SIZE)) +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + || (p_peer->cp_active != cp_active) +#endif + ) + { + /* Save the new configuration */ + p_peer->p_snk = p_sink; + memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE); +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + p_peer->cp_active = cp_active; + if (p_peer->cp_active) + { + bta_av_co_cb.cp.active = TRUE; + num_protect = BTA_AV_CP_INFO_LEN; + } + else + { + bta_av_co_cb.cp.active = FALSE; + } +#endif + APPL_TRACE_DEBUG1("bta_av_co_audio_codec_supported call BTA_AvReconfig(x%x)", BTA_AV_CO_AUDIO_INDX_TO_HNDL(index)); + BTA_AvReconfig(BTA_AV_CO_AUDIO_INDX_TO_HNDL(index), TRUE, p_sink->sep_info_idx, + p_peer->codec_cfg, num_protect, (UINT8 *)bta_av_co_cp_scmst); + } + } + } + else + { + APPL_TRACE_DEBUG1("bta_av_co_audio_codec_supported index %d doesn't support codec", index); + return FALSE; + } + } + } + + *p_status = BTIF_SUCCESS; + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_reset + ** + ** Description Reset the current codec configuration + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_codec_reset(void) +{ + GKI_disable(); + FUNC_TRACE(); + + /* Reset the current configuration to SBC */ + bta_av_co_cb.codec_cfg.id = BTIF_AV_CODEC_SBC; + + if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btif_av_sbc_default_config, bta_av_co_cb.codec_cfg.info) != A2D_SUCCESS) + { + APPL_TRACE_ERROR0("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed"); + } + + GKI_enable(); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_set_codec + ** + ** Description Set the current codec configuration from the feeding type. + ** This function is starting to modify the configuration, it + ** should be protected. + ** + ** Returns TRUE if successful, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_set_codec(const tBTIF_AV_MEDIA_FEEDINGS *p_feeding, tBTIF_STATUS *p_status) +{ + tA2D_SBC_CIE sbc_config; + tBTIF_AV_CODEC_INFO new_cfg; + + FUNC_TRACE(); + + /* Check AV feeding is supported */ + *p_status = BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED; + + APPL_TRACE_DEBUG1("bta_av_co_audio_set_codec cid=%d", p_feeding->format); + + /* Supported codecs */ + switch (p_feeding->format) + { + case BTIF_AV_CODEC_PCM: + new_cfg.id = BTIF_AV_CODEC_SBC; + + sbc_config = btif_av_sbc_default_config; + if ((p_feeding->cfg.pcm.num_channel != 1) && + (p_feeding->cfg.pcm.num_channel != 2)) + { + APPL_TRACE_ERROR0("bta_av_co_audio_set_codec PCM channel number unsupported"); + return FALSE; + } + if ((p_feeding->cfg.pcm.bit_per_sample != 8) && + (p_feeding->cfg.pcm.bit_per_sample != 16)) + { + APPL_TRACE_ERROR0("bta_av_co_audio_set_codec PCM sample size unsupported"); + return FALSE; + } + switch (p_feeding->cfg.pcm.sampling_freq) + { + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 48000: + sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_48; + break; + + case 11025: + case 22050: + case 44100: + sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_44; + break; + default: + APPL_TRACE_ERROR0("bta_av_co_audio_set_codec PCM sampling frequency unsupported"); + return FALSE; + break; + } + /* Build the codec config */ + if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, &sbc_config, new_cfg.info) != A2D_SUCCESS) + { + APPL_TRACE_ERROR0("bta_av_co_audio_set_codec A2D_BldSbcInfo failed"); + return FALSE; + } + break; + + + default: + APPL_TRACE_ERROR0("bta_av_co_audio_set_codec Feeding format unsupported"); + return FALSE; + break; + } + + /* The new config was correctly built */ + bta_av_co_cb.codec_cfg = new_cfg; + + + /* Check all devices support it */ + *p_status = BTIF_SUCCESS; + return bta_av_co_audio_codec_supported(p_status); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_get_sbc_config + ** + ** Description Retrieves the SBC codec configuration. If the codec in use + ** is not SBC, return the default SBC codec configuration. + ** + ** Returns TRUE if codec is SBC, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_get_sbc_config(tA2D_SBC_CIE *p_sbc_config, UINT16 *p_minmtu) +{ + BOOLEAN result = FALSE; + UINT8 index, jndex; + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_sink; + + APPL_TRACE_EVENT1("bta_av_co_cb.codec_cfg.id : codec 0x%x", bta_av_co_cb.codec_cfg.id); + + /* Minimum MTU is by default very large */ + *p_minmtu = 0xFFFF; + + GKI_disable(); + if (bta_av_co_cb.codec_cfg.id == BTIF_AV_CODEC_SBC) + { + if (A2D_ParsSbcInfo(p_sbc_config, bta_av_co_cb.codec_cfg.info, FALSE) == A2D_SUCCESS) + { + for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++) + { + p_peer = &bta_av_co_cb.peers[index]; + if (p_peer->opened) + { + if (p_peer->mtu < *p_minmtu) + { + *p_minmtu = p_peer->mtu; + } + for (jndex = 0; jndex < p_peer->num_sup_snks; jndex++) + { + p_sink = &p_peer->snks[jndex]; + if (p_sink->codec_type == A2D_MEDIA_CT_SBC) + { + /* Update the bitpool boundaries of the current config */ + p_sbc_config->min_bitpool = + BTA_AV_CO_MAX(p_sink->codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_sbc_config->min_bitpool); + p_sbc_config->max_bitpool = + BTA_AV_CO_MIN(p_sink->codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], + p_sbc_config->max_bitpool); + APPL_TRACE_EVENT2("bta_av_co_audio_get_sbc_config : sink bitpool min %d, max %d", + p_sbc_config->min_bitpool, p_sbc_config->max_bitpool); + break; + } + } + } + } + result = TRUE; + } + } + + if (!result) + { + /* Not SBC, still return the default values */ + *p_sbc_config = btif_av_sbc_default_config; + } + GKI_enable(); + + return result; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_discard_config + ** + ** Description Discard the codec configuration of a connection + ** + ** Returns Nothing + ** + *******************************************************************************/ +void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl) +{ + tBTA_AV_CO_PEER *p_peer; + + FUNC_TRACE(); + + /* Find the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) + { + APPL_TRACE_ERROR0("bta_av_co_audio_discard_config could not find peer entry"); + return; + } + + /* Reset the peer codec configuration */ + bta_av_co_audio_peer_reset_config(p_peer); +} + +/******************************************************************************* + ** + ** Function bta_av_co_init + ** + ** Description Initialization + ** + ** Returns Nothing + ** + *******************************************************************************/ +void bta_av_co_init(void) +{ + FUNC_TRACE(); + + /* Reset the control block */ + memset(&bta_av_co_cb, 0, sizeof(bta_av_co_cb)); + + bta_av_co_cb.codec_cfg_setconfig.id = BTIF_AV_CODEC_NONE; + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_NEVER); +#else + bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_FREE); +#endif + + /* Reset the current config */ + bta_av_co_audio_codec_reset(); +} + + +/******************************************************************************* + ** + ** Function bta_av_co_peer_cp_supported + ** + ** Description Checks if the peer supports CP + ** + ** Returns TRUE if the peer supports CP + ** + *******************************************************************************/ +BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl) +{ + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_sink; + UINT8 index; + + FUNC_TRACE(); + + /* Find the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) + { + APPL_TRACE_ERROR0("bta_av_co_peer_cp_supported could not find peer entry"); + return FALSE; + } + + for (index = 0; index < p_peer->num_sup_snks; index++) + { + p_sink = &p_peer->snks[index]; + if (p_sink->codec_type == A2D_MEDIA_CT_SBC) + { + return bta_av_co_audio_sink_has_scmst(p_sink); + } + } + APPL_TRACE_ERROR0("bta_av_co_peer_cp_supported did not find SBC sink"); + return FALSE; +} + + +/******************************************************************************* + ** + ** Function bta_av_co_get_remote_bitpool_pref + ** + ** Description Check if remote side did a setconfig within the limits + ** of our exported bitpool range. If set we will set the + ** remote preference. + ** + ** Returns TRUE if config set, FALSE otherwize + ** + *******************************************************************************/ + +BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max) +{ + /* check if remote peer did a set config */ + if (bta_av_co_cb.codec_cfg_setconfig.id == BTIF_AV_CODEC_NONE) + return FALSE; + + *min = bta_av_co_cb.codec_cfg_setconfig.info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF]; + *max = bta_av_co_cb.codec_cfg_setconfig.info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]; + + return TRUE; +} + + diff --git a/btif/co/bta_dm_co.c b/btif/co/bta_dm_co.c new file mode 100644 index 0000000..611af2d --- /dev/null +++ b/btif/co/bta_dm_co.c @@ -0,0 +1,417 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include <stdio.h> +#include <stdlib.h> + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_dm_co.h" +#include "bta_dm_ci.h" +#if (BTM_OOB_INCLUDED == TRUE) +#include "btif_dm.h" +#endif +/******************************************************************************* +** +** Function bta_dm_co_get_compress_memory +** +** Description This callout function is executed by DM to get memory for compression + +** Parameters id - BTA SYS ID +** memory_p - memory return by callout +** memory_size - memory size +** +** Returns TRUE for success, FALSE for fail. +** +*******************************************************************************/ +BOOLEAN bta_dm_co_get_compress_memory(tBTA_SYS_ID id, UINT8 **memory_p, UINT32 *memory_size) +{ + return TRUE; +} + +/******************************************************************************* +** +** Function bta_dm_co_io_req +** +** Description This callout function is executed by DM to get IO capabilities +** of the local device for the Simple Pairing process +** +** Parameters bd_addr - The peer device +** *p_io_cap - The local Input/Output capabilities +** *p_oob_data - TRUE, if OOB data is available for the peer device. +** *p_auth_req - TRUE, if MITM protection is required. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, tBTA_OOB_DATA *p_oob_data, + tBTA_AUTH_REQ *p_auth_req, BOOLEAN is_orig) +{ +#if (BTM_OOB_INCLUDED == TRUE) + btif_dm_set_oob_for_io_req(p_oob_data); +#endif + BTIF_TRACE_DEBUG1("bta_dm_co_io_req *p_oob_data = %d", *p_oob_data); + BTIF_TRACE_DEBUG1("bta_dm_co_io_req *p_io_cap = %d", *p_io_cap); + BTIF_TRACE_DEBUG1("bta_dm_co_io_req *p_auth_req = %d", *p_auth_req); + BTIF_TRACE_DEBUG1("bta_dm_co_io_req is_orig = %d", is_orig); +} + +/******************************************************************************* +** +** Function bta_dm_co_io_rsp +** +** Description This callout function is executed by DM to report IO capabilities +** of the peer device for the Simple Pairing process +** +** Parameters bd_addr - The peer device +** io_cap - The remote Input/Output capabilities +** oob_data - TRUE, if OOB data is available for the peer device. +** auth_req - TRUE, if MITM protection is required. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, + tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req) +{ +} + +/******************************************************************************* +** +** Function bta_dm_co_lk_upgrade +** +** Description This callout function is executed by DM to check if the +** platform wants allow link key upgrade +** +** Parameters bd_addr - The peer device +** *p_upgrade - TRUE, if link key upgrade is desired. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, BOOLEAN *p_upgrade ) +{ +} + +#if (BTM_OOB_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_co_loc_oob +** +** Description This callout function is executed by DM to report the OOB +** data of the local device for the Simple Pairing process +** +** Parameters valid - TRUE, if the local OOB data is retrieved from LM +** c - Simple Pairing Hash C +** r - Simple Pairing Randomnizer R +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r) +{ + BTIF_TRACE_DEBUG1("bta_dm_co_loc_oob, valid = %d", valid); +#ifdef BTIF_DM_OOB_TEST + btif_dm_proc_loc_oob(valid, c, r); +#endif +} + +/******************************************************************************* +** +** Function bta_dm_co_rmt_oob +** +** Description This callout function is executed by DM to request the OOB +** data for the remote device for the Simple Pairing process +** Need to call bta_dm_ci_rmt_oob() in response +** +** Parameters bd_addr - The peer device +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_rmt_oob(BD_ADDR bd_addr) +{ + BT_OCTET16 p_c; + BT_OCTET16 p_r; + BOOLEAN result = FALSE; + +#ifdef BTIF_DM_OOB_TEST + result = btif_dm_proc_rmt_oob(bd_addr, p_c, p_r); +#endif + + BTIF_TRACE_DEBUG1("bta_dm_co_rmt_oob: result=%d",result); + bta_dm_ci_rmt_oob(result, bd_addr, p_c, p_r); +} + +#endif /* BTM_OOB_INCLUDED */ + + +// REMOVE FOR BLUEDROID ? + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function btui_sco_codec_callback +** +** Description Callback for btui codec. +** +** +** Returns void +** +*******************************************************************************/ +static void btui_sco_codec_callback(UINT16 event, UINT16 sco_handle) +{ + bta_dm_sco_ci_data_ready(event, sco_handle); +} +/******************************************************************************* +** +** Function bta_dm_sco_co_init +** +** Description This function can be used by the phone to initialize audio +** codec or for other initialization purposes before SCO connection +** is opened. +** +** +** Returns tBTA_DM_SCO_ROUTE_TYPE: SCO routing configuration type. +** +*******************************************************************************/ +tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, + tBTA_CODEC_INFO * p_codec_type, UINT8 app_id) +{ + tBTM_SCO_ROUTE_TYPE route = BTA_DM_SCO_ROUTE_PCM; + + BTIF_TRACE_DEBUG0("bta_dm_sco_co_init"); + + /* set up SCO routing configuration if SCO over HCI app ID is used and run time + configuration is set to SCO over HCI */ + /* HS invoke this call-out */ + if ( +#if (BTA_HS_INCLUDED == TRUE ) && (BTA_HS_INCLUDED == TRUE) + (app_id == BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.hs_sco_over_hci) || +#endif + /* AG invoke this call-out */ + (app_id != BTUI_DM_SCO_4_HS_APP_ID && btui_cfg.ag_sco_over_hci )) + { + route = btui_cb.sco_hci = BTA_DM_SCO_ROUTE_HCI; + } + /* no codec is is used for the SCO data */ + if (p_codec_type->codec_type == BTA_SCO_CODEC_PCM && route == BTA_DM_SCO_ROUTE_HCI) + { + /* initialize SCO codec */ + if (!btui_sco_codec_init(rx_bw, tx_bw)) + { + BTIF_TRACE_ERROR0("codec initialization exception!"); + } + } + + return route; +} + + + +/******************************************************************************* +** +** Function bta_dm_sco_co_open +** +** Description This function is executed when a SCO connection is open. +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event) +{ + tBTUI_SCO_CODEC_CFG cfg; + + if (btui_cb.sco_hci) + { + BTIF_TRACE_DEBUG2("bta_dm_sco_co_open handle:%d pkt_size:%d", handle, pkt_size); + /* use dedicated SCO buffer pool for SCO TX data */ + cfg.pool_id = HCI_SCO_POOL_ID; + cfg.p_cback = btui_sco_codec_callback; + cfg.pkt_size = pkt_size; + cfg.cb_event = event; + /* open and start the codec */ + btui_sco_codec_open(&cfg); + btui_sco_codec_start(handle); + } +} + +/******************************************************************************* +** +** Function bta_dm_sco_co_close +** +** Description This function is called when a SCO connection is closed +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_co_close(void) +{ + if (btui_cb.sco_hci) + { + BTIF_TRACE_DEBUG0("bta_dm_sco_co_close close codec"); + /* close sco codec */ + btui_sco_codec_close(); + + btui_cb.sco_hci = FALSE; + } +} + +/******************************************************************************* +** +** Function bta_dm_sco_co_in_data +** +** Description This function is called to send incoming SCO data to application. +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_co_in_data(BT_HDR *p_buf) +{ + if (btui_cfg.sco_use_mic) + btui_sco_codec_inqdata (p_buf); + else + GKI_freebuf(p_buf); +} + +/******************************************************************************* +** +** Function bta_dm_sco_co_out_data +** +** Description This function is called to send SCO data over HCI. +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_co_out_data(BT_HDR **p_buf) +{ + btui_sco_codec_readbuf(p_buf); +} + +#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) && (BTM_SCO_INCLUDED == TRUE)*/ + + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_co_le_io_key_req +** +** Description This callout function is executed by DM to get BLE key information +** before SMP pairing gets going. +** +** Parameters bd_addr - The peer device +** *p_max_key_size - max key size local device supported. +** *p_init_key - initiator keys. +** *p_resp_key - responder keys. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_le_io_key_req(BD_ADDR bd_addr, UINT8 *p_max_key_size, + tBTA_LE_KEY_TYPE *p_init_key, + tBTA_LE_KEY_TYPE *p_resp_key ) +{ + BTIF_TRACE_ERROR0("##################################"); + BTIF_TRACE_ERROR0("bta_dm_co_le_io_key_req: only setting max size to 16"); + BTIF_TRACE_ERROR0("##################################"); + *p_max_key_size = 16; + *p_init_key = *p_resp_key = + (BTA_LE_KEY_PENC|BTA_LE_KEY_PID|BTA_LE_KEY_PCSRK|BTA_LE_KEY_LENC|BTA_LE_KEY_LID|BTA_LE_KEY_LCSRK); +} + + +/******************************************************************************* +** +** Function bta_dm_co_ble_local_key_reload +** +** Description This callout function is to load the local BLE keys if available +** on the device. +** +** Parameters none +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK *p_key_mask, BT_OCTET16 er, + tBTA_BLE_LOCAL_ID_KEYS *p_id_keys) +{ + BTIF_TRACE_ERROR0("##################################"); + BTIF_TRACE_ERROR0("bta_dm_co_ble_load_local_keys: TBD Load local keys if any are persisted"); + BTIF_TRACE_ERROR0("##################################"); +} + +/******************************************************************************* +** +** Function bta_dm_co_ble_io_req +** +** Description This callout function is executed by DM to get BLE IO capabilities +** before SMP pairing gets going. +** +** Parameters bd_addr - The peer device +** *p_io_cap - The local Input/Output capabilities +** *p_oob_data - TRUE, if OOB data is available for the peer device. +** *p_auth_req - Auth request setting (Bonding and MITM required or not) +** *p_max_key_size - max key size local device supported. +** *p_init_key - initiator keys. +** *p_resp_key - responder keys. +** +** Returns void. +** +*******************************************************************************/ +void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap, + tBTA_OOB_DATA *p_oob_data, + tBTA_LE_AUTH_REQ *p_auth_req, + UINT8 *p_max_key_size, + tBTA_LE_KEY_TYPE *p_init_key, + tBTA_LE_KEY_TYPE *p_resp_key ) +{ + /* if OOB is not supported, this call-out function does not need to do anything + * otherwise, look for the OOB data associated with the address and set *p_oob_data accordingly + * If the answer can not be obtained right away, + * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the answer is available */ + + /* *p_auth_req by default is FALSE for devices with NoInputNoOutput; TRUE for other devices. */ + BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_auth_req=%d ble_authereq=%d", *p_auth_req, bte_appl_cfg.ble_auth_req); + BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_io_cap=%d ble_io_cap=%d", *p_io_cap, bte_appl_cfg.ble_io_cap); + BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_init_key=%d ble_init_key=%d", *p_init_key, bte_appl_cfg.ble_init_key); + BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_resp_key=%d ble_resp_key=%d", *p_resp_key, bte_appl_cfg.ble_resp_key ); + BTIF_TRACE_ERROR2("bta_dm_co_ble_io_req. p_max_key_size=%d ble_max_key_size=%d", *p_max_key_size, bte_appl_cfg.ble_max_key_size ); + + *p_oob_data = FALSE; + if (bte_appl_cfg.ble_auth_req) + *p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04); + + if (bte_appl_cfg.ble_io_cap <=4) + *p_io_cap = bte_appl_cfg.ble_io_cap; + + if (bte_appl_cfg.ble_init_key<=7) + *p_init_key = bte_appl_cfg.ble_init_key; + + if (bte_appl_cfg.ble_resp_key<=7) + *p_resp_key = bte_appl_cfg.ble_resp_key; + + if (bte_appl_cfg.ble_max_key_size<=16) + *p_max_key_size = bte_appl_cfg.ble_max_key_size; + +} + + +#endif + diff --git a/btif/co/bta_fs_co.c b/btif/co/bta_fs_co.c new file mode 100644 index 0000000..ffc146b --- /dev/null +++ b/btif/co/bta_fs_co.c @@ -0,0 +1,1181 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/vfs.h> +#include <unistd.h> +#include <dirent.h> +#include <time.h> +#include <limits.h> +#include "gki.h" +#include "bta_fs_co.h" +#include "bta_fs_ci.h" +#include <inttypes.h> + +#ifndef AID_SYSTEM +#define AID_SYSTEM 1000 +#define AID_BLUETOOTH 1002 +#define AID_SDCARD_RW 1015 +#define AID_MISC 9998 +#endif + +#define FAT_FS 0x4d44 +const unsigned short BT_UID= AID_BLUETOOTH; +const unsigned short BT_GID= AID_BLUETOOTH; + +/* enable additional debugging traces that should be compiled out by default! */ +#ifndef BTA_FS_DEBUG +#define BTA_FS_DEBUG TRUE +#define LOG_TAG "BTA_FS_CO" +#define LOGI(format, ...) fprintf (stdout, LOG_TAG format"\n", ## __VA_ARGS__) +#endif + +#if (defined BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE) +extern const tBTA_PBS_CFG bta_pbs_cfg; +#endif + + + +static int del_path (const char *path) +{ + DIR *dir; + struct dirent *de; + int ret = 0; + char nameBuffer[PATH_MAX] = {0}; + struct stat statBuffer; + BTIF_TRACE_DEBUG1("in del_path for path:%s", path); + dir = opendir(path); + + if (dir == NULL) { + BTIF_TRACE_DEBUG1("opendir failed on path:%s", path); + return -1; + } + + char *filenameOffset; + + strncpy(nameBuffer, path, PATH_MAX - 1); + strcat(nameBuffer, "/"); + int nameLen = strlen(nameBuffer); + filenameOffset = nameBuffer + nameLen; + + for (;;) { + de = readdir(dir); + + if (de == NULL) { + BTIF_TRACE_DEBUG1("readdir failed for path:%s", path); + //ret = -1; + break; + } + + if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, "..")) + continue; + + if((int)strlen(de->d_name) > PATH_MAX - nameLen) { + BTIF_TRACE_DEBUG1("d_name len:%d is too big", strlen(de->d_name)); + ret = -1; + break; + } + + strcpy(filenameOffset, de->d_name); + + ret = lstat (nameBuffer, &statBuffer); + + if (ret != 0) { + BTIF_TRACE_DEBUG1("lstat failed for path:%s", nameBuffer); + break; + } + + if(S_ISDIR(statBuffer.st_mode)) { + + ret = del_path(nameBuffer); + if(ret != 0) + break; + } else { + ret = unlink(nameBuffer); + if (ret != 0) { + BTIF_TRACE_DEBUG1("unlink failed for path:%s", nameBuffer); + break; + } + } + } + + closedir(dir); + if(ret == 0) { + ret = rmdir(path); + BTIF_TRACE_DEBUG2("rmdir return:%d for path:%s", ret, path); + } + + return ret; + +} + +inline int getAccess(int accType, struct stat *buffer, char *p_path) +{ + + struct statfs fsbuffer; + int idType; + + if(! buffer) + return BTA_FS_CO_FAIL; + + //idType= (buffer->st_uid== BT_UID) ? 1 : (buffer->st_uid== BT_GID) ? 2 : 3; + if(buffer->st_uid == BT_UID) + idType = 1; + else if(buffer->st_gid == BT_GID || + buffer->st_gid == AID_SYSTEM || + buffer->st_gid == AID_MISC || + buffer->st_gid == AID_SDCARD_RW) + idType = 2; + else idType = 3; + + if(statfs(p_path, &fsbuffer)==0) + { + if(fsbuffer.f_type == FAT_FS) + return BTA_FS_CO_OK; + } + else { + return BTA_FS_CO_FAIL; + } + + switch(accType) { + case 4: + if(idType== 1) { //Id is User Id + if(buffer-> st_mode & S_IRUSR) + return BTA_FS_CO_OK; + } + else if(idType==2) { //Id is Group Id + if(buffer-> st_mode & S_IRGRP) + return BTA_FS_CO_OK; + } + else { //Id is Others + if(buffer-> st_mode & S_IROTH) + return BTA_FS_CO_OK; + } + break; + + case 6: + if(idType== 1) { //Id is User Id + if((buffer-> st_mode & S_IRUSR) && (buffer-> st_mode & S_IWUSR)) + return BTA_FS_CO_OK; + } + else if(idType==2) { //Id is Group Id + if((buffer-> st_mode & S_IRGRP) && (buffer-> st_mode & S_IWGRP)) + return BTA_FS_CO_OK; + } + else { //Id is Others + if((buffer-> st_mode & S_IROTH) && (buffer-> st_mode & S_IWOTH)) + return BTA_FS_CO_OK; + } + break; + + default: + return BTA_FS_CO_OK; + } + BTIF_TRACE_DEBUG0("*************FTP- Access Failed **********"); + return BTA_FS_CO_EACCES; +} + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_fs_convert_oflags +** +** Description This function converts the open flags from BTA into MFS. +** +** Returns BTA FS status value. +** +*******************************************************************************/ +int bta_fs_convert_bta_oflags(int bta_oflags) +{ + int oflags = 0; /* Initially read only */ + + /* Only one of these can be set: Read Only, Read/Write, or Write Only */ + if (bta_oflags & BTA_FS_O_RDWR) + oflags |= O_RDWR; + else if (bta_oflags & BTA_FS_O_WRONLY) + oflags |= O_WRONLY; + + /* OR in any other flags that are set by BTA */ + if (bta_oflags & BTA_FS_O_CREAT) + oflags |= O_CREAT; + + if (bta_oflags & BTA_FS_O_EXCL) + oflags |= O_EXCL; + + if (bta_oflags & BTA_FS_O_TRUNC) + oflags |= O_TRUNC; + + return (oflags); +} + + + +/******************************************************************************* + ** + ** Function btapp_fs_check_space + ** + ** Description determines access and if there is enough space for given files size on given path + ** + ** Parameters p_path - Fully qualified path and file name. + ** WARNING: file name is stripped off! so it must be present! + ** size - size of file to put (0 if unavailable or not applicable) + ** app_id - in case application specific treatement is required (e.g opp versus ftp) + ** Returns 0 if enough space, otherwise errno failure codes + ** + *******************************************************************************/ +static int btapp_fs_check_space( const char *p_path, const UINT32 size, const UINT8 app_id ) +{ + + unsigned long long max_space; + struct statfs fs_buffer; + int err = 0; + char *p_dir; + char *p_end; + + if(size==BTA_FS_LEN_UNKNOWN) + return 0; + /* fail silently in case of no memory. write will catch if not enough space */ + + if (NULL != (p_dir = (char *) GKI_getbuf(strlen(p_path) + 1))) + { + strcpy(p_dir, p_path); + if (NULL != (p_end = strrchr(p_dir, '/'))) + { + + *p_end = '\0'; + /* get fs info and calculate available space. if not enough, the fs error EFBIG is returned */ + + if (0 == statfs(p_dir, &fs_buffer)) + { + + max_space = fs_buffer.f_bavail * fs_buffer.f_bsize; +#if (BTA_FS_DEBUG==TRUE) + BTIF_TRACE_DEBUG2("btapp_fs_enough_space(file size: %d): (uint)max_size: %u", size, (UINT32)max_space); +#endif + if (max_space < size) + err = EFBIG; + } + else + { + err = errno; + BTIF_TRACE_WARNING1("btapp_fs_enough_space(): statfs() failed with err: %d", err); + } + } + else + { + err = ENOENT; + } + GKI_freebuf(p_dir); + } + else + { + err = ENOMEM; + } + return err; + +} /* btapp_fs_check_access_space() */ + + +/******************************************************************************* +** +** Function bta_fs_co_open +** +** Description This function is executed by BTA when a file is opened. +** The phone uses this function to open +** a file for reading or writing. +** +** Parameters p_path - Fully qualified path and file name. +** oflags - permissions and mode (see constants above) +** size - size of file to put (0 if unavailable or not applicable) +** evt - event that must be passed into the call-in function. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +** Note: Upon completion of the request, a file descriptor (int), +** if successful, and an error code (tBTA_FS_CO_STATUS) +** are returned in the call-in function, bta_fs_ci_open(). +** +*******************************************************************************/ + +void bta_fs_co_open(const char *p_path, int oflags, UINT32 size, UINT16 evt, + UINT8 app_id) +{ + + tBTA_FS_CO_STATUS status; + UINT32 file_size = 0; + struct stat file_stat; + int fd = -1; + int err = 0; + + /* Convert BTA oflags into os specific flags */ + oflags = bta_fs_convert_bta_oflags(oflags); + + /* check available space in case of write access. oflags are in OS format! */ + if (oflags & (O_RDWR|O_WRONLY)) + { + err = btapp_fs_check_space(p_path, size, app_id); + } + + if ( 0==err ) + { + if ((fd = open(p_path, oflags | O_NONBLOCK, 0666)) >= 0) + { + if (fstat(fd, &file_stat) == 0) + { + file_size = file_stat.st_size; + if (oflags & O_CREAT) + { + fchown(fd, BT_UID, BT_GID); + BTIF_TRACE_DEBUG0("\n ******CHANGED OWNERSHIP SUCCESSFULLY**********"); + } + } + } + + else + { + err = errno; + } + } + + BTIF_TRACE_DEBUG4("[CO] bta_fs_co_open: handle:%d err:%d, flags:%x, app id:%d", + fd, err, oflags, app_id); + BTIF_TRACE_DEBUG1("file=%s", p_path); + + /* convert fs error into bta_fs err. erro is set by first call to enough space to a valid value + * and needs only updating in case of error. This reports correct failure to remote obex! */ + + switch (err) + { + + case 0: + status = BTA_FS_CO_OK; + break; + case EACCES: + status = BTA_FS_CO_EACCES; + break; + case EFBIG: /* file to big for available fs space */ + status = BTA_FS_CO_ENOSPACE; + break; + default: + status = BTA_FS_CO_FAIL; + break; + } + bta_fs_ci_open(fd, status, file_size, evt); +} + +/******************************************************************************* +** +** Function bta_fs_co_close +** +** Description This function is called by BTA when a connection to a +** client is closed. +** +** Parameters fd - file descriptor of file to close. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns (tBTA_FS_CO_STATUS) status of the call. +** [BTA_FS_CO_OK if successful], +** [BTA_FS_CO_FAIL if failed ] +** +*******************************************************************************/ +tBTA_FS_CO_STATUS bta_fs_co_close(int fd, UINT8 app_id) +{ + tBTA_FS_CO_STATUS status = BTA_FS_CO_OK; + int err; + + BTIF_TRACE_DEBUG2("[CO] bta_fs_co_close: handle:%d, app id:%d", + fd, app_id); + if (close (fd) < 0) + { + err = errno; + status = BTA_FS_CO_FAIL; + BTIF_TRACE_WARNING3("[CO] bta_fs_co_close: handle:%d error=%d app_id:%d", fd, err, app_id); + } + + return (status); +} + +/******************************************************************************* +** +** Function bta_fs_co_read +** +** Description This function is called by BTA to read in data from the +** previously opened file on the phone. +** +** Parameters fd - file descriptor of file to read from. +** p_buf - buffer to read the data into. +** nbytes - number of bytes to read into the buffer. +** evt - event that must be passed into the call-in function. +** ssn - session sequence number. Ignored, if bta_fs_co_open +** was not called with BTA_FS_CO_RELIABLE. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +** Note: Upon completion of the request, bta_fs_ci_read() is +** called with the buffer of data, along with the number +** of bytes read into the buffer, and a status. The +** call-in function should only be called when ALL requested +** bytes have been read, the end of file has been detected, +** or an error has occurred. +** +*******************************************************************************/ +void bta_fs_co_read(int fd, UINT8 *p_buf, UINT16 nbytes, UINT16 evt, UINT8 ssn, UINT8 app_id) +{ + tBTA_FS_CO_STATUS status = BTA_FS_CO_OK; + INT32 num_read; + int err; + + if ((num_read = read (fd, p_buf, nbytes)) < 0) + { + err = errno; + status = BTA_FS_CO_FAIL; + BTIF_TRACE_WARNING3("[CO] bta_fs_co_read: handle:%d error=%d app_id:%d", + fd, err, app_id); + } + else if (num_read < nbytes) + status = BTA_FS_CO_EOF; + + bta_fs_ci_read(fd, (UINT16)num_read, status, evt); +} + +/******************************************************************************* +** +** Function bta_fs_co_write +** +** Description This function is called by io to send file data to the +** phone. +** +** Parameters fd - file descriptor of file to write to. +** p_buf - buffer to read the data from. +** nbytes - number of bytes to write out to the file. +** evt - event that must be passed into the call-in function. +** ssn - session sequence number. Ignored, if bta_fs_co_open +** was not called with BTA_FS_CO_RELIABLE. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +** Note: Upon completion of the request, bta_fs_ci_write() is +** called with the file descriptor and the status. The +** call-in function should only be called when ALL requested +** bytes have been written, or an error has been detected, +** +*******************************************************************************/ +void bta_fs_co_write(int fd, const UINT8 *p_buf, UINT16 nbytes, UINT16 evt, + UINT8 ssn, UINT8 app_id) +{ + tBTA_FS_CO_STATUS status = BTA_FS_CO_OK; + INT32 num_written; + int err=0; + + if ((num_written = write (fd, p_buf, nbytes)) < 0) + { + err = errno; + status = BTA_FS_CO_FAIL; + } +/* BTIF_TRACE_DEBUG3("[CO] bta_fs_co_write: handle:%d error=%d, num_written:%d", fd, err, num_written);*/ + + bta_fs_ci_write(fd, status, evt); +} + +/******************************************************************************* +** +** Function bta_fs_co_seek +** +** Description This function is called by io to move the file pointer +** of a previously opened file to the specified location for +** the next read or write operation. +** +** Parameters fd - file descriptor of file. +** offset - Number of bytes from origin. +** origin - Initial position. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_co_seek (int fd, INT32 offset, INT16 origin, UINT8 app_id) +{ + lseek(fd, offset, origin); +} + +/******************************************************************************* +** +** Function bta_fs_co_access +** +** Description This function is called to check the existence of +** a file or directory, and return whether or not it is a +** directory or length of the file. +** +** Parameters p_path - (input) file or directory to access (fully qualified path). +** mode - (input) [BTA_FS_ACC_EXIST, BTA_FS_ACC_READ, or BTA_FS_ACC_RDWR] +** p_is_dir - (output) returns TRUE if p_path specifies a directory. +** app_id - (input) application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns (tBTA_FS_CO_STATUS) status of the call. +** [BTA_FS_CO_OK if it exists] +** [BTA_FS_CO_EACCES if permissions are wrong] +** [BTA_FS_CO_FAIL if it does not exist] +** +*******************************************************************************/ +tBTA_FS_CO_STATUS bta_fs_co_access(const char *p_path, int mode, BOOLEAN *p_is_dir, + UINT8 app_id) +{ + int err; + int os_mode = 0; + tBTA_FS_CO_STATUS status = BTA_FS_CO_OK; + struct stat buffer; + + #if (TRUE==BTA_FS_DEBUG) + LOGI("***********CHECKING ACCESS TO = %s", p_path); + #endif + + #if (defined BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE) + + if (app_id == UI_PBS_ID) + { + + *p_is_dir = TRUE; + + #if (TRUE==BTA_FS_DEBUG) + LOGI("***********SUPPORTED REPO = %d", bta_pbs_cfg.supported_repositories); + #endif + //Check if SIM contact requested, and if so if it's supported. + //If not, return error! + if (strstr(p_path,"SIM1") && !(bta_pbs_cfg.supported_repositories & 0x2)) { + LOGI("***********RETURNING FAIL!"); + return BTA_FS_CO_FAIL; + } + + #if (TRUE==BTA_FS_DEBUG) + LOGI("***********RETURNING success!"); + #endif + return (status); + } + #endif + + + *p_is_dir = FALSE; + + if (mode == BTA_FS_ACC_RDWR) + os_mode = 6; + else if (mode == BTA_FS_ACC_READ) + os_mode = 4; + + if (stat(p_path, &buffer) == 0) + { + /* Determine if the object is a file or directory */ + if (S_ISDIR(buffer.st_mode)) + *p_is_dir = TRUE; + } + else + { + BTIF_TRACE_DEBUG0("stat() failed! "); + return BTA_FS_CO_FAIL; + } + + status=getAccess (os_mode, &buffer, (char*)p_path); + return (status); +} + +/******************************************************************************* +** +** Function bta_fs_co_mkdir +** +** Description This function is called to create a directory with +** the pathname given by path. The pathname is a null terminated +** string. All components of the path must already exist. +** +** Parameters p_path - (input) name of directory to create (fully qualified path). +** app_id - (input) application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns (tBTA_FS_CO_STATUS) status of the call. +** [BTA_FS_CO_OK if successful] +** [BTA_FS_CO_FAIL if unsuccessful] +** +*******************************************************************************/ +tBTA_FS_CO_STATUS bta_fs_co_mkdir(const char *p_path, UINT8 app_id) +{ + int err; + tBTA_FS_CO_STATUS status = BTA_FS_CO_OK; + + if ((mkdir (p_path, 0666)) != 0) + { + err = errno; + status = BTA_FS_CO_FAIL; + BTIF_TRACE_WARNING3("[CO] bta_fs_co_mkdir: error=%d, path [%s] app_id:%d", + err, p_path, app_id); + } + return (status); +} + +/******************************************************************************* +** +** Function bta_fs_co_rmdir +** +** Description This function is called to remove a directory whose +** name is given by path. The directory must be empty. +** +** Parameters p_path - (input) name of directory to remove (fully qualified path). +** app_id - (input) application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns (tBTA_FS_CO_STATUS) status of the call. +** [BTA_FS_CO_OK if successful] +** [BTA_FS_CO_EACCES if read-only] +** [BTA_FS_CO_ENOTEMPTY if directory is not empty] +** [BTA_FS_CO_FAIL otherwise] +** +*******************************************************************************/ +tBTA_FS_CO_STATUS bta_fs_co_rmdir(const char *p_path, UINT8 app_id) +{ + int err, path_len; + tBTA_FS_CO_STATUS status = BTA_FS_CO_OK; + struct stat buffer; + char *dirName, *tmp = NULL; + + path_len = strlen( p_path )+1; + BTIF_TRACE_DEBUG2( "bta_fs_co_rmdir( app_id: %d ): path_len: %d", app_id, path_len ); +#if (TRUE==BTA_FS_DEBUG) + BTIF_TRACE_DEBUG1( "bta_fs_co_rmdir():path_len: %d, p_path", app_id ); + BTIF_TRACE_DEBUG0( p_path ); +#endif + + /* allocate a temp buffer for path with 0 char. make sure not to crash if path is too big! */ + dirName = (char*) calloc(1, path_len+1); + if ( NULL != dirName ) + { + strcpy( dirName, p_path ); + } + else + { + BTIF_TRACE_WARNING2( "bta_fs_co_rmdir( app_id: %d ) for path_len: %d::out of memory", + app_id, path_len ); + return BTA_FS_CO_FAIL; + } + + if (NULL!= (tmp = strrchr(dirName, '/'))) + { + *tmp = '\0'; + } + if (stat(dirName, &buffer) == 0) + { + status = getAccess(6, &buffer, dirName); + } + else + { + free(dirName); +#if (TRUE==BTA_FS_DEBUG) + BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::stat(dirName) failed" ); +#endif + return BTA_FS_CO_FAIL; + } + + free(dirName); + if (status != BTA_FS_CO_OK) + { +#if (TRUE==BTA_FS_DEBUG) + BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::getAccess(dirName) FAILED"); +#endif + return status; + } + + if (stat(p_path, &buffer) == 0) + { + status = getAccess(6, &buffer, (char*)p_path); + } + else + { +#if (TRUE==BTA_FS_DEBUG) + BTIF_TRACE_WARNING0( "bta_fs_co_rmdir()::stat(p_path) FAILED"); +#endif + return BTA_FS_CO_FAIL; + } + + if (status != BTA_FS_CO_OK) + { +#if (TRUE==BTA_FS_DEBUG) + BTIF_TRACE_DEBUG0( "bta_fs_co_rmdir()::getAccess(p_path) FAILED"); +#endif + return status; + } + //if ((rmdir (p_path)) != 0) + if (del_path(p_path) != 0) + { + err = errno; + BTIF_TRACE_WARNING1( "bta_fs_co_rmdir():rmdir/del_path FAILED with err: %d", err ); + if (err == EACCES) + status = BTA_FS_CO_EACCES; + else if (err == ENOTEMPTY) + status = BTA_FS_CO_ENOTEMPTY; + else + status = BTA_FS_CO_FAIL; + } + return (status); +} + +/******************************************************************************* +** +** Function bta_fs_co_unlink +** +** Description This function is called to remove a file whose name +** is given by p_path. +** +** Parameters p_path - (input) name of file to remove (fully qualified path). +** app_id - (input) application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns (tBTA_FS_CO_STATUS) status of the call. +** [BTA_FS_CO_OK if successful] +** [BTA_FS_CO_EACCES if read-only] +** [BTA_FS_CO_FAIL otherwise] +** +*******************************************************************************/ +tBTA_FS_CO_STATUS bta_fs_co_unlink(const char *p_path, UINT8 app_id) +{ + BTIF_TRACE_DEBUG0("bta_fs_co_unlink"); + int err; + tBTA_FS_CO_STATUS status = BTA_FS_CO_OK; + char *dirName, *tmp=NULL; + struct stat buffer; + + if(! p_path) + return BTA_FS_CO_FAIL; + + /* buffer needs to be NULL terminated - so add one more byte to be zero'd out */ +#if 0 + dirName= (char*) calloc(1, strlen(p_path)); /* <--- this can cause problems */ +#else + dirName= (char*) calloc(1, strlen(p_path) + 1); +#endif + + strncpy(dirName, p_path, strlen(p_path)); + if((tmp=strrchr(dirName, '/'))) + { + *tmp='\0'; + } + if (stat(dirName, &buffer) == 0) + { + status=getAccess (6, &buffer, dirName); + free(dirName); + } + else + { + BTIF_TRACE_DEBUG0("stat() failed! "); + free(dirName); + return BTA_FS_CO_FAIL; + } + + if(status!= BTA_FS_CO_OK) + return status; + + if ((unlink (p_path)) != 0) + { + err = errno; + if (err == EACCES) + status = BTA_FS_CO_EACCES; + else + status = BTA_FS_CO_FAIL; + } + return (status); + +} + +/******************************************************************************* +** +** Function bta_fs_co_getdirentry +** +** Description This function is called to get a directory entry for the +** specified p_path. The first/next directory should be filled +** into the location specified by p_entry. +** +** Parameters p_path - directory to search (Fully qualified path) +** first_item - TRUE if first search, FALSE if next search +** (p_cur contains previous) +** p_entry (input/output) - Points to last entry data (valid when +** first_item is FALSE) +** evt - event that must be passed into the call-in function. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +** Note: Upon completion of the request, the status is passed +** in the bta_fs_ci_direntry() call-in function. +** BTA_FS_CO_OK is returned when p_entry is valid, +** BTA_FS_CO_EODIR is returned when no more entries [finished] +** BTA_FS_CO_FAIL is returned if an error occurred +** +*******************************************************************************/ +void bta_fs_co_getdirentry(const char *p_path, BOOLEAN first_item, + tBTA_FS_DIRENTRY *p_entry, UINT16 evt, UINT8 app_id) +{ + tBTA_FS_CO_STATUS co_status = BTA_FS_CO_FAIL; + int status = -1; /* '0' - success, '-1' - fail */ + struct tm *p_tm; + DIR *dir; + struct dirent *dirent; + struct stat buf; + char fullname[500]; + + BTIF_TRACE_DEBUG0("Entered bta_fs_co_getdirentry"); + + /* First item is to be retrieved */ + if (first_item) + { + BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: path = %s", p_path); + + dir = opendir(p_path); + if(dir == NULL) + { + BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dir is NULL so error out with errno=%d", errno); + co_status = BTA_FS_CO_EODIR; + bta_fs_ci_direntry(co_status, evt); + return; + } + + BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dir = %p", dir); + if((dirent = readdir(dir)) != NULL) + { + p_entry->refdata = (UINT32) dir; /* Save this for future searches */ + status = 0; + BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent); + } + else + { + BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent); + /* Close the search if there are no more items */ + closedir( (DIR*) p_entry->refdata); + co_status = BTA_FS_CO_EODIR; + } + } + else /* Get the next entry based on the p_ref data from previous search */ + { + if ((dirent = readdir((DIR*)p_entry->refdata)) == NULL) + { + /* Close the search if there are no more items */ + closedir( (DIR*) p_entry->refdata); + co_status = BTA_FS_CO_EODIR; + BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent); + } + else + { + BTIF_TRACE_DEBUG1("bta_fs_co_getdirentry: dirent = %p", dirent); + status = 0; + } + } + + if (status == 0) + { + BTIF_TRACE_DEBUG0("bta_fs_co_getdirentry: status = 0"); + + sprintf(fullname, "%s/%s", p_path, dirent->d_name); + + /* Load new values into the return structure (refdata is left untouched) */ + if (stat(fullname, &buf) == 0) { + p_entry->filesize = buf.st_size; + p_entry->mode = 0; /* Default is normal read/write file access */ + + if (S_ISDIR(buf.st_mode)) + p_entry->mode |= BTA_FS_A_DIR; + else + p_entry->mode |= BTA_FS_A_RDONLY; + + strcpy(p_entry->p_name, dirent->d_name); +#if 0 + fprintf(stderr, "bta_fs_co_getdirentry(): %s %9d %d\n", + dirent->d_name, + buf.st_size, + p_entry->mode); +#endif + p_tm = localtime((const time_t*)&buf.st_mtime); + if (p_tm != NULL) + { + sprintf(p_entry->crtime, "%04d%02d%02dT%02d%02d%02dZ", + p_tm->tm_year + 1900, /* Base Year ISO 6201 */ + p_tm->tm_mon + 1, /* month starts at 0 */ + p_tm->tm_mday, + p_tm->tm_hour, + p_tm->tm_min, + p_tm->tm_sec); + } + else + p_entry->crtime[0] = '\0'; /* No valid time */ +#if 0 + fprintf(stderr, "bta_fs_co_getdirentry(): %s %9d %d %s\n", + dirent->d_name, + p_entry->filesize, + p_entry->mode, + p_entry->crtime); +#endif + co_status = BTA_FS_CO_OK; + } else { + BTIF_TRACE_WARNING0("stat() failed! "); + co_status = BTA_FS_CO_EACCES; + } + } + BTIF_TRACE_DEBUG0("bta_fs_co_getdirentry: calling bta_fs_ci_getdirentry"); + + bta_fs_ci_direntry(co_status, evt); +} + + + + +/******************************************************************************* +** +** Function bta_fs_co_setdir +** +** Description This function is executed by BTA when the server changes the +** local path +** +** Parameters p_path - the new path. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_co_setdir(const char *p_path, UINT8 app_id) +{ + BTIF_TRACE_DEBUG2("Entered %s. New path: %s", __FUNCTION__, p_path); +} + +/******************************************************************************* +** OBEX14 Reliable Session not supported. Stub associated callouts. +******************************************************************************/ + +/******************************************************************************* +** +** Function bta_fs_co_resume +** +** Description This function is executed by BTA when resuming a session. +** This is used to retrieve the session ID and related information +** +** Parameters evt - event that must be passed into the call-in function. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +** Note: Upon completion of the request, the related session information, +** if successful, and an error code (tBTA_FS_CO_STATUS) +** are returned in the call-in function, bta_fs_ci_resume(). +** +*******************************************************************************/ +void bta_fs_co_resume(UINT16 evt, UINT8 app_id) +{ + BTIF_TRACE_WARNING0("[CO] bta_fs_co_resume - NOT implemented"); +} + +/******************************************************************************* +** +** Function bta_fs_co_set_perms +** +** Description This function is called to set the permission a file/directory +** with name as p_src_path. +** +** Parameters p_src_path - (input) name of file/directory to set permission (fully qualified path). +** p_perms - the permission . +** app_id - (input) application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns (tBTA_FS_CO_STATUS) status of the call. +** [BTA_FS_CO_OK if successful] +** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path); +** or p_src_path is a directory and p_dest_path specifies a different path. ] +** [BTA_FS_CO_FAIL otherwise] +** +*******************************************************************************/ +void bta_fs_co_set_perms(const char *p_src_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id) +{ + BTIF_TRACE_WARNING0("[CO] bta_fs_co_set_perms - NOT implemented"); +} + +/******************************************************************************* +** +** Function bta_fs_co_rename +** +** Description This function is called to move a file/directory whose +** name is given by p_src_path to p_dest_path. +** +** Parameters p_src_path - (input) name of file/directory to be moved (fully qualified path). +** p_dest_path - (input) new name of file/directory(fully qualified path). +** p_perms - the permission of the new object. +** app_id - (input) application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns (tBTA_FS_CO_STATUS) status of the call. +** [BTA_FS_CO_OK if successful] +** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path); +** or p_src_path is a directory and p_dest_path specifies a different path. ] +** [BTA_FS_CO_FAIL otherwise] +** +*******************************************************************************/ +void bta_fs_co_rename(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id) +{ + BTIF_TRACE_WARNING0("[CO] bta_fs_co_rename - NOT implemented"); +} + +/******************************************************************************* +** +** Function bta_fs_co_copy +** +** Description This function is called to copy a file/directory whose +** name is given by p_src_path to p_dest_path. +** +** Parameters p_src_path - (input) name of file/directory to be copied (fully qualified path). +** p_dest_path - (input) new name of file/directory(fully qualified path). +** p_perms - the permission of the new object. +** evt - event that must be passed into the call-in function. +** app_id - (input) application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns (tBTA_FS_CO_STATUS) status of the call. +** [BTA_FS_CO_OK if successful] +** [BTA_FS_CO_EIS_DIR if p_src_path is a folder] +** [BTA_FS_CO_EACCES if p_dest_path already exists or could not be created (invalid path); +** or p_src_path is a directory and p_dest_path specifies a different path. ] +** [BTA_FS_CO_FAIL otherwise] +** +*******************************************************************************/ +void bta_fs_co_copy(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id) +{ + BTIF_TRACE_WARNING0("[CO] bta_fs_co_copy - NOT implemented"); +} + +/******************************************************************************* +** +** Function bta_fs_co_resume_op +** +** Description This function is executed by BTA when a reliable session is +** resumed and there was an interrupted operation. +** +** Parameters offset - the session ID and related information. +** evt - event that must be passed into the call-in function. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_co_resume_op(UINT32 offset, UINT16 evt, UINT8 app_id) +{ + BTIF_TRACE_WARNING0("[CO] bta_fs_co_resume_op - NOT implemented"); +} + + +/******************************************************************************* +** +** Function bta_fs_co_session_info +** +** Description This function is executed by BTA when a reliable session is +** established (p_sess_info != NULL) or ended (p_sess_info == NULL). +** +** Parameters bd_addr - the peer address +** p_sess_info - the session ID and related information. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_co_session_info(BD_ADDR bd_addr, UINT8 *p_sess_info, UINT8 ssn, + tBTA_FS_CO_SESS_ST new_st, char *p_path, UINT8 *p_info, UINT8 app_id) +{ + BTIF_TRACE_WARNING0("[CO] bta_fs_co_session_info - NOT implemented"); +} + + +/******************************************************************************* +** +** Function bta_fs_co_suspend +** +** Description This function is executed by BTA when a reliable session is +** suspended. +** +** Parameters bd_addr - the peer address +** ssn - the session sequence number. +** info - the BTA specific information (like last active operation). +** p_offset- the location to receive object offset of the suspended session +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_co_suspend(BD_ADDR bd_addr, UINT8 *p_sess_info, UINT8 ssn, + UINT32 *p_timeout, UINT32 *p_offset, UINT8 info, UINT8 app_id) +{ + BTIF_TRACE_WARNING0("[CO] bta_fs_co_suspend - NOT implemented"); +} + +/******************************************************************************* +** +** Function bta_fs_co_sess_ssn +** +** Description This function is executed by BTA when resuming a session. +** This is used to inform call-out module if the ssn/file offset +** needs to be adjusted. +** +** Parameters ssn - the session sequence number of the first request +** after resume. +** app_id - application ID specified in the enable functions. +** It can be used to identify which profile is the caller +** of the call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_co_sess_ssn(int fd, UINT8 ssn, UINT8 app_id) +{ + BTIF_TRACE_WARNING0("[CO] bta_fs_co_suspend - NOT implemented"); +} + diff --git a/btif/co/bta_hh_co.c b/btif/co/bta_hh_co.c new file mode 100644 index 0000000..81414d2 --- /dev/null +++ b/btif/co/bta_hh_co.c @@ -0,0 +1,276 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +//#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)) + +#include <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <linux/uhid.h> +#include "btif_hh.h" +#include "bta_api.h" +#include "bta_hh_api.h" + + + +const char *dev_path = "/dev/uhid"; + + +/*Internal function to perform UHID write and error checking*/ +static int uhid_write(int fd, const struct uhid_event *ev) +{ + ssize_t ret; + ret = write(fd, ev, sizeof(*ev)); + if (ret < 0){ + int rtn = -errno; + APPL_TRACE_ERROR2("%s: Cannot write to uhid:%s",__FUNCTION__,strerror(errno)); + return rtn; + } else if (ret != sizeof(*ev)) { + APPL_TRACE_ERROR3("%s: Wrong size written to uhid: %ld != %lu", + __FUNCTION__, ret, sizeof(*ev)); + return -EFAULT; + } else { + return 0; + } +} + +void bta_hh_co_destroy(int fd) +{ + struct uhid_event ev; + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_DESTROY; + uhid_write(fd, &ev); + close(fd); +} + +int bta_hh_co_write(int fd, UINT8* rpt, UINT16 len) +{ + APPL_TRACE_DEBUG0("bta_hh_co_data: UHID write"); + struct uhid_event ev; + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_INPUT; + ev.u.input.size = len; + if(len > sizeof(ev.u.input.data)){ + APPL_TRACE_WARNING1("%s:report size greater than allowed size",__FUNCTION__); + return -1; + } + memcpy(ev.u.input.data, rpt, len); + return uhid_write(fd, &ev); + +} + + +/******************************************************************************* +** +** Function bta_hh_co_open +** +** Description When connection is opened, this call-out function is executed +** by HH to do platform specific initialization. +** +** Returns void. +*******************************************************************************/ +void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_mask, + UINT8 app_id) +{ + UINT32 i; + btif_hh_device_t *p_dev = NULL; + + if (dev_handle == BTA_HH_INVALID_HANDLE) { + APPL_TRACE_WARNING2("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle); + return; + } + + for (i = 0; i < BTIF_HH_MAX_HID; i++) { + p_dev = &btif_hh_cb.devices[i]; + if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) { + // We found a device with the same handle. Must be a device reconnected. + APPL_TRACE_WARNING2("%s: Found an existing device with the same handle " + "dev_status = %d",__FUNCTION__, + p_dev->dev_status); + APPL_TRACE_WARNING6("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__, + p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2], + p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]); + APPL_TRACE_WARNING4("%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d", + __FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id); + + if(p_dev->fd<0) { + p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC); + if (p_dev->fd < 0){ + APPL_TRACE_ERROR2("%s: Error: failed to open uhid, err:%s", + __FUNCTION__,strerror(errno)); + }else + APPL_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd); + } + + break; + } + p_dev = NULL; + } + + if (p_dev == NULL) { + // Did not find a device reconnection case. Find an empty slot now. + for (i = 0; i < BTIF_HH_MAX_HID; i++) { + if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) { + p_dev = &btif_hh_cb.devices[i]; + p_dev->dev_handle = dev_handle; + p_dev->attr_mask = attr_mask; + p_dev->sub_class = sub_class; + p_dev->app_id = app_id; + + btif_hh_cb.device_num++; + // This is a new device,open the uhid driver now. + p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC); + if (p_dev->fd < 0){ + APPL_TRACE_ERROR2("%s: Error: failed to open uhid, err:%s", + __FUNCTION__,strerror(errno)); + }else + APPL_TRACE_DEBUG2("%s: uhid fd = %d", __FUNCTION__, p_dev->fd); + + + break; + } + } + } + + if (p_dev == NULL) { + APPL_TRACE_ERROR1("%s: Error: too many HID devices are connected", __FUNCTION__); + return; + } + + p_dev->dev_status = BTHH_CONN_STATE_CONNECTED; + APPL_TRACE_DEBUG2("%s: Return device status %d", __FUNCTION__, p_dev->dev_status); +} + + +/******************************************************************************* +** +** Function bta_hh_co_close +** +** Description When connection is closed, this call-out function is executed +** by HH to do platform specific finalization. +** +** Parameters dev_handle - device handle +** app_id - application id +** +** Returns void. +*******************************************************************************/ +void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id) +{ + APPL_TRACE_WARNING3("%s: dev_handle = %d, app_id = %d", __FUNCTION__, dev_handle, app_id); +} + + +/******************************************************************************* +** +** Function bta_hh_co_data +** +** Description This function is executed by BTA when HID host receive a data +** report. +** +** Parameters dev_handle - device handle +** *p_rpt - pointer to the report data +** len - length of report data +** mode - Hid host Protocol Mode +** sub_clas - Device Subclass +** app_id - application id +** +** Returns void +*******************************************************************************/ +void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MODE mode, + UINT8 sub_class, UINT8 ctry_code, BD_ADDR peer_addr, UINT8 app_id) +{ + btif_hh_device_t *p_dev; + + APPL_TRACE_DEBUG6("%s: dev_handle = %d, subclass = 0x%02X, mode = %d, " + "ctry_code = %d, app_id = %d", + __FUNCTION__, dev_handle, sub_class, mode, ctry_code, app_id); + + p_dev = btif_hh_find_connected_dev_by_handle(dev_handle); + if (p_dev == NULL) { + APPL_TRACE_WARNING2("%s: Error: unknown HID device handle %d", __FUNCTION__, dev_handle); + return; + } + // Send the HID report to the kernel. + if (p_dev->fd >= 0) { + bta_hh_co_write(p_dev->fd, p_rpt, len); + }else { + APPL_TRACE_WARNING3("%s: Error: fd = %d, len = %d", __FUNCTION__, p_dev->fd, len); + } +} + + +/******************************************************************************* +** +** Function bta_hh_co_send_hid_info +** +** Description This function is called in btif_hh.c to process DSCP received. +** +** Parameters dev_handle - device handle +** dscp_len - report descriptor length +** *p_dscp - report descriptor +** +** Returns void +*******************************************************************************/ +void bta_hh_co_send_hid_info(btif_hh_device_t *p_dev, char *dev_name, UINT16 vendor_id, + UINT16 product_id, UINT16 version, UINT8 ctry_code, + int dscp_len, UINT8 *p_dscp) +{ + int result; + struct uhid_event ev; + + if (p_dev->fd < 0) { + APPL_TRACE_WARNING3("%s: Error: fd = %d, dscp_len = %d", __FUNCTION__, p_dev->fd, dscp_len); + return; + } + + APPL_TRACE_WARNING4("%s: fd = %d, name = [%s], dscp_len = %d", __FUNCTION__, + p_dev->fd, dev_name, dscp_len); + APPL_TRACE_WARNING5("%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x," + "ctry_code=0x%02x",__FUNCTION__, + vendor_id, product_id, + version, ctry_code); + +//Create and send hid descriptor to kernel + memset(&ev, 0, sizeof(ev)); + ev.type = UHID_CREATE; + strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1); + ev.u.create.rd_size = dscp_len; + ev.u.create.rd_data = p_dscp; + ev.u.create.bus = BUS_BLUETOOTH; + ev.u.create.vendor = vendor_id; + ev.u.create.product = product_id; + ev.u.create.version = version; + ev.u.create.country = ctry_code; + result = uhid_write(p_dev->fd, &ev); + + APPL_TRACE_WARNING4("%s: fd = %d, dscp_len = %d, result = %d", __FUNCTION__, + p_dev->fd, dscp_len, result); + + if (result) { + APPL_TRACE_WARNING2("%s: Error: failed to send DSCP, result = %d", __FUNCTION__, result); + + /* The HID report descriptor is corrupted. Close the driver. */ + close(p_dev->fd); + p_dev->fd = -1; + } +} + + diff --git a/btif/co/bta_hl_co.c b/btif/co/bta_hl_co.c new file mode 100644 index 0000000..a7a9061 --- /dev/null +++ b/btif/co/bta_hl_co.c @@ -0,0 +1,459 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the implementation file for the HeaLth device profile (HL) + * subsystem call-out functions. + * + ******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <time.h> +#include <fcntl.h> +#include <ctype.h> +#include <cutils/sockets.h> +#include <cutils/log.h> +#include "bta_api.h" +#include "btm_api.h" +#include "bta_sys.h" +#include "bta_hl_api.h" +#include "bta_hl_co.h" +#include "bta_hl_ci.h" +#include "btif_hl.h" + + + +/***************************************************************************** +** Constants and Data Types +*****************************************************************************/ +/************************** +** Common Definitions +***************************/ + + + + +/******************************************************************************* +** +** Function bta_hl_co_get_num_of_mdep +** +** Description This function is called to get the number of MDEPs for this +** application ID +** +** Parameters app_id - application ID +** p_num_of_mdep (output) - number of MDEP configurations supported +** by the application +** +** Returns Bloolean - TRUE success +** +*******************************************************************************/ +BOOLEAN bta_hl_co_get_num_of_mdep(UINT8 app_id, UINT8 *p_num_of_mdep) +{ + UINT8 app_idx; + BOOLEAN success = FALSE; + + if (btif_hl_find_app_idx(app_id, &app_idx)) + { + *p_num_of_mdep = p_btif_hl_cb->acb[app_idx].sup_feature.num_of_mdeps; + success = TRUE; + } + + + BTIF_TRACE_DEBUG3("%s success=%d num_mdeps=%d", + __FUNCTION__, success, *p_num_of_mdep ); + return success; +} + +/******************************************************************************* +** +** Function bta_hl_co_advrtise_source_sdp +** +** Description This function is called to find out whether the SOURCE MDEP +** configuration information should be advertize in the SDP or nopt +** +** Parameters app_id - application ID +** +** Returns Bloolean - TRUE advertise the SOURCE MDEP configuration +** information +** +*******************************************************************************/ +BOOLEAN bta_hl_co_advrtise_source_sdp(UINT8 app_id) +{ + BOOLEAN advertize_source_sdp=FALSE; + UINT8 app_idx; + + if (btif_hl_find_app_idx(app_id, &app_idx)) + { + advertize_source_sdp = p_btif_hl_cb->acb[app_idx].sup_feature.advertize_source_sdp; + } + + + BTIF_TRACE_DEBUG2("%s advertize_flag=%d", __FUNCTION__, advertize_source_sdp ); + + return advertize_source_sdp; +} +/******************************************************************************* +** +** Function bta_hl_co_get_mdep_config +** +** Description This function is called to get the supported feature +** configuration for the specified mdep index and it also assigns +** the MDEP ID for the specified mdep index +** +** Parameters app_id - HDP application ID +** mdep_idx - the mdep index +** mdep_id - the assigned MDEP ID for the specified medp_idx +** p_mdl_cfg (output) - pointer to the MDEP configuration +** +** +** Returns Bloolean - TRUE success +*******************************************************************************/ +BOOLEAN bta_hl_co_get_mdep_config(UINT8 app_id, + UINT8 mdep_idx, + tBTA_HL_MDEP_ID mdep_id, + tBTA_HL_MDEP_CFG *p_mdep_cfg) +{ + UINT8 idx ; + UINT8 app_idx; + BOOLEAN success = FALSE; + + BTIF_TRACE_DEBUG4("%s app_id=%d mdep_idx=%d mdep_id=%d", + __FUNCTION__, app_id,mdep_idx,mdep_id ); + + if (btif_hl_find_app_idx(app_id, &app_idx)) + { + idx = mdep_idx -1; + p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_id = mdep_id; + memcpy(p_mdep_cfg, + &p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_cfg, + sizeof(tBTA_HL_MDEP_CFG)); + + success = TRUE; + } + + BTIF_TRACE_DEBUG4("%s success=%d mdep_idx=%d mdep_id=%d", + __FUNCTION__, success, mdep_idx, mdep_id ); + + return success; +} + + +/******************************************************************************* +** +** Function bta_hl_co_get_echo_config +** +** Description This function is called to get the echo test +** maximum APDU size configurations +** +** Parameters app_id - HDP application ID +** p_echo_cfg (output) - pointer to the Echo test maximum APDU size +** configuration +** +** Returns Bloolean - TRUE success +*******************************************************************************/ +BOOLEAN bta_hl_co_get_echo_config(UINT8 app_id, + tBTA_HL_ECHO_CFG *p_echo_cfg) +{ + UINT8 app_idx; + BOOLEAN success = FALSE; + btif_hl_app_cb_t *p_acb; + tBTA_HL_SUP_FEATURE *p_sup; + + BTIF_TRACE_DEBUG2("%s app_id=%d",__FUNCTION__, app_id ); + + if (btif_hl_find_app_idx(app_id, &app_idx)) + { + p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx); + p_sup = &p_acb->sup_feature; + p_echo_cfg->max_rx_apdu_size = p_sup->echo_cfg.max_rx_apdu_size; + p_echo_cfg->max_tx_apdu_size = p_sup->echo_cfg.max_tx_apdu_size; + success = TRUE; + } + + BTIF_TRACE_DEBUG4("%s success=%d max tx_size=%d rx_size=%d", + __FUNCTION__, success, p_echo_cfg->max_tx_apdu_size, + p_echo_cfg->max_rx_apdu_size ); + + return success; +} + + +/******************************************************************************* +** +** Function bta_hl_co_save_mdl +** +** Description This function is called to save a MDL configuration item in persistent +** storage +** +** Parameters app_id - HDP application ID +** item_idx - the MDL configuration storage index +** p_mdl_cfg - pointer to the MDL configuration data +** +** Returns void +** +*******************************************************************************/ +void bta_hl_co_save_mdl(UINT8 app_id, UINT8 item_idx, tBTA_HL_MDL_CFG *p_mdl_cfg ) +{ + + BTIF_TRACE_DEBUG6("%s app_id=%d, item_idx=%d active=%d mdl_id=%d time=%d", + __FUNCTION__, app_id, item_idx, + p_mdl_cfg->active, + p_mdl_cfg->mdl_id, + p_mdl_cfg->time); + + + btif_hl_save_mdl_cfg(app_id, item_idx, p_mdl_cfg); + +} + +/******************************************************************************* +** +** Function bta_hl_co_delete_mdl +** +** Description This function is called to delete a MDL configuration item in persistent +** storage +** +** Parameters app_id - HDP application ID +** item_idx - the MDL configuration storage index +** +** Returns void +** +*******************************************************************************/ +void bta_hl_co_delete_mdl(UINT8 app_id, UINT8 item_idx) +{ + + + BTIF_TRACE_DEBUG3("%s app_id=%d, item_idx=%d", __FUNCTION__, app_id, item_idx); + + btif_hl_delete_mdl_cfg(app_id, item_idx); + + +} + +/******************************************************************************* +** +** Function bta_hl_co_get_mdl_config +** +** Description This function is called to get the MDL configuration +** from the persistent memory. This function shall only be called +*8 once after the device is powered up +** +** Parameters app_id - HDP application ID +** buffer_size - the unit of the buffer size is sizeof(tBTA_HL_MDL_CFG) +** p_mdl_buf - Point to the starting location of the buffer +** +** Returns BOOLEAN +** +** +*******************************************************************************/ +BOOLEAN bta_hl_co_load_mdl_config (UINT8 app_id, UINT8 buffer_size, + tBTA_HL_MDL_CFG *p_mdl_buf ) +{ + BOOLEAN result = TRUE; + UINT8 i; + tBTA_HL_MDL_CFG *p; + + BTIF_TRACE_DEBUG3("%s app_id=%d, num_items=%d", + __FUNCTION__, app_id, buffer_size); + + if (buffer_size > BTA_HL_NUM_MDL_CFGS) + { + result = FALSE; + return result; + } + result = btif_hl_load_mdl_config(app_id, buffer_size, p_mdl_buf); + + if (result) + { + for (i=0, p=p_mdl_buf; i<buffer_size; i++, p++ ) + { + if (p->active) + { + BTIF_TRACE_DEBUG6("i=%d mdl_id=0x%x dch_mode=%d local mdep_role=%d mdep_id=%d mtu=%d", + i, p->mdl_id, p->dch_mode, p->local_mdep_role, p->local_mdep_role, p->mtu); + } + } + } + + BTIF_TRACE_DEBUG3("%s success=%d num_items=%d", __FUNCTION__, result, buffer_size); + + return result; +} + +/******************************************************************************* +** +** Function bta_hl_co_get_tx_data +** +** Description Get the data to be sent +** +** Parameters app_id - HDP application ID +** mdl_handle - MDL handle +** buf_size - the size of the buffer +** p_buf - the buffer pointer +** evt - the evt to be passed back to the HL in the +** bta_hl_ci_get_tx_data call-in function +** +** Returns Void +** +*******************************************************************************/ +void bta_hl_co_get_tx_data (UINT8 app_id, tBTA_HL_MDL_HANDLE mdl_handle, + UINT16 buf_size, UINT8 *p_buf, UINT16 evt) +{ + UINT8 app_idx, mcl_idx, mdl_idx; + btif_hl_mdl_cb_t *p_dcb; + tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL; + + BTIF_TRACE_DEBUG4("%s app_id=%d mdl_handle=0x%x buf_size=%d", + __FUNCTION__, app_id, mdl_handle, buf_size); + + if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx, &mdl_idx)) + { + p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + + if (p_dcb->tx_size <= buf_size ) + { + memcpy(p_buf, p_dcb->p_tx_pkt, p_dcb->tx_size); + btif_hl_free_buf((void **) &p_dcb->p_tx_pkt); + p_dcb->tx_size = 0; + status = BTA_HL_STATUS_OK; + } + } + + + bta_hl_ci_get_tx_data(mdl_handle, status, evt); + +} + + +/******************************************************************************* +** +** Function bta_hl_co_put_rx_data +** +** Description Put the received data +** +** Parameters app_id - HDP application ID +** mdl_handle - MDL handle +** data_size - the size of the data +** p_data - the data pointer +** evt - the evt to be passed back to the HL in the +** bta_hl_ci_put_rx_data call-in function +** +** Returns Void +** +*******************************************************************************/ +void bta_hl_co_put_rx_data (UINT8 app_id, tBTA_HL_MDL_HANDLE mdl_handle, + UINT16 data_size, UINT8 *p_data, UINT16 evt) +{ + UINT8 app_idx, mcl_idx, mdl_idx; + btif_hl_mdl_cb_t *p_dcb; + tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL; + int r; + BTIF_TRACE_DEBUG4("%s app_id=%d mdl_handle=0x%x data_size=%d", + __FUNCTION__,app_id, mdl_handle, data_size); + + if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx, &mdl_idx)) + { + p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + + if ((p_dcb->p_rx_pkt = (UINT8 *)btif_hl_get_buf(data_size)) != NULL) + { + memcpy(p_dcb->p_rx_pkt, p_data, data_size); + if (p_dcb->p_scb) + { + BTIF_TRACE_DEBUG4("app_idx=%d mcl_idx=0x%x mdl_idx=0x%x data_size=%d", + app_idx, mcl_idx, mdl_idx, data_size); + r = send(p_dcb->p_scb->socket_id[1], p_dcb->p_rx_pkt, data_size, 0); + + if (r == data_size) + { + BTIF_TRACE_DEBUG1("socket send success data_size=%d", data_size); + status = BTA_HL_STATUS_OK; + } + else + { + BTIF_TRACE_ERROR2("socket send failed r=%d data_size=%d",r, data_size); + } + + + } + btif_hl_free_buf((void **) &p_dcb->p_rx_pkt); + } + } + + bta_hl_ci_put_rx_data(mdl_handle, status, evt); +} + + +/******************************************************************************* +** +** Function bta_hl_co_get_tx_data +** +** Description Get the Echo data to be sent +** +** Parameters app_id - HDP application ID +** mcl_handle - MCL handle +** buf_size - the size of the buffer +** p_buf - the buffer pointer +** evt - the evt to be passed back to the HL in the +** bta_hl_ci_get_tx_data call-in function +** +** Returns Void +** +*******************************************************************************/ +void bta_hl_co_get_echo_data (UINT8 app_id, tBTA_HL_MCL_HANDLE mcl_handle, + UINT16 buf_size, UINT8 *p_buf, UINT16 evt) +{ + tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL; + + BTIF_TRACE_ERROR1("%s not supported",__FUNCTION__); + bta_hl_ci_get_echo_data(mcl_handle, status, evt); +} + + +/******************************************************************************* +** +** Function bta_hl_co_put_echo_data +** +** Description Put the received loopback echo data +** +** Parameters app_id - HDP application ID +** mcl_handle - MCL handle +** data_size - the size of the data +** p_data - the data pointer +** evt - the evt to be passed back to the HL in the +** bta_hl_ci_put_echo_data call-in function +** +** Returns Void +** +*******************************************************************************/ +void bta_hl_co_put_echo_data (UINT8 app_id, tBTA_HL_MCL_HANDLE mcl_handle, + UINT16 data_size, UINT8 *p_data, UINT16 evt) +{ + tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL; + + BTIF_TRACE_ERROR1("%s not supported",__FUNCTION__); + bta_hl_ci_put_echo_data(mcl_handle, status, evt); +} + diff --git a/btif/co/bta_pan_co.c b/btif/co/bta_pan_co.c new file mode 100644 index 0000000..e78a5f8 --- /dev/null +++ b/btif/co/bta_pan_co.c @@ -0,0 +1,334 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/************************************************************************************ + * + * Filename: bta_pan_co.c + * + * Description: PAN stack callout api + * + * + ***********************************************************************************/ +#include "bta_api.h" +#include "bta_pan_api.h" +#include "bta_pan_ci.h" +#include "bta_pan_co.h" +#include "pan_api.h" +#include "gki.h" +//#include "btui.h" +//#include "btui_int.h" +#include <hardware/bluetooth.h> +#include <hardware/bt_pan.h> +#include "btif_pan_internal.h" +#include "bd.h" + + +#include <cutils/log.h> +#define info(fmt, ...) ALOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__) +#define debug(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__) +#define warn(fmt, ...) ALOGW ("## WARNING : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__) +#define error(fmt, ...) ALOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__) +#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__) + + + + +/******************************************************************************* +** +** Function bta_pan_co_init +** +** Description +** +** +** Returns Data flow mask. +** +*******************************************************************************/ +UINT8 bta_pan_co_init(UINT8 *q_level) +{ + + ALOGD("bta_pan_co_init"); + + /* set the q_level to 30 buffers */ + *q_level = 30; + + //return (BTA_PAN_RX_PULL | BTA_PAN_TX_PULL); + return (BTA_PAN_RX_PUSH_BUF | BTA_PAN_RX_PUSH | BTA_PAN_TX_PULL); +} + + + + +/******************************************************************************* +** +** Function bta_pan_co_open +** +** Description +** +** +** +** +** +** Returns void +** +*******************************************************************************/ + +void bta_pan_co_open(UINT16 handle, UINT8 app_id, tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role, BD_ADDR peer_addr) +{ + ALOGD("bta_pan_co_open:app_id:%d, local_role:%d, peer_role:%d, handle:%d", + app_id, local_role, peer_role, handle); + btpan_conn_t* conn = btpan_find_conn_addr(peer_addr); + if(conn == NULL) + conn = btpan_new_conn(handle, peer_addr, local_role, peer_role); + if(conn) + { + ALOGD("bta_pan_co_open:tap_fd:%d, open_count:%d, conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d", + btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, handle, conn->local_role, conn->remote_role); + //refresh the role & bt address + + btpan_cb.open_count++; + conn->handle = handle; + //bdcpy(conn->peer, peer_addr); + if(btpan_cb.tap_fd < 0) + { + btpan_cb.tap_fd = btpan_tap_open(); + if(btpan_cb.tap_fd >= 0) + create_tap_read_thread(btpan_cb.tap_fd); + } + if(btpan_cb.tap_fd >= 0) + { + conn->state = PAN_STATE_OPEN; + bta_pan_ci_rx_ready(handle); + } + } +} + + +/******************************************************************************* +** +** Function bta_pan_co_close +** +** Description This function is called by PAN when a connection to a +** peer is closed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_co_close(UINT16 handle, UINT8 app_id) +{ + ALOGD("bta_pan_co_close:app_id:%d, handle:%d", app_id, handle); + btpan_conn_t* conn = btpan_find_conn_handle(handle); + if(conn && conn->state == PAN_STATE_OPEN) + { + ALOGD("bta_pan_co_close"); + + // let bta close event reset this handle as it needs + // the handle to find the connection upon CLOSE + //conn->handle = -1; + conn->state = PAN_STATE_CLOSE; + btpan_cb.open_count--; + + if(btpan_cb.open_count == 0) + { + destroy_tap_read_thread(); + if(btpan_cb.tap_fd != -1) + { + btpan_tap_close(btpan_cb.tap_fd); + btpan_cb.tap_fd = -1; + } + } + } +} + +/******************************************************************************* +** +** Function bta_pan_co_tx_path +** +** Description This function is called by PAN to transfer data on the +** TX path; that is, data being sent from BTA to the phone. +** This function is used when the TX data path is configured +** to use the pull interface. The implementation of this +** function will typically call Bluetooth stack functions +** PORT_Read() or PORT_ReadData() to read data from RFCOMM +** and then a platform-specific function to send data that +** data to the phone. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_co_tx_path(UINT16 handle, UINT8 app_id) +{ + BT_HDR *p_buf; + UINT8 i; + BD_ADDR src; + BD_ADDR dst; + UINT16 protocol; + BOOLEAN ext; + BOOLEAN forward; + + ALOGD("bta_pan_co_tx_path, handle:%d, app_id:%d", handle, app_id); + + btpan_conn_t* conn = btpan_find_conn_handle(handle); + if(conn && conn->state != PAN_STATE_OPEN) + { + ALOGE("bta_pan_co_tx_path: cannot find pan connction or conn is not opened, conn:%p, conn->state:%d", conn, conn->state); + return; + } + do + { + + /* read next data buffer from pan */ + if ((p_buf = bta_pan_ci_readbuf(handle, src, dst, &protocol, + &ext, &forward))) + { + ALOGD("bta_pan_co_tx_path, calling btapp_tap_send, p_buf->len:%d, offset:%d", p_buf->len, p_buf->offset); + if(is_empty_eth_addr(conn->eth_addr) && is_valid_bt_eth_addr(src)) + { + ALOGD("pan bt peer addr: %02x:%02x:%02x:%02x:%02x:%02x, update its ethernet addr: %02x:%02x:%02x:%02x:%02x:%02x", + conn->peer[0], conn->peer[1], conn->peer[2], conn->peer[3],conn->peer[4], conn->peer[5], + src[0], src[1], src[2], src[3],src[4], src[5]); + memcpy(conn->eth_addr, src, sizeof(conn->eth_addr)); + + } + btpan_tap_send(btpan_cb.tap_fd, src, dst, protocol, (char*)(p_buf + 1) + p_buf->offset, p_buf->len, ext, forward); + GKI_freebuf(p_buf); + } + + } while (p_buf != NULL); + +} + +/******************************************************************************* +** +** Function bta_pan_co_rx_path +** +** Description +** +** +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_co_rx_path(UINT16 handle, UINT8 app_id) +{ + + + UINT8 i; + + ALOGD("bta_pan_co_rx_path not used"); + + +} + +/******************************************************************************* +** +** Function bta_pan_co_tx_write +** +** Description This function is called by PAN to send data to the phone +** when the TX path is configured to use a push interface. +** The implementation of this function must copy the data to +** the phone's memory. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_co_tx_write(UINT16 handle, UINT8 app_id, BD_ADDR src, BD_ADDR dst, UINT16 protocol, UINT8 *p_data, + UINT16 len, BOOLEAN ext, BOOLEAN forward) +{ + ALOGD("bta_pan_co_tx_write not used"); + +} + +/******************************************************************************* +** +** Function bta_pan_co_tx_writebuf +** +** Description This function is called by PAN to send data to the phone +** when the TX path is configured to use a push interface with +** zero copy. The phone must free the buffer using function +** GKI_freebuf() when it is through processing the buffer. +** +** +** Returns TRUE if flow enabled +** +*******************************************************************************/ +void bta_pan_co_tx_writebuf(UINT16 handle, UINT8 app_id, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf, + BOOLEAN ext, BOOLEAN forward) +{ + + ALOGD("bta_pan_co_tx_writebuf not used"); + + +} + +/******************************************************************************* +** +** Function bta_pan_co_rx_flow +** +** Description This function is called by PAN to enable or disable +** data flow on the RX path when it is configured to use +** a push interface. If data flow is disabled the phone must +** not call bta_pan_ci_rx_write() or bta_pan_ci_rx_writebuf() +** until data flow is enabled again. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_co_rx_flow(UINT16 handle, UINT8 app_id, BOOLEAN enable) +{ + + ALOGD("bta_pan_co_rx_flow, enabled:%d, not used", enable); + +} + + +/******************************************************************************* +** +** Function bta_pan_co_filt_ind +** +** Description protocol filter indication from peer device +** +** Returns void +** +*******************************************************************************/ +void bta_pan_co_pfilt_ind(UINT16 handle, BOOLEAN indication, tBTA_PAN_STATUS result, + UINT16 len, UINT8 *p_filters) +{ + ALOGD("bta_pan_co_pfilt_ind"); + +} +/******************************************************************************* +** +** Function bta_pan_co_mfilt_ind +** +** Description multicast filter indication from peer device +** +** Returns void +** +*******************************************************************************/ +void bta_pan_co_mfilt_ind(UINT16 handle, BOOLEAN indication, tBTA_PAN_STATUS result, + UINT16 len, UINT8 *p_filters) +{ + + ALOGD("bta_pan_co_mfilt_ind"); +} + diff --git a/btif/co/bta_sys_co.c b/btif/co/bta_sys_co.c new file mode 100644 index 0000000..b7768ad --- /dev/null +++ b/btif/co/bta_sys_co.c @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#include "bta_sys.h" +#include "bta_sys_ci.h" + +/******************************************************************************* +** +** Function bta_sys_hw_co_enable +** +** Description This function is called by the stack to power up the HW +** +** Returns void +** +*******************************************************************************/ +void bta_sys_hw_co_enable( tBTA_SYS_HW_MODULE module ) +{ + /* platform specific implementation to power-up the HW */ + + + /* if no client/server asynchronous system like linux-based OS, directly call the ci here */ + bta_sys_hw_ci_enabled( module ); +} + + +/******************************************************************************* +** +** Function bta_sys_hw_co_disable +** +** Description This function is called by the stack to power down the HW +** +** Returns void +** +*******************************************************************************/ +void bta_sys_hw_co_disable( tBTA_SYS_HW_MODULE module ) +{ + /* platform specific implementation to power-down the HW */ + + + /* if no client/server asynchronous system like linux-based OS, directly call the ci here */ + bta_sys_hw_ci_disabled( module ); + +} |