diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2012-12-12 16:00:35 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2012-12-12 16:00:35 -0800 |
commit | 5738f83aeb59361a0a2eda2460113f6dc9194271 (patch) | |
tree | bf9fb1c890a681253207fe5d48e2cd56b94de3a7 /bta | |
download | external_bluetooth_bluedroid-5738f83aeb59361a0a2eda2460113f6dc9194271.zip external_bluetooth_bluedroid-5738f83aeb59361a0a2eda2460113f6dc9194271.tar.gz external_bluetooth_bluedroid-5738f83aeb59361a0a2eda2460113f6dc9194271.tar.bz2 |
Snapshot cdeccf6fdd8c2d494ea2867cb37a025bf8879baf
Change-Id: Ia2de32ccb97a9641462c72363b0a8c4288f4f36d
Diffstat (limited to 'bta')
115 files changed, 68145 insertions, 0 deletions
diff --git a/bta/Android.mk b/bta/Android.mk new file mode 100644 index 0000000..7d1c19e --- /dev/null +++ b/bta/Android.mk @@ -0,0 +1,104 @@ +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true) +LOCAL_CFLAGS += \ + -DBOARD_HAVE_BLUETOOTH_BCM +endif +LOCAL_CFLAGS += -DBUILDCFG $(bdroid_CFLAGS) + +LOCAL_PRELINK_MODULE:=false +LOCAL_SRC_FILES:= \ + ./dm/bta_dm_ci.c \ + ./dm/bta_dm_act.c \ + ./dm/bta_dm_pm.c \ + ./dm/bta_dm_main.c \ + ./dm/bta_dm_cfg.c \ + ./dm/bta_dm_api.c \ + ./dm/bta_dm_sco.c \ + ./gatt/bta_gattc_api.c \ + ./gatt/bta_gatts_act.c \ + ./gatt/bta_gatts_main.c \ + ./gatt/bta_gattc_utils.c \ + ./gatt/bta_gattc_ci.c \ + ./gatt/bta_gatts_api.c \ + ./gatt/bta_gattc_main.c \ + ./gatt/bta_gattc_act.c \ + ./gatt/bta_gattc_cache.c \ + ./gatt/bta_gatts_utils.c \ + ./ag/bta_ag_sdp.c \ + ./ag/bta_ag_sco.c \ + ./ag/bta_ag_cfg.c \ + ./ag/bta_ag_main.c \ + ./ag/bta_ag_api.c \ + ./ag/bta_ag_rfc.c \ + ./ag/bta_ag_act.c \ + ./ag/bta_ag_cmd.c \ + ./ag/bta_ag_ci.c \ + ./ag/bta_ag_at.c \ + ./hh/bta_hh_cfg.c \ + ./hh/bta_hh_act.c \ + ./hh/bta_hh_api.c \ + ./hh/bta_hh_utils.c \ + ./hh/bta_hh_main.c \ + ./pb/bta_pbs_cfg.c \ + ./fs/bta_fs_ci.c \ + ./fs/bta_fs_cfg.c \ + ./pan/bta_pan_main.c \ + ./pan/bta_pan_ci.c \ + ./pan/bta_pan_act.c \ + ./pan/bta_pan_api.c \ + ./av/bta_av_act.c \ + ./av/bta_av_ci.c \ + ./av/bta_av_api.c \ + ./av/bta_av_aact.c \ + ./av/bta_av_main.c \ + ./av/bta_av_cfg.c \ + ./av/bta_av_ssm.c \ + ./av/bta_av_sbc.c \ + ./ar/bta_ar.c \ + ./hl/bta_hl_act.c \ + ./hl/bta_hl_api.c \ + ./hl/bta_hl_main.c \ + ./hl/bta_hl_utils.c \ + ./hl/bta_hl_sdp.c \ + ./hl/bta_hl_ci.c \ + ./sys/bta_sys_main.c \ + ./sys/bta_sys_ci.c \ + ./sys/bta_sys_conn.c \ + ./sys/bta_sys_cfg.c \ + ./sys/ptim.c \ + ./sys/bd.c \ + ./sys/utl.c \ + ./jv/bta_jv_act.c \ + ./jv/bta_jv_cfg.c \ + ./jv/bta_jv_main.c \ + ./jv/bta_jv_api.c + +LOCAL_MODULE := libbt-brcm_bta +LOCAL_MODULE_CLASS := STATIC_LIBRARIES +LOCAL_MODULE_TAGS := optional +LOCAL_SHARED_LIBRARIES := libcutils libc + +LOCAL_C_INCLUDES+= . \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/sys \ + $(LOCAL_PATH)/dm \ + $(LOCAL_PATH)/../gki/common \ + $(LOCAL_PATH)/../gki/ulinux \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../stack/include \ + $(LOCAL_PATH)/../stack/btm \ + $(LOCAL_PATH)/../hcis \ + $(LOCAL_PATH)/../hcis/patchram \ + $(LOCAL_PATH)/../udrv/include \ + $(LOCAL_PATH)/../brcm/include \ + $(bdroid_C_INCLUDES) \ + + +include $(BUILD_STATIC_LIBRARY) + +endif # TARGET_SIMULATOR != true diff --git a/bta/ag/bta_ag_act.c b/bta/ag/bta_ag_act.c new file mode 100644 index 0000000..5f72444 --- /dev/null +++ b/bta/ag/bta_ag_act.c @@ -0,0 +1,867 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains action functions for the audio gateway. + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bd.h" +#include "bta_sys.h" +#include "bta_ag_api.h" +#include "bta_ag_co.h" +#include "bta_ag_int.h" +#include "port_api.h" +#include "utl.h" +#include <string.h> +#include "bta_dm_int.h" +#include "l2c_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* maximum length of data to read from RFCOMM */ +#define BTA_AG_RFC_READ_MAX 512 + +/* maximum AT command length */ +#define BTA_AG_CMD_MAX 512 + +const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX] = +{ + UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, + UUID_SERVCLASS_AG_HANDSFREE +}; + +const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX] = +{ + BTM_SEC_SERVICE_HEADSET_AG, + BTM_SEC_SERVICE_AG_HANDSFREE +}; + +const tBTA_SERVICE_ID bta_ag_svc_id[BTA_AG_NUM_IDX] = +{ + BTA_HSP_SERVICE_ID, + BTA_HFP_SERVICE_ID +}; + +const tBTA_SERVICE_MASK bta_ag_svc_mask[BTA_AG_NUM_IDX] = +{ + BTA_HSP_SERVICE_MASK, + BTA_HFP_SERVICE_MASK +}; + +typedef void (*tBTA_AG_ATCMD_CBACK)(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type, + char *p_arg, INT16 int_arg); + +const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] = +{ + bta_ag_at_hsp_cback, + bta_ag_at_hfp_cback +}; + +/******************************************************************************* +** +** Function bta_ag_cback_open +** +** Description Send open callback event to application. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_cback_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data, tBTA_AG_STATUS status) +{ + tBTA_AG_OPEN open; + + /* call app callback with open event */ + open.hdr.handle = bta_ag_scb_to_idx(p_scb); + open.hdr.app_id = p_scb->app_id; + open.status = status; + open.service_id = bta_ag_svc_id[p_scb->conn_service]; + if(p_data) + { + /* if p_data is provided then we need to pick the bd address from the open api structure */ + bdcpy(open.bd_addr, p_data->api_open.bd_addr); + } + else + { + bdcpy(open.bd_addr, p_scb->peer_addr); + } + + (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG *) &open); +} + +/******************************************************************************* +** +** Function bta_ag_register +** +** Description This function initializes values of the AG cb and sets up +** the SDP record for the services. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + tBTA_AG_REGISTER reg; + + /* initialize control block */ + p_scb->reg_services = p_data->api_register.services; + p_scb->serv_sec_mask = p_data->api_register.sec_mask; + p_scb->features = p_data->api_register.features; + p_scb->app_id = p_data->api_register.app_id; + + /* create SDP records */ + bta_ag_create_records(p_scb, p_data); + + /* start RFCOMM servers */ + bta_ag_start_servers(p_scb, p_scb->reg_services); + + /* call app callback with register event */ + reg.hdr.handle = bta_ag_scb_to_idx(p_scb); + reg.hdr.app_id = p_scb->app_id; + reg.status = BTA_AG_SUCCESS; + (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) ®); +} + +/******************************************************************************* +** +** Function bta_ag_deregister +** +** Description This function removes the sdp records, closes the RFCOMM +** servers, and deallocates the service control block. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* set dealloc */ + p_scb->dealloc = TRUE; + + /* remove sdp records */ + bta_ag_del_records(p_scb, p_data); + + /* remove rfcomm servers */ + bta_ag_close_servers(p_scb, p_scb->reg_services); + + /* dealloc */ + bta_ag_scb_dealloc(p_scb); +} + +/******************************************************************************* +** +** Function bta_ag_start_dereg +** +** Description Start a deregister event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* set dealloc */ + p_scb->dealloc = TRUE; + + /* remove sdp records */ + bta_ag_del_records(p_scb, p_data); +} + +/******************************************************************************* +** +** Function bta_ag_start_open +** +** Description This starts an AG open. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + BD_ADDR pending_bd_addr; + + /* store parameters */ + if (p_data) + { + bdcpy(p_scb->peer_addr, p_data->api_open.bd_addr); + p_scb->open_services = p_data->api_open.services; + p_scb->cli_sec_mask = p_data->api_open.sec_mask; + } + + /* Check if RFCOMM has any incoming connection to avoid collision. */ + if (PORT_IsOpening (pending_bd_addr)) + { + /* Let the incoming connection goes through. */ + /* Issue collision for this scb for now. */ + /* We will decide what to do when we find incoming connetion later. */ + bta_ag_collision_cback (0, BTA_ID_AG, 0, p_scb->peer_addr); + return; + } + + /* close servers */ + bta_ag_close_servers(p_scb, p_scb->reg_services); + + /* set role */ + p_scb->role = BTA_AG_INT; + + /* do service search */ + bta_ag_do_disc(p_scb, p_scb->open_services); +} + +/******************************************************************************* +** +** Function bta_ag_disc_int_res +** +** Description This function handles a discovery result when initiator. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + UINT16 event = BTA_AG_DISC_FAIL_EVT; + + APPL_TRACE_DEBUG1 ("bta_ag_disc_int_res: Status: %d", p_data->disc_result.status); + + /* if found service */ + if (p_data->disc_result.status == SDP_SUCCESS || + p_data->disc_result.status == SDP_DB_FULL) + { + /* get attributes */ + if (bta_ag_sdp_find_attr(p_scb, p_scb->open_services)) + { + /* set connected service */ + p_scb->conn_service = bta_ag_service_to_idx(p_scb->open_services); + + /* send ourselves sdp ok event */ + event = BTA_AG_DISC_OK_EVT; + } + } + + /* free discovery db */ + bta_ag_free_db(p_scb, p_data); + + /* if service not found check if we should search for other service */ + if ((event == BTA_AG_DISC_FAIL_EVT) && + (p_data->disc_result.status == SDP_SUCCESS || + p_data->disc_result.status == SDP_DB_FULL || + p_data->disc_result.status == SDP_NO_RECS_MATCH)) + { + if ((p_scb->open_services & BTA_HFP_SERVICE_MASK) && + (p_scb->open_services & BTA_HSP_SERVICE_MASK)) + { + /* search for HSP */ + p_scb->open_services &= ~BTA_HFP_SERVICE_MASK; + bta_ag_do_disc(p_scb, p_scb->open_services); + } + else if ((p_scb->open_services & BTA_HSP_SERVICE_MASK) && + (p_scb->hsp_version == HSP_VERSION_1_2)) + { + /* search for UUID_SERVCLASS_HEADSET for HSP 1.0 device */ + p_scb->hsp_version = HSP_VERSION_1_0; + bta_ag_do_disc(p_scb, p_scb->open_services); + } + else + { + /* send ourselves sdp ok/fail event */ + bta_ag_sm_execute(p_scb, event, p_data); + } + } + else + { + /* send ourselves sdp ok/fail event */ + bta_ag_sm_execute(p_scb, event, p_data); + } + +} + +/******************************************************************************* +** +** Function bta_ag_disc_acp_res +** +** Description This function handles a discovery result when acceptor. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* if found service */ + if (p_data->disc_result.status == SDP_SUCCESS || + p_data->disc_result.status == SDP_DB_FULL) + { + /* get attributes */ + bta_ag_sdp_find_attr(p_scb, bta_ag_svc_mask[p_scb->conn_service]); + } + + /* free discovery db */ + bta_ag_free_db(p_scb, p_data); +} + +/******************************************************************************* +** +** Function bta_ag_disc_fail +** +** Description This function handles a discovery failure. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* reopen registered servers */ + bta_ag_start_servers(p_scb, p_scb->reg_services); + + /* reinitialize stuff */ + + /* call open cback w. failure */ + bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_SDP); +} + +/******************************************************************************* +** +** Function bta_ag_open_fail +** +** Description open connection failed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* call open cback w. failure */ + bta_ag_cback_open(p_scb, p_data, BTA_AG_FAIL_RESOURCES); +} + +/******************************************************************************* +** +** Function bta_ag_rfc_fail +** +** Description RFCOMM connection failed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* reinitialize stuff */ + p_scb->conn_handle = 0; + p_scb->conn_service = 0; + p_scb->peer_features = 0; +#if (BTM_WBS_INCLUDED == TRUE ) + p_scb->peer_codecs = BTA_AG_CODEC_NONE; + p_scb->sco_codec = BTA_AG_CODEC_NONE; +#endif + p_scb->role = 0; + p_scb->svc_conn = FALSE; + p_scb->hsp_version = HSP_VERSION_1_2; + + /* reopen registered servers */ + bta_ag_start_servers(p_scb, p_scb->reg_services); + + /* call open cback w. failure */ + bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_RFCOMM); +} + +/******************************************************************************* +** +** Function bta_ag_rfc_close +** +** Description RFCOMM connection closed. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + tBTA_AG_HDR close; + tBTA_SERVICE_MASK services; + int i, num_active_conn = 0; + +#ifdef _WIN32_WCE + /* The BTE RFCOMM automatically removes the connection when closed, but BTW does not */ + if (p_scb->conn_handle != 0) + RFCOMM_RemoveConnection (p_scb->conn_handle); +#endif + + /* reinitialize stuff */ + p_scb->conn_service = 0; + p_scb->peer_features = 0; +#if (BTM_WBS_INCLUDED == TRUE ) + p_scb->peer_codecs = BTA_AG_CODEC_NONE; + p_scb->sco_codec = BTA_AG_CODEC_NONE; +#endif + p_scb->role = 0; + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + p_scb->svc_conn = FALSE; + p_scb->hsp_version = HSP_VERSION_1_2; + bta_ag_at_reinit(&p_scb->at_cb); + + /* stop timers */ + bta_sys_stop_timer(&p_scb->act_timer); +#if (BTM_WBS_INCLUDED == TRUE) + bta_sys_stop_timer(&p_scb->cn_timer); +#endif + + close.handle = bta_ag_scb_to_idx(p_scb); + close.app_id = p_scb->app_id; + + bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + /* call close call-out */ + bta_ag_co_data_close(close.handle); + + /* call close cback */ + (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close); + + /* if not deregistering (deallocating) reopen registered servers */ + if (p_scb->dealloc == FALSE) + { + /* Clear peer bd_addr so instance can be reused */ + bdcpy(p_scb->peer_addr, bd_addr_null); + + /* start only unopened server */ + services = p_scb->reg_services; + for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++) + { + if(p_scb->serv_handle[i]) + services &= ~((tBTA_SERVICE_MASK)1 << (BTA_HSP_SERVICE_ID + i)); + } + bta_ag_start_servers(p_scb, services); + + p_scb->conn_handle = 0; + + /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */ + bta_ag_sco_shutdown(p_scb, NULL); + + /* Check if all the SLCs are down */ + for (i = 0; i < BTA_AG_NUM_SCB; i++) + { + if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn) + num_active_conn++; + } + + if(!num_active_conn) + { + bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + } + + } + /* else close port and deallocate scb */ + else + { + RFCOMM_RemoveServer(p_scb->conn_handle); + bta_ag_scb_dealloc(p_scb); + } +} + +/******************************************************************************* +** +** Function bta_ag_rfc_open +** +** Description Handle RFCOMM channel open. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* initialize AT feature variables */ + p_scb->clip_enabled = FALSE; + p_scb->ccwa_enabled = FALSE; + p_scb->cmer_enabled = FALSE; + p_scb->cmee_enabled = FALSE; + p_scb->inband_enabled = ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND); + + /* set up AT command interpreter */ + p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD *) bta_ag_at_tbl[p_scb->conn_service]; + p_scb->at_cb.p_cmd_cback = (tBTA_AG_AT_CMD_CBACK *) bta_ag_at_cback_tbl[p_scb->conn_service]; + p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK *) bta_ag_at_err_cback; + p_scb->at_cb.p_user = p_scb; + p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX; + bta_ag_at_init(&p_scb->at_cb); + + /* call app open call-out */ + bta_ag_co_data_open(bta_ag_scb_to_idx(p_scb), bta_ag_svc_id[p_scb->conn_service]); + + bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS); + + if (p_scb->conn_service == BTA_AG_HFP) + { + /* if hfp start timer for service level conn */ + bta_sys_start_timer(&p_scb->act_timer, BTA_AG_SVC_TOUT_EVT, p_bta_ag_cfg->conn_tout); + } + else + { + /* else service level conn is open */ + bta_ag_svc_conn_open(p_scb, p_data); + } +} + +/******************************************************************************* +** +** Function bta_ag_rfc_acp_open +** +** Description Handle RFCOMM channel open when accepting connection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + UINT16 lcid; + int i; + tBTA_AG_SCB *ag_scb, *other_scb; + BD_ADDR dev_addr; + int status; + + /* set role */ + p_scb->role = BTA_AG_ACP; + + APPL_TRACE_DEBUG2 ("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d", + p_scb->serv_handle[0], p_scb->serv_handle[1]); + + /* get bd addr of peer */ + if (PORT_SUCCESS != (status=PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid))) + { + APPL_TRACE_DEBUG1 ("bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d", status); + } + + /* Collision Handling */ + for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) + { + if ((ag_scb->in_use) && (ag_scb->colli_tmr_on)) + { + /* stop collision timer */ + ag_scb->colli_tmr_on = FALSE; + bta_sys_stop_timer (&ag_scb->colli_timer); + + if (bdcmp (dev_addr, ag_scb->peer_addr) == 0) + { + /* If incoming and outgoing device are same, nothing more to do. */ + /* Outgoing conn will be aborted because we have successful incoming conn. */ + } + else + { + /* Resume outgoing connection. */ + other_scb = bta_ag_get_other_idle_scb (p_scb); + if (other_scb) + { + bdcpy(other_scb->peer_addr, ag_scb->peer_addr); + other_scb->open_services = ag_scb->open_services; + other_scb->cli_sec_mask = ag_scb->cli_sec_mask; + + bta_ag_resume_open (other_scb); + } + } + + break; + } + } + + bdcpy (p_scb->peer_addr, dev_addr); + + /* determine connected service from port handle */ + for (i = 0; i < BTA_AG_NUM_IDX; i++) + { + APPL_TRACE_DEBUG3 ("bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", + i, p_scb->serv_handle[i], p_data->rfc.port_handle); + + if (p_scb->serv_handle[i] == p_data->rfc.port_handle) + { + p_scb->conn_service = i; + p_scb->conn_handle = p_data->rfc.port_handle; + break; + } + } + + APPL_TRACE_DEBUG2 ("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d", + p_scb->conn_service, p_scb->conn_handle); + + /* close any unopened server */ + bta_ag_close_servers(p_scb, (p_scb->reg_services & ~bta_ag_svc_mask[p_scb->conn_service])); + + /* do service discovery to get features */ + bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]); + + /* continue with common open processing */ + bta_ag_rfc_open(p_scb, p_data); + + + +} + +/******************************************************************************* +** +** Function bta_ag_rfc_data +** +** Description Read and process data from RFCOMM. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + UINT16 len; + char buf[BTA_AG_RFC_READ_MAX]; + + memset(buf, 0, BTA_AG_RFC_READ_MAX); + + /* do the following */ + for(;;) + { + /* read data from rfcomm; if bad status, we're done */ + if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) != PORT_SUCCESS) + { + break; + } + + /* if no data, we're done */ + if (len == 0) + { + break; + } + + /* run AT command interpreter on data */ + bta_ag_at_parse(&p_scb->at_cb, buf, len); + + /* no more data to read, we're done */ + if (len < BTA_AG_RFC_READ_MAX) + { + break; + } + } +} + +/******************************************************************************* +** +** Function bta_ag_start_close +** +** Description Start the process of closing SCO and RFCOMM connection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* Take the link out of sniff and set L2C idle time to 0 */ + bta_dm_pm_active(p_scb->peer_addr); + L2CA_SetIdleTimeoutByBdAddr(p_scb->peer_addr, 0); + + /* if SCO is open close SCO and wait on RFCOMM close */ + if (bta_ag_sco_is_open(p_scb)) + { + p_scb->post_sco = BTA_AG_POST_SCO_CLOSE_RFC; + } + else + { + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + bta_ag_rfc_do_close(p_scb, p_data); + } + + /* always do SCO shutdown to handle all SCO corner cases */ + bta_ag_sco_shutdown(p_scb, p_data); +} + +/******************************************************************************* +** +** Function bta_ag_post_sco_open +** +** Description Perform post-SCO open action, if any +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + switch (p_scb->post_sco) + { + case BTA_AG_POST_SCO_RING: + bta_ag_send_ring(p_scb, p_data); + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + break; + + case BTA_AG_POST_SCO_CALL_CONN: + bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES); + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + break; + + default: + break; + } +} + +/******************************************************************************* +** +** Function bta_ag_post_sco_close +** +** Description Perform post-SCO close action, if any +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + switch (p_scb->post_sco) + { + case BTA_AG_POST_SCO_CLOSE_RFC: + bta_ag_rfc_do_close(p_scb, p_data); + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + break; + + case BTA_AG_POST_SCO_CALL_CONN: + bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES); + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + break; + + case BTA_AG_POST_SCO_CALL_ORIG: + bta_ag_send_call_inds(p_scb, BTA_AG_OUT_CALL_ORIG_RES); + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + break; + + case BTA_AG_POST_SCO_CALL_END: + bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES); + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + break; + + case BTA_AG_POST_SCO_CALL_END_INCALL: + bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES); + + /* Sending callsetup IND and Ring were defered to after SCO close. */ + bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_RES); + + if (bta_ag_inband_enabled(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + p_scb->post_sco = BTA_AG_POST_SCO_RING; + bta_ag_sco_open(p_scb, p_data); + } + else + { + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + bta_ag_send_ring(p_scb, p_data); + } + break; + + default: + break; + } +} + +/******************************************************************************* +** +** Function bta_ag_svc_conn_open +** +** Description Service level connection opened +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + tBTA_AG_CONN evt; + + if (!p_scb->svc_conn) + { + /* set state variable */ + p_scb->svc_conn = TRUE; + + /* Clear AT+BIA mask from previous SLC if any. */ + p_scb->bia_masked_out = 0; + + /* stop timer */ + bta_sys_stop_timer(&p_scb->act_timer); + + /* call callback */ + evt.hdr.handle = bta_ag_scb_to_idx(p_scb); + evt.hdr.app_id = p_scb->app_id; + evt.peer_feat = p_scb->peer_features; +#if (BTM_WBS_INCLUDED == TRUE ) + evt.peer_codec = p_scb->peer_codecs; +#endif + + if ((p_scb->call_ind != BTA_AG_CALL_INACTIVE) || + (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE)) + { + bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + } + + (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG *) &evt); + } +} + +/******************************************************************************* +** +** Function bta_ag_ci_rx_data +** +** Description Send result code +** +** Returns void +** +*******************************************************************************/ +void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + UINT16 len; + tBTA_AG_CI_RX_WRITE *p_rx_write_msg = (tBTA_AG_CI_RX_WRITE *)p_data; + char *p_data_area = (char *)(p_rx_write_msg+1); /* Point to data area after header */ + + /* send to RFCOMM */ + PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len); +} + +/******************************************************************************* +** +** Function bta_ag_rcvd_slc_ready +** +** Description Handles SLC ready call-in in case of pass-through mode. +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + APPL_TRACE_DEBUG1("bta_ag_rcvd_slc_ready: handle = %d", bta_ag_scb_to_idx(p_scb)); + + if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) + { + /* In pass-through mode, BTA knows that SLC is ready only through call-in. */ + bta_ag_svc_conn_open(p_scb, NULL); + } +} + diff --git a/bta/ag/bta_ag_api.c b/bta/ag/bta_ag_api.c new file mode 100644 index 0000000..07dceb9 --- /dev/null +++ b/bta/ag/bta_ag_api.c @@ -0,0 +1,323 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 of the API for the audio gateway (AG) + * subsystem of BTA, Broadcom's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bd.h" +#include "bta_sys.h" +#include "bta_ag_api.h" +#include "bta_ag_int.h" +#include "gki.h" +#include <string.h> + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_ag_reg = +{ + bta_ag_hdl_event, + BTA_AgDisable +}; + +/******************************************************************************* +** +** Function BTA_AgEnable +** +** Description Enable the audio gateway service. When the enable +** operation is complete the callback function will be +** called with a BTA_AG_ENABLE_EVT. This function must +** be called before other function in the AG API are +** called. +** +** Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise. +** +*******************************************************************************/ +tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback) +{ + tBTA_AG_API_ENABLE *p_buf; + UINT8 idx; + + /* Error if AG is already enabled, or AG is in the middle of disabling. */ + for (idx = 0; idx < BTA_AG_NUM_SCB; idx++) + { + if (bta_ag_cb.scb[idx].in_use) + { + APPL_TRACE_ERROR0 ("BTA_AgEnable: FAILED, AG already enabled."); + return BTA_FAILURE; + } + } + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_AG, &bta_ag_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_AG_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AG_API_ENABLE))) != NULL) + { + p_buf->hdr.event = BTA_AG_API_ENABLE_EVT; + p_buf->parse_mode = parse_mode; + p_buf->p_cback = p_cback; + bta_sys_sendmsg(p_buf); + } + + return BTA_SUCCESS; + +} + +/******************************************************************************* +** +** Function BTA_AgDisable +** +** Description Disable the audio gateway service +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgDisable(void) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AgRegister +** +** Description Register an Audio Gateway service. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,tBTA_AG_FEAT features, + char * p_service_names[], UINT8 app_id) +{ + tBTA_AG_API_REGISTER *p_buf; + int i; + + if ((p_buf = (tBTA_AG_API_REGISTER *) GKI_getbuf(sizeof(tBTA_AG_API_REGISTER))) != NULL) + { + p_buf->hdr.event = BTA_AG_API_REGISTER_EVT; + p_buf->features = features; + p_buf->sec_mask = sec_mask; + p_buf->services = services; + p_buf->app_id = app_id; + for (i = 0; i < BTA_AG_NUM_IDX; i++) + { + if(p_service_names[i]) + { + BCM_STRNCPY_S(p_buf->p_name[i], BTA_SERVICE_NAME_LEN+1, p_service_names[i], BTA_SERVICE_NAME_LEN); + p_buf->p_name[i][BTA_SERVICE_NAME_LEN] = 0; + } + else + { + p_buf->p_name[i][0] = 0; + } + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AgDeregister +** +** Description Deregister an audio gateway service. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgDeregister(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_API_DEREGISTER_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AgOpen +** +** Description Opens a connection to a headset or hands-free device. +** When connection is open callback function is called +** with a BTA_AG_OPEN_EVT. Only the data connection is +** opened. The audio connection is not opened. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services) +{ + tBTA_AG_API_OPEN *p_buf; + + if ((p_buf = (tBTA_AG_API_OPEN *) GKI_getbuf(sizeof(tBTA_AG_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_AG_API_OPEN_EVT; + p_buf->hdr.layer_specific = handle; + bdcpy(p_buf->bd_addr, bd_addr); + p_buf->services = services; + p_buf->sec_mask = sec_mask; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AgClose +** +** Description Close the current connection to a headset or a handsfree +** Any current audio connection will also be closed. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgClose(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_API_CLOSE_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AgAudioOpen +** +** Description Opens an audio connection to the currently connected +** headset or hnadsfree. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgAudioOpen(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_API_AUDIO_OPEN_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AgAudioClose +** +** Description Close the currently active audio connection to a headset +** or hnadsfree. The data connection remains open +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgAudioClose(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_API_AUDIO_CLOSE_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + + +/******************************************************************************* +** +** Function BTA_AgResult +** +** Description Send an AT result code to a headset or hands-free device. +** This function is only used when the AG parse mode is set +** to BTA_AG_PARSE. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data) +{ + tBTA_AG_API_RESULT *p_buf; + + if ((p_buf = (tBTA_AG_API_RESULT *) GKI_getbuf(sizeof(tBTA_AG_API_RESULT))) != NULL) + { + p_buf->hdr.event = BTA_AG_API_RESULT_EVT; + p_buf->hdr.layer_specific = handle; + p_buf->result = result; + if(p_data) + { + memcpy(&p_buf->data, p_data, sizeof(p_buf->data)); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AgSetCodec +** +** Description Specify the codec type to be used for the subsequent +** audio connection. +** +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec) +{ + tBTA_AG_API_SETCODEC *p_buf; + + if ((p_buf = (tBTA_AG_API_SETCODEC *) GKI_getbuf(sizeof(tBTA_AG_API_SETCODEC))) != NULL) + { + p_buf->hdr.event = BTA_AG_API_SETCODEC_EVT; + p_buf->hdr.layer_specific = handle; + p_buf->codec = codec; + bta_sys_sendmsg(p_buf); + } +} + diff --git a/bta/ag/bta_ag_at.c b/bta/ag/bta_ag_at.c new file mode 100644 index 0000000..74d3948 --- /dev/null +++ b/bta/ag/bta_ag_at.c @@ -0,0 +1,243 @@ +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * BTA AG AT command interpreter. + * + ******************************************************************************/ + +#include <string.h> +#include "gki.h" +#include "bta_ag_at.h" +#include "utl.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/****************************************************************************** +** +** Function bta_ag_at_init +** +** Description Initialize the AT command parser control block. +** +** +** Returns void +** +******************************************************************************/ +void bta_ag_at_init(tBTA_AG_AT_CB *p_cb) +{ + p_cb->p_cmd_buf = NULL; + p_cb->cmd_pos = 0; +} + +/****************************************************************************** +** +** Function bta_ag_at_reinit +** +** Description Re-initialize the AT command parser control block. This +** function resets the AT command parser state and frees +** any GKI buffer. +** +** +** Returns void +** +******************************************************************************/ +void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb) +{ + if (p_cb->p_cmd_buf != NULL) + { + GKI_freebuf(p_cb->p_cmd_buf); + p_cb->p_cmd_buf = NULL; + } + p_cb->cmd_pos = 0; +} +/****************************************************************************** +** +** Function bta_ag_process_at +** +** Description Parse AT commands. This function will take the input +** character string and parse it for AT commands according to +** the AT command table passed in the control block. +** +** +** Returns void +** +******************************************************************************/ +void bta_ag_process_at(tBTA_AG_AT_CB *p_cb) +{ + UINT16 idx; + UINT8 arg_type; + char *p_arg; + INT16 int_arg = 0; + /* loop through at command table looking for match */ + for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++) + { + if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf)) + { + break; + } + } + + /* if there is a match; verify argument type */ + if (p_cb->p_at_tbl[idx].p_cmd[0] != 0) + { + /* start of argument is p + strlen matching command */ + p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd); + + /* if no argument */ + if (p_arg[0] == 0) + { + arg_type = BTA_AG_AT_NONE; + } + /* else if arg is '?' and it is last character */ + else if (p_arg[0] == '?' && p_arg[1] == 0) + { + /* we have a read */ + arg_type = BTA_AG_AT_READ; + } + /* else if arg is '=' */ + else if (p_arg[0] == '=' && p_arg[1] != 0) + { + if (p_arg[1] == '?' && p_arg[2] == 0) + { + /* we have a test */ + arg_type = BTA_AG_AT_TEST; + } + else + { + /* we have a set */ + arg_type = BTA_AG_AT_SET; + + /* skip past '=' */ + p_arg++; + } + } + else + /* else it is freeform argument */ + { + arg_type = BTA_AG_AT_FREE; + } + + /* if arguments match command capabilities */ + if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0) + { + /* if it's a set integer check max, min range */ + if (arg_type == BTA_AG_AT_SET && + p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT) + { + int_arg = utl_str2int(p_arg); + if (int_arg < (INT16) p_cb->p_at_tbl[idx].min || + int_arg > (INT16) p_cb->p_at_tbl[idx].max) + { + /* arg out of range; error */ + (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL); + } + else + { + + (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg); + } + } + else + { + (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg); + } + } + /* else error */ + else + { + (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL); + } + } + /* else no match call error callback */ + else + { + (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf); + } +} + +/****************************************************************************** +** +** Function bta_ag_at_parse +** +** Description Parse AT commands. This function will take the input +** character string and parse it for AT commands according to +** the AT command table passed in the control block. +** +** +** Returns void +** +******************************************************************************/ +void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len) +{ + int i = 0; + char* p_save; + + if (p_cb->p_cmd_buf == NULL) + { + p_cb->p_cmd_buf = (char *) GKI_getbuf(p_cb->cmd_max_len); + p_cb->cmd_pos = 0; + } + + for (i = 0; i < len;) + { + while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len) + { + /* Skip null characters between AT commands. */ + if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) + { + i++; + continue; + } + + p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++]; + if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') + { + p_cb->p_cmd_buf[p_cb->cmd_pos] = 0; + if ((p_cb->cmd_pos > 2) && + (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') && + (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) + { + p_save = p_cb->p_cmd_buf; + p_cb->p_cmd_buf += 2; + bta_ag_process_at(p_cb); + p_cb->p_cmd_buf = p_save; + } + + p_cb->cmd_pos = 0; + + } + else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B ) + { + p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0; + (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf); + p_cb->cmd_pos = 0; + } + else + { + ++p_cb->cmd_pos; + } + } + + if (i < len) + p_cb->cmd_pos = 0; + } +} + diff --git a/bta/ag/bta_ag_at.h b/bta/ag/bta_ag_at.h new file mode 100644 index 0000000..90d7b0f --- /dev/null +++ b/bta/ag/bta_ag_at.h @@ -0,0 +1,121 @@ +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Interface file for BTA AG AT command interpreter. + * + ******************************************************************************/ +#ifndef BTA_AG_AT_H +#define BTA_AG_AT_H + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* AT command argument capabilities */ +#define BTA_AG_AT_NONE 0x01 /* no argument */ +#define BTA_AG_AT_SET 0x02 /* set value */ +#define BTA_AG_AT_READ 0x04 /* read value */ +#define BTA_AG_AT_TEST 0x08 /* test value range */ +#define BTA_AG_AT_FREE 0x10 /* freeform argument */ + +/* AT command argument format */ +#define BTA_AG_AT_STR 0 /* string */ +#define BTA_AG_AT_INT 1 /* integer */ + +/***************************************************************************** +** Data types +*****************************************************************************/ + +/* AT command table element */ +typedef struct +{ + const char *p_cmd; /* AT command string */ + UINT8 arg_type; /* allowable argument type syntax */ + UINT8 fmt; /* whether arg is int or string */ + UINT8 min; /* minimum value for int arg */ + INT16 max; /* maximum value for int arg */ +} tBTA_AG_AT_CMD; + +/* callback function executed when command is parsed */ +typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 cmd, UINT8 arg_type, + char *p_arg, INT16 int_arg); + +/* callback function executed to send "ERROR" result code */ +typedef void (tBTA_AG_AT_ERR_CBACK)(void *p_user, BOOLEAN unknown, char *p_arg); + +/* AT command parsing control block */ +typedef struct +{ + tBTA_AG_AT_CMD *p_at_tbl; /* AT command table */ + tBTA_AG_AT_CMD_CBACK *p_cmd_cback; /* command callback */ + tBTA_AG_AT_ERR_CBACK *p_err_cback; /* error callback */ + void *p_user; /* user-defined data */ + char *p_cmd_buf; /* temp parsing buffer */ + UINT16 cmd_pos; /* position in temp buffer */ + UINT16 cmd_max_len; /* length of temp buffer to allocate */ + UINT8 state; /* parsing state */ +} tBTA_AG_AT_CB; + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +/***************************************************************************** +** +** Function bta_ag_at_init +** +** Description Initialize the AT command parser control block. +** +** +** Returns void +** +*****************************************************************************/ +extern void bta_ag_at_init(tBTA_AG_AT_CB *p_cb); + +/***************************************************************************** +** +** Function bta_ag_at_reinit +** +** Description Re-initialize the AT command parser control block. This +** function resets the AT command parser state and frees +** any GKI buffer. +** +** +** Returns void +** +*****************************************************************************/ +extern void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb); + +/***************************************************************************** +** +** Function bta_ag_at_parse +** +** Description Parse AT commands. This function will take the input +** character string and parse it for AT commands according to +** the AT command table passed in the control block. +** +** +** Returns void +** +*****************************************************************************/ +extern void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len); + +#endif /* BTA_AG_AT_H */ + diff --git a/bta/ag/bta_ag_cfg.c b/bta/ag/bta_ag_cfg.c new file mode 100644 index 0000000..e02f9f6 --- /dev/null +++ b/bta/ag/bta_ag_cfg.c @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains compile-time configurable constants for the audio + * gateway. + * + ******************************************************************************/ + +#include "gki.h" +#include "bta_api.h" +#include "bta_ag_api.h" + +#ifndef BTA_AG_CIND_INFO +#define BTA_AG_CIND_INFO "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-3)),(\"signal\",(0-6)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2)),(\"bearer\",(0-7))" +#endif + +#ifndef BTA_AG_CHLD_VAL_ECC +#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3,4)" +#endif + +#ifndef BTA_AG_CHLD_VAL +#define BTA_AG_CHLD_VAL "(0,1,2,3,4)" +#endif + +#ifndef BTA_AG_CONN_TIMEOUT +#define BTA_AG_CONN_TIMEOUT 5000 +#endif + +#ifndef BTA_AG_SCO_PKT_TYPES +/* S1 packet type setting from HFP 1.5 spec */ +#define BTA_AG_SCO_PKT_TYPES /* BTM_SCO_LINK_ALL_PKT_MASK */ (BTM_SCO_LINK_ONLY_MASK | \ + BTM_SCO_PKT_TYPES_MASK_EV3 | \ + BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \ + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \ + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5) +#endif + +const tBTA_AG_CFG bta_ag_cfg = +{ + BTA_AG_CIND_INFO, + BTA_AG_CONN_TIMEOUT, + BTA_AG_SCO_PKT_TYPES, + BTA_AG_CHLD_VAL_ECC, + BTA_AG_CHLD_VAL +}; + +tBTA_AG_CFG *p_bta_ag_cfg = (tBTA_AG_CFG *) &bta_ag_cfg; diff --git a/bta/ag/bta_ag_ci.c b/bta/ag/bta_ag_ci.c new file mode 100644 index 0000000..fd39e34 --- /dev/null +++ b/bta/ag/bta_ag_ci.c @@ -0,0 +1,98 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 audio gateway call-in functions. + * + ******************************************************************************/ + +#include <string.h> +#include "bta_api.h" +#include "bta_ag_api.h" +#include "bta_ag_int.h" +#include "bta_ag_ci.h" +#include "gki.h" + +/****************************************************************************** +** +** Function bta_ag_ci_rx_write +** +** Description This function is called to send data to the AG when the AG +** is configured for AT command pass-through. The function +** copies data to an event buffer and sends it. +** +** Returns void +** +******************************************************************************/ +void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len) +{ + tBTA_AG_CI_RX_WRITE *p_buf; + UINT16 len_remaining = len; + char *p_data_area; + + if (len > (RFCOMM_DATA_POOL_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1)) + len = RFCOMM_DATA_POOL_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1; + + while (len_remaining) + { + if (len_remaining < len) + len = len_remaining; + + if ((p_buf = (tBTA_AG_CI_RX_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_AG_CI_RX_WRITE) + len + 1))) != NULL) + { + p_buf->hdr.event = BTA_AG_CI_RX_WRITE_EVT; + p_buf->hdr.layer_specific = handle; + + p_data_area = (char *)(p_buf+1); /* Point to data area after header */ + strncpy(p_data_area, p_data, len); + p_data_area[len] = 0; + + bta_sys_sendmsg(p_buf); + } else { + APPL_TRACE_ERROR1("ERROR: Unable to allocate buffer to hold AT response code. len=%i", len); + break; + } + + len_remaining-=len; + p_data+=len; + } +} + +/****************************************************************************** +** +** Function bta_ag_ci_slc_ready +** +** Description This function is called to notify AG that SLC is up at +** the application. This funcion is only used when the app +** is running in pass-through mode. +** +** Returns void +** +******************************************************************************/ +void bta_ag_ci_slc_ready(UINT16 handle) +{ + tBTA_AG_DATA *p_buf; + + if ((p_buf = (tBTA_AG_DATA *)GKI_getbuf(sizeof(tBTA_AG_DATA))) != NULL) + { + p_buf->hdr.event = BTA_AG_CI_SLC_READY_EVT; + p_buf->hdr.layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} diff --git a/bta/ag/bta_ag_cmd.c b/bta/ag/bta_ag_cmd.c new file mode 100644 index 0000000..d552eed --- /dev/null +++ b/bta/ag/bta_ag_cmd.c @@ -0,0 +1,1836 @@ +/****************************************************************************** + * + * 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 file contains functions for processing AT commands and results. + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_ag_api.h" +#include "bta_ag_int.h" +#include "bta_ag_at.h" +#include "port_api.h" +#include "utl.h" +#include <stdio.h> +#include <string.h> + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* ring timeout */ +#define BTA_AG_RING_TOUT 10000 + +#define BTA_AG_CMD_MAX_VAL 32767 /* Maximum value is signed 16-bit value */ + + + +/* clip type constants */ +#define BTA_AG_CLIP_TYPE_MIN 128 +#define BTA_AG_CLIP_TYPE_MAX 175 +#define BTA_AG_CLIP_TYPE_DEFAULT 129 +#define BTA_AG_CLIP_TYPE_VOIP 255 + +#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE) +#define BTA_AG_AT_MULTI_LEN 2 +#define AT_SET_RES_CB(res_cb, c, p, i) {res_cb.code = c; res_cb.p_arg = p; res_cb.int_arg = i;} + +/* type for AT result code block */ +typedef struct +{ + UINT8 code; + char *p_arg; + INT16 int_arg; +} tBTA_AG_RESULT_CB; + +/* type for multiple AT result codes block */ +typedef struct +{ + UINT8 num_result; + tBTA_AG_RESULT_CB res_cb[BTA_AG_AT_MULTI_LEN]; +} tBTA_AG_MULTI_RESULT_CB; +#endif + +/* enumeration of HSP AT commands matches HSP command interpreter table */ +enum +{ + BTA_AG_HS_CMD_CKPD, + BTA_AG_HS_CMD_VGS, + BTA_AG_HS_CMD_VGM +}; + +/* enumeration of HFP AT commands matches HFP command interpreter table */ +enum +{ + BTA_AG_HF_CMD_A, + BTA_AG_HF_CMD_D, + BTA_AG_HF_CMD_VGS, + BTA_AG_HF_CMD_VGM, + BTA_AG_HF_CMD_CCWA, + BTA_AG_HF_CMD_CHLD, + BTA_AG_HF_CMD_CHUP, + BTA_AG_HF_CMD_CIND, + BTA_AG_HF_CMD_CLIP, + BTA_AG_HF_CMD_CMER, + BTA_AG_HF_CMD_VTS, + BTA_AG_HF_CMD_BINP, + BTA_AG_HF_CMD_BLDN, + BTA_AG_HF_CMD_BVRA, + BTA_AG_HF_CMD_BRSF, + BTA_AG_HF_CMD_NREC, + BTA_AG_HF_CMD_CNUM, + BTA_AG_HF_CMD_BTRH, + BTA_AG_HF_CMD_CLCC, + BTA_AG_HF_CMD_COPS, + BTA_AG_HF_CMD_CMEE, + BTA_AG_HF_CMD_BIA, + BTA_AG_HF_CMD_CBC, + BTA_AG_HF_CMD_BCC, + BTA_AG_HF_CMD_BCS, + BTA_AG_HF_CMD_BAC +}; + +/* AT command interpreter table for HSP */ +const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] = +{ + {"+CKPD", BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200}, + {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15}, + {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15}, + {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0} +}; + +/* AT command interpreter table for HFP */ +const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] = +{ + {"A", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, + {"D", (BTA_AG_AT_NONE | BTA_AG_AT_FREE), BTA_AG_AT_STR, 0, 0}, + {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15}, + {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15}, + {"+CCWA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1}, + /* Consider CHLD as str to take care of indexes for ECC */ + {"+CHLD", (BTA_AG_AT_SET | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 4}, + {"+CHUP", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, + {"+CIND", (BTA_AG_AT_READ | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 0}, + {"+CLIP", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1}, + {"+CMER", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, + {"+VTS", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, + {"+BINP", BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1}, + {"+BLDN", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, + {"+BVRA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1}, + {"+BRSF", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL}, + {"+NREC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0}, + {"+CNUM", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, + {"+BTRH", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_INT, 0, 2}, + {"+CLCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, + {"+COPS", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_STR, 0, 0}, + {"+CMEE", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1}, + {"+BIA", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20}, + {"+CBC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100}, + {"+BCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, + {"+BCS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL}, + {"+BAC", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, + {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0} +}; + +/* AT result code table element */ +typedef struct +{ + const char *p_res; /* AT result string */ + UINT8 fmt; /* whether argument is int or string */ +} tBTA_AG_RESULT; + +/* AT result code argument types */ +enum +{ + BTA_AG_RES_FMT_NONE, /* no argument */ + BTA_AG_RES_FMT_INT, /* integer argument */ + BTA_AG_RES_FMT_STR /* string argument */ +}; + +/* enumeration of AT result codes, matches constant table */ +enum +{ + BTA_AG_RES_OK, + BTA_AG_RES_ERROR, + BTA_AG_RES_RING, + BTA_AG_RES_VGS, + BTA_AG_RES_VGM, + BTA_AG_RES_CCWA, + BTA_AG_RES_CHLD, + BTA_AG_RES_CIND, + BTA_AG_RES_CLIP, + BTA_AG_RES_CIEV, + BTA_AG_RES_BINP, + BTA_AG_RES_BVRA, + BTA_AG_RES_BRSF, + BTA_AG_RES_BSIR, + BTA_AG_RES_CNUM, + BTA_AG_RES_BTRH, + BTA_AG_RES_CLCC, + BTA_AG_RES_COPS, + BTA_AG_RES_CMEE, + BTA_AG_RES_BCS, + BTA_AG_RES_UNAT +}; + +#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE) +#define COLON_IDX_4_VGSVGM 4 +#endif +/* AT result code constant table (Indexed by result code) */ +const tBTA_AG_RESULT bta_ag_result_tbl[] = +{ + {"OK", BTA_AG_RES_FMT_NONE}, + {"ERROR", BTA_AG_RES_FMT_NONE}, + {"RING", BTA_AG_RES_FMT_NONE}, + {"+VGS: ", BTA_AG_RES_FMT_INT}, + {"+VGM: ", BTA_AG_RES_FMT_INT}, + {"+CCWA: ", BTA_AG_RES_FMT_STR}, + {"+CHLD: ", BTA_AG_RES_FMT_STR}, + {"+CIND: ", BTA_AG_RES_FMT_STR}, + {"+CLIP: ", BTA_AG_RES_FMT_STR}, + {"+CIEV: ", BTA_AG_RES_FMT_STR}, + {"+BINP: ", BTA_AG_RES_FMT_STR}, + {"+BVRA: ", BTA_AG_RES_FMT_INT}, + {"+BRSF: ", BTA_AG_RES_FMT_INT}, + {"+BSIR: ", BTA_AG_RES_FMT_INT}, + {"+CNUM: ", BTA_AG_RES_FMT_STR}, + {"+BTRH: ", BTA_AG_RES_FMT_INT}, + {"+CLCC: ", BTA_AG_RES_FMT_STR}, + {"+COPS: ", BTA_AG_RES_FMT_STR}, + {"+CME ERROR: ", BTA_AG_RES_FMT_INT}, + {"+BCS: ", BTA_AG_RES_FMT_INT}, + {"", BTA_AG_RES_FMT_STR} +}; + +const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX] = +{ + bta_ag_hsp_cmd, + bta_ag_hfp_cmd +}; + +/* callback event lookup table for HSP */ +const tBTA_AG_EVT bta_ag_hsp_cb_evt[] = +{ + BTA_AG_AT_CKPD_EVT, /* BTA_AG_HS_CMD_CKPD */ + BTA_AG_SPK_EVT, /* BTA_AG_HS_CMD_VGS */ + BTA_AG_MIC_EVT /* BTA_AG_HS_CMD_VGM */ +}; + +/* callback event lookup table for HFP (Indexed by command) */ +const tBTA_AG_EVT bta_ag_hfp_cb_evt[] = +{ + BTA_AG_AT_A_EVT, /* BTA_AG_HF_CMD_A */ + BTA_AG_AT_D_EVT, /* BTA_AG_HF_CMD_D */ + BTA_AG_SPK_EVT, /* BTA_AG_HF_CMD_VGS */ + BTA_AG_MIC_EVT, /* BTA_AG_HF_CMD_VGM */ + 0, /* BTA_AG_HF_CMD_CCWA */ + BTA_AG_AT_CHLD_EVT, /* BTA_AG_HF_CMD_CHLD */ + BTA_AG_AT_CHUP_EVT, /* BTA_AG_HF_CMD_CHUP */ + BTA_AG_AT_CIND_EVT, /* BTA_AG_HF_CMD_CIND */ + 0, /* BTA_AG_HF_CMD_CLIP */ + 0, /* BTA_AG_HF_CMD_CMER */ + BTA_AG_AT_VTS_EVT, /* BTA_AG_HF_CMD_VTS */ + BTA_AG_AT_BINP_EVT, /* BTA_AG_HF_CMD_BINP */ + BTA_AG_AT_BLDN_EVT, /* BTA_AG_HF_CMD_BLDN */ + BTA_AG_AT_BVRA_EVT, /* BTA_AG_HF_CMD_BVRA */ + 0, /* BTA_AG_HF_CMD_BRSF */ + BTA_AG_AT_NREC_EVT, /* BTA_AG_HF_CMD_NREC */ + BTA_AG_AT_CNUM_EVT, /* BTA_AG_HF_CMD_CNUM */ + BTA_AG_AT_BTRH_EVT, /* BTA_AG_HF_CMD_BTRH */ + BTA_AG_AT_CLCC_EVT, /* BTA_AG_HF_CMD_CLCC */ + BTA_AG_AT_COPS_EVT, /* BTA_AG_HF_CMD_COPS */ + 0, /* BTA_AG_HF_CMD_CMEE */ + 0, /* BTA_AG_HF_CMD_BIA */ + BTA_AG_AT_CBC_EVT, /* BTA_AG_HF_CMD_CBC */ + 0, /* BTA_AG_HF_CMD_BCC */ + BTA_AG_AT_BCS_EVT, /* BTA_AG_HF_CMD_BCS */ + BTA_AG_AT_BAC_EVT /* BTA_AG_HF_CMD_BAC */ +}; + +/* translation of API result code values to internal values */ +const UINT8 bta_ag_trans_result[] = +{ + BTA_AG_RES_VGS, /* BTA_AG_SPK_RES */ + BTA_AG_RES_VGM, /* BTA_AG_MIC_RES */ + BTA_AG_RES_BSIR, /* BTA_AG_INBAND_RING_RES */ + BTA_AG_RES_CIND, /* BTA_AG_CIND_RES */ + BTA_AG_RES_BINP, /* BTA_AG_BINP_RES */ + BTA_AG_RES_CIEV, /* BTA_AG_IND_RES */ + BTA_AG_RES_BVRA, /* BTA_AG_BVRA_RES */ + BTA_AG_RES_CNUM, /* BTA_AG_CNUM_RES */ + BTA_AG_RES_BTRH, /* BTA_AG_BTRH_RES */ + BTA_AG_RES_CLCC, /* BTA_AG_CLCC_RES */ + BTA_AG_RES_COPS, /* BTA_AG_COPS_RES */ + 0, /* BTA_AG_IN_CALL_RES */ + 0, /* BTA_AG_IN_CALL_CONN_RES */ + BTA_AG_RES_CCWA, /* BTA_AG_CALL_WAIT_RES */ + 0, /* BTA_AG_OUT_CALL_ORIG_RES */ + 0, /* BTA_AG_OUT_CALL_ALERT_RES */ + 0, /* BTA_AG_OUT_CALL_CONN_RES */ + 0, /* BTA_AG_CALL_CANCEL_RES */ + 0, /* BTA_AG_END_CALL_RES */ + 0, /* BTA_AG_IN_CALL_HELD_RES */ + BTA_AG_RES_UNAT /* BTA_AG_UNAT_RES */ +}; + +/* callsetup indicator value lookup table */ +const UINT8 bta_ag_callsetup_ind_tbl[] = +{ + 0, /* BTA_AG_SPK_RES */ + 0, /* BTA_AG_MIC_RES */ + 0, /* BTA_AG_INBAND_RING_RES */ + 0, /* BTA_AG_CIND_RES */ + 0, /* BTA_AG_BINP_RES */ + 0, /* BTA_AG_IND_RES */ + 0, /* BTA_AG_BVRA_RES */ + 0, /* BTA_AG_CNUM_RES */ + 0, /* BTA_AG_BTRH_RES */ + 0, /* BTA_AG_CLCC_RES */ + 0, /* BTA_AG_COPS_RES */ + BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_IN_CALL_RES */ + BTA_AG_CALLSETUP_NONE, /* BTA_AG_IN_CALL_CONN_RES */ + BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_CALL_WAIT_RES */ + BTA_AG_CALLSETUP_OUTGOING, /* BTA_AG_OUT_CALL_ORIG_RES */ + BTA_AG_CALLSETUP_ALERTING, /* BTA_AG_OUT_CALL_ALERT_RES */ + BTA_AG_CALLSETUP_NONE, /* BTA_AG_OUT_CALL_CONN_RES */ + BTA_AG_CALLSETUP_NONE, /* BTA_AG_CALL_CANCEL_RES */ + BTA_AG_CALLSETUP_NONE, /* BTA_AG_END_CALL_RES */ + BTA_AG_CALLSETUP_NONE /* BTA_AG_IN_CALL_HELD_RES */ +}; + +/******************************************************************************* +** +** Function bta_ag_send_result +** +** Description Send an AT result code. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_send_result(tBTA_AG_SCB *p_scb, UINT8 code, char *p_arg, + INT16 int_arg) +{ + char buf[BTA_AG_AT_MAX_LEN + 16]; + char *p = buf; + UINT16 len; + +#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE) + memset(buf, NULL, sizeof(buf)); +#endif + /* init with \r\n */ + *p++ = '\r'; + *p++ = '\n'; + + /* copy result code string */ + BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[code].p_res); +#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE) + if(p_scb->conn_service == BTA_AG_HSP) + { + /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */ + switch(code) + { + case BTA_AG_RES_VGS: + case BTA_AG_RES_VGM: + if(*(p+COLON_IDX_4_VGSVGM) == ':') + { + #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("[HSP] ':'symbol is changed as '=' for HSP compatibility"); + #endif + *(p+COLON_IDX_4_VGSVGM) = '='; + } + break; + } + } +#endif + p += strlen(bta_ag_result_tbl[code].p_res); + + /* copy argument if any */ + if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_INT) + { + p += utl_itoa((UINT16) int_arg, p); + } + else if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_STR) + { + BCM_STRCPY_S(p, sizeof(buf), p_arg); + p += strlen(p_arg); + } + + /* finish with \r\n */ + *p++ = '\r'; + *p++ = '\n'; + +#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE) + APPL_TRACE_DEBUG1("bta_ag_send_result: %s", buf); +#endif + + /* send to RFCOMM */ + PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len); +} + +#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_ag_send_multi_result +** +** Description Send multiple AT result codes. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_send_multi_result(tBTA_AG_SCB *p_scb, tBTA_AG_MULTI_RESULT_CB *m_res_cb) +{ + char buf[BTA_AG_AT_MAX_LEN * BTA_AG_AT_MULTI_LEN + 16]; + char *p = buf; + UINT16 len; + UINT8 res_idx = 0; + + if((!m_res_cb) || (m_res_cb->num_result == 0) || (m_res_cb->num_result > BTA_AG_AT_MULTI_LEN)) + { + APPL_TRACE_DEBUG0("m_res_cb is NULL or num_result is out of range."); + return; + } + +#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE) + memset(buf, NULL, sizeof(buf)); +#endif + + while(res_idx < m_res_cb->num_result) + { + /* init with \r\n */ + *p++ = '\r'; + *p++ = '\n'; + + /* copy result code string */ + BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res); + p += strlen(bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res); + + /* copy argument if any */ + if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_INT) + { + p += utl_itoa((UINT16) m_res_cb->res_cb[res_idx].int_arg, p); + } + else if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_STR) + { + BCM_STRCPY_S(p, sizeof(buf), m_res_cb->res_cb[res_idx].p_arg); + p += strlen(m_res_cb->res_cb[res_idx].p_arg); + } + + /* finish with \r\n */ + *p++ = '\r'; + *p++ = '\n'; + + res_idx++; + } + +#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE) + APPL_TRACE_DEBUG1("send_result: %s", buf); +#endif + + /* send to RFCOMM */ + PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len); +} +#endif + +/******************************************************************************* +** +** Function bta_ag_send_ok +** +** Description Send an OK result code. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_send_ok(tBTA_AG_SCB *p_scb) +{ + bta_ag_send_result(p_scb, BTA_AG_RES_OK, NULL, 0); +} + +/******************************************************************************* +** +** Function bta_ag_send_error +** +** Description Send an ERROR result code. +** errcode - used to send verbose errocode +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_send_error(tBTA_AG_SCB *p_scb, INT16 errcode) +{ + /* If HFP and extended audio gateway error codes are enabled */ + if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled) + bta_ag_send_result(p_scb, BTA_AG_RES_CMEE, NULL, errcode); + else + bta_ag_send_result(p_scb, BTA_AG_RES_ERROR, NULL, 0); +} + +/******************************************************************************* +** +** Function bta_ag_send_ind +** +** Description Send an indicator CIEV result code. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_send_ind(tBTA_AG_SCB *p_scb, UINT16 id, UINT16 value, BOOLEAN on_demand) +{ + char str[12]; + char *p = str; + + /* If the indicator is masked out, just return */ + /* Mandatory indicators can not be masked out. */ + if ((p_scb->bia_masked_out & ((UINT32)1 << id)) && + ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) && (id != BTA_AG_IND_CALLHELD))) + return; + + /* Ensure we do not send duplicate indicators if not requested by app */ + /* If it was requested by app, transmit CIEV even if it is duplicate. */ + if (id == BTA_AG_IND_CALL) + { + if ((value == p_scb->call_ind) && (on_demand == FALSE)) + return; + + p_scb->call_ind = (UINT8)value; + } + + if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == FALSE)) + { + if (value == p_scb->callsetup_ind) + return; + + p_scb->callsetup_ind = (UINT8)value; + } + + if ((id == BTA_AG_IND_SERVICE) && (on_demand == FALSE)) + { + if (value == p_scb->service_ind) + return; + + p_scb->service_ind = (UINT8)value; + } + if ((id == BTA_AG_IND_SIGNAL) && (on_demand == FALSE)) + { + if (value == p_scb->signal_ind) + return; + + p_scb->signal_ind = (UINT8)value; + } + if ((id == BTA_AG_IND_ROAM) && (on_demand == FALSE)) + { + if (value == p_scb->roam_ind) + return; + + p_scb->roam_ind = (UINT8)value; + } + if ((id == BTA_AG_IND_BATTCHG) && (on_demand == FALSE)) + { + if (value == p_scb->battchg_ind) + return; + + p_scb->battchg_ind = (UINT8)value; + } + + if ((id == BTA_AG_IND_CALLHELD) && (on_demand == FALSE)) + { + /* call swap could result in sending callheld=1 multiple times */ + if ((value != 1) && (value == p_scb->callheld_ind)) + return; + + p_scb->callheld_ind = (UINT8)value; + } + + if (p_scb->cmer_enabled) + { + p += utl_itoa(id, p); + *p++ = ','; + utl_itoa(value, p); + bta_ag_send_result(p_scb, BTA_AG_RES_CIEV, str, 0); + } +} + +/******************************************************************************* +** +** Function bta_ag_parse_cmer +** +** Description Parse AT+CMER parameter string. +** +** +** Returns TRUE if parsed ok, FALSE otherwise. +** +*******************************************************************************/ +static BOOLEAN bta_ag_parse_cmer(char *p_s, BOOLEAN *p_enabled) +{ + INT16 n[4] = {-1, -1, -1, -1}; + int i; + char *p; + + for (i = 0; i < 4; i++) + { + /* skip to comma delimiter */ + for (p = p_s; *p != ',' && *p != 0; p++); + + /* get integer value */ + *p = 0; + n[i] = utl_str2int(p_s); + p_s = p + 1; + if (p_s == 0) + { + break; + } + } + + /* process values */ + if (n[0] < 0 || n[3] < 0) + { + return FALSE; + } + + if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0))) + { + *p_enabled = (BOOLEAN) n[3]; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function bta_ag_parse_chld +** +** Description Parse AT+CHLD parameter string. +** +** +** Returns Returns idx (1-7), or 0 if ECC not enabled or idx doesn't exist +** +*******************************************************************************/ +static UINT8 bta_ag_parse_chld(tBTA_AG_SCB *p_scb, char *p_s) +{ + UINT8 retval = 0; + INT16 idx = -1; + + if (p_s[1] != 0) + { + /* p_idxstr++; point to beginning of call number */ + idx = utl_str2int(&p_s[1]); + if (idx != -1 && idx < 255) + retval = (UINT8)idx; + } + + return (retval); +} + +#if (BTM_WBS_INCLUDED == TRUE ) +/******************************************************************************* +** +** Function bta_ag_parse_bac +** +** Description Parse AT+BAC parameter string. +** +** Returns Returns bitmap of supported codecs. +** +*******************************************************************************/ +static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s) +{ + tBTA_AG_PEER_CODEC retval = BTA_AG_CODEC_NONE; + UINT16 uuid_codec; + BOOLEAN cont = FALSE; /* Continue processing */ + char *p; + + while(p_s) + { + /* skip to comma delimiter */ + for(p = p_s; *p != ',' && *p != 0; p++); + + /* get integre value */ + if (*p != 0) + { + *p = 0; + cont = TRUE; + } + else + cont = FALSE; + + uuid_codec = utl_str2int(p_s); + switch(uuid_codec) + { + case UUID_CODEC_CVSD: retval |= BTA_AG_CODEC_CVSD; break; + case UUID_CODEC_MSBC: retval |= BTA_AG_CODEC_MSBC; break; + default: + APPL_TRACE_ERROR1("Unknown Codec UUID(%d) received", uuid_codec); + return BTA_AG_CODEC_NONE; + } + + if (cont) + p_s = p + 1; + else + break; + } + + return (retval); +} +#endif + +/******************************************************************************* +** +** Function bta_ag_process_unat_res +** +** Description Process the unat response data and remove extra carriage return +** and line feed +** +** +** Returns void +** +*******************************************************************************/ + +static void bta_ag_process_unat_res(char *unat_result) +{ + UINT8 str_leng; + UINT8 i = 0; + UINT8 j = 0; + UINT8 pairs_of_nl_cr; + char trim_data[BTA_AG_AT_MAX_LEN]; + + + + str_leng = strlen(unat_result); + + /* If no extra CR and LF, just return */ + if(str_leng < 4) + return; + + /* Remove the carriage return and left feed */ + while(unat_result[0] =='\r' && unat_result[1] =='\n' + && unat_result[str_leng-2] =='\r' && unat_result[str_leng-1] =='\n') + { + pairs_of_nl_cr = 1; + for (i=0;i<(str_leng-4*pairs_of_nl_cr);i++) + { + trim_data[j++] = unat_result[i+pairs_of_nl_cr*2]; + } + /* Add EOF */ + trim_data[j] = '\0'; + str_leng = str_leng - 4; + BCM_STRNCPY_S(unat_result, BTA_AG_AT_MAX_LEN+1, trim_data,str_leng+1); + i=0; + j=0; + + if(str_leng <4) + return; + + + } + return; +} + + +/******************************************************************************* +** +** Function bta_ag_inband_enabled +** +** Description Determine whether in-band ring can be used. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb) +{ + /* if feature is enabled and no other scbs connected */ + if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb)) + { + return TRUE; + } + else + { + return FALSE; + } +} + +/******************************************************************************* +** +** Function bta_ag_send_call_inds +** +** Description Send call and callsetup indicators. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result) +{ + UINT8 call = p_scb->call_ind; + UINT8 callsetup; + + /* set new call and callsetup values based on BTA_AgResult */ + callsetup = bta_ag_callsetup_ind_tbl[result]; + + if (result == BTA_AG_END_CALL_RES) + { + call = BTA_AG_CALL_INACTIVE; + } + else if (result == BTA_AG_IN_CALL_CONN_RES || result == BTA_AG_OUT_CALL_CONN_RES + || result == BTA_AG_IN_CALL_HELD_RES) + { + call = BTA_AG_CALL_ACTIVE; + } + else + { + call = p_scb->call_ind; + } + + /* Send indicator function tracks if the values have actually changed */ + bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, FALSE); + bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, FALSE); +} + +/******************************************************************************* +** +** Function bta_ag_at_hsp_cback +** +** Description AT command processing callback for HSP. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type, + char *p_arg, INT16 int_arg) +{ + tBTA_AG_VAL val; + + APPL_TRACE_DEBUG4("AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type, + int_arg, p_arg); + + /* send OK */ + bta_ag_send_ok(p_scb); + + val.hdr.handle = bta_ag_scb_to_idx(p_scb); + val.hdr.app_id = p_scb->app_id; + val.num = (UINT16) int_arg; + BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN); + val.str[BTA_AG_AT_MAX_LEN] = 0; + + /* call callback with event */ + (*bta_ag_cb.p_cback)(bta_ag_hsp_cb_evt[cmd], (tBTA_AG *) &val); +} + +/******************************************************************************* +** +** Function bta_ag_at_hfp_cback +** +** Description AT command processing callback for HFP. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type, + char *p_arg, INT16 int_arg) +{ + tBTA_AG_VAL val; + tBTA_AG_EVT event; + tBTA_AG_SCB *ag_scb; + UINT32 i, ind_id; + UINT32 bia_masked_out; +#if (BTM_WBS_INCLUDED == TRUE ) + tBTA_AG_PEER_CODEC codec_type, codec_sent; +#endif + + APPL_TRACE_DEBUG4("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type, + int_arg, p_arg); + + val.hdr.handle = bta_ag_scb_to_idx(p_scb); + val.hdr.app_id = p_scb->app_id; + val.num = int_arg; + BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN); + val.str[BTA_AG_AT_MAX_LEN] = 0; + + event = bta_ag_hfp_cb_evt[cmd]; + + switch (cmd) + { + case BTA_AG_HF_CMD_A: + case BTA_AG_HF_CMD_VGS: + case BTA_AG_HF_CMD_VGM: + case BTA_AG_HF_CMD_CHUP: + case BTA_AG_HF_CMD_CBC: + /* send OK */ + bta_ag_send_ok(p_scb); + break; + + case BTA_AG_HF_CMD_BLDN: + /* Do not send OK, App will send error or OK depending on + ** last dial number enabled or not */ + break; + + case BTA_AG_HF_CMD_D: + /* Do not send OK for Dial cmds + ** Let application decide whether to send OK or ERROR*/ + + /* if mem dial cmd, make sure string contains only digits */ + if(p_arg[0] == '>') + { + if(!utl_isintstr(p_arg+1)) + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR); + } + } + else if (p_arg[0] == 'V') /* ATDV : Dial VoIP Call */ + { + /* We do not check string. Code will be added later if needed. */ + if(!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) && (p_scb->features & BTA_AG_FEAT_VOIP))) + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + } + } + /* If dial cmd, make sure string contains only dial digits + ** Dial digits are 0-9, A-C, *, #, + */ + else + { + if(!utl_isdialstr(p_arg)) + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR); + } + } + break; + + case BTA_AG_HF_CMD_CCWA: + /* store setting */ + p_scb->ccwa_enabled = (BOOLEAN) int_arg; + + /* send OK */ + bta_ag_send_ok(p_scb); + break; + + case BTA_AG_HF_CMD_CHLD: + if (arg_type == BTA_AG_AT_TEST) + { + /* don't call callback */ + event = 0; + + /* send CHLD string */ + /* Form string based on supported 1.5 feature */ + if ((p_scb->peer_version >= HFP_VERSION_1_5) && + (p_scb->features & BTA_AG_FEAT_ECC) && + (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC)) + bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val_ecc, 0); + else + bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val, 0); + + /* send OK */ + bta_ag_send_ok(p_scb); + + /* if service level conn. not already open, now it's open */ + bta_ag_svc_conn_open(p_scb, NULL); + + } + else + { + val.idx = bta_ag_parse_chld(p_scb, val.str); + + if(val.idx && !((p_scb->features & BTA_AG_FEAT_ECC) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))) + { + /* we do not support ECC, but HF is sending us a CHLD with call index*/ + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + + } + else + { + + /* If it is swap between calls, set call held indicator to 3(out of valid 0-2) + ** Application will set it back to 1 + ** callheld indicator will be sent across to the peer. */ + if(val.str[0] == '2') + { + for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) + { + if (ag_scb->in_use) + { + if((ag_scb->call_ind == BTA_AG_CALL_ACTIVE) + && (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE)) + ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1; + } + } + } + } + + /* Do not send OK. Let app decide after parsing the val str */ + /* bta_ag_send_ok(p_scb); */ + } + break; + + case BTA_AG_HF_CMD_CIND: + if (arg_type == BTA_AG_AT_TEST) + { + /* don't call callback */ + event = 0; + + /* send CIND string, send OK */ + bta_ag_send_result(p_scb, BTA_AG_RES_CIND, p_bta_ag_cfg->cind_info, 0); + bta_ag_send_ok(p_scb); + } + break; + + case BTA_AG_HF_CMD_CLIP: + /* store setting, send OK */ + p_scb->clip_enabled = (BOOLEAN) int_arg; + bta_ag_send_ok(p_scb); + break; + + case BTA_AG_HF_CMD_CMER: + /* if parsed ok store setting, send OK */ + if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled)) + { + bta_ag_send_ok(p_scb); + + /* if service level conn. not already open and our features and + ** peer features do not have 3-way, service level conn. now open + */ + if (!p_scb->svc_conn && + !((p_scb->features & BTA_AG_FEAT_3WAY) && (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY))) + { + bta_ag_svc_conn_open(p_scb, NULL); + } + } + else + { + bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR); + } + break; + + case BTA_AG_HF_CMD_VTS: + /* check argument */ + if (strlen(p_arg) == 1) + { + bta_ag_send_ok(p_scb); + } + else + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR); + } + break; + + case BTA_AG_HF_CMD_BINP: + /* if feature not set don't call callback, send ERROR */ + if (!(p_scb->features & BTA_AG_FEAT_VTAG)) + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + } + break; + + case BTA_AG_HF_CMD_BVRA: + /* if feature not supported don't call callback, send ERROR. App will send OK */ + if (!(p_scb->features & BTA_AG_FEAT_VREC)) + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + } + break; + + case BTA_AG_HF_CMD_BRSF: + /* store peer features */ + p_scb->peer_features = (UINT16) int_arg; + + /* send BRSF, send OK */ + bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL, + (INT16) (p_scb->features & BTA_AG_BSRF_FEAT_SPEC)); + bta_ag_send_ok(p_scb); + break; + + case BTA_AG_HF_CMD_NREC: + /* if feature send OK, else don't call callback, send ERROR */ + if (p_scb->features & BTA_AG_FEAT_ECNR) + { + bta_ag_send_ok(p_scb); + } + else + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + } + break; + + case BTA_AG_HF_CMD_BTRH: + /* if feature send BTRH, send OK:, else don't call callback, send ERROR */ + if (p_scb->features & BTA_AG_FEAT_BTRH) + { + /* If set command; send response and notify app */ + if (arg_type == BTA_AG_AT_SET) + { + for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) + { + if (ag_scb->in_use) + { + bta_ag_send_result(ag_scb, BTA_AG_RES_BTRH, NULL, int_arg); + } + } + bta_ag_send_ok(p_scb); + } + else /* Read Command */ + { + val.num = BTA_AG_BTRH_READ; + } + } + else + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + } + break; + + case BTA_AG_HF_CMD_COPS: + if (arg_type == BTA_AG_AT_SET) + { + /* don't call callback */ + event = 0; + + /* send OK */ + bta_ag_send_ok(p_scb); + } + break; + + case BTA_AG_HF_CMD_CMEE: + if (p_scb->features & BTA_AG_FEAT_EXTERR) + { + /* store setting */ + p_scb->cmee_enabled = (BOOLEAN) int_arg; + + /* send OK */ + bta_ag_send_ok(p_scb); + } + else + { + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + } + /* don't call callback */ + event = 0; + break; + + case BTA_AG_HF_CMD_BIA: + /* don't call callback */ + event = 0; + + bia_masked_out = p_scb->bia_masked_out; + + /* Parse the indicator mask */ + for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20); i++, ind_id++) + { + if (val.str[i] == ',') + continue; + + if (val.str[i] == '0') + bia_masked_out |= ((UINT32)1 << ind_id); + else if (val.str[i] == '1') + bia_masked_out &= ~((UINT32)1 << ind_id); + else + break; + + i++; + if ( (val.str[i] != 0) && (val.str[i] != ',') ) + break; + } + if (val.str[i] == 0) + { + p_scb->bia_masked_out = bia_masked_out; + bta_ag_send_ok (p_scb); + } + else + bta_ag_send_error (p_scb, BTA_AG_ERR_INVALID_INDEX); + break; + + case BTA_AG_HF_CMD_CNUM: + break; + case BTA_AG_HF_CMD_CLCC: + if(!(p_scb->features & BTA_AG_FEAT_ECS)) + { + event = 0; + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + } + break; + +#if (BTM_WBS_INCLUDED == TRUE ) + case BTA_AG_HF_CMD_BAC: + bta_ag_send_ok(p_scb); + + /* store available codecs from the peer */ + if((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) && (p_scb->features & BTA_AG_FEAT_CODEC)) + { + p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg); + p_scb->codec_updated = TRUE; + + if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC) + { + p_scb->sco_codec = UUID_CODEC_MSBC; + APPL_TRACE_DEBUG0("Received AT+BAC, updating sco codec to MSBC"); + } + else + { + p_scb->sco_codec = UUID_CODEC_CVSD; + APPL_TRACE_DEBUG0("Received AT+BAC, updating sco codec to CVSD"); + } + + /* Received BAC while in codec negotiation. */ + if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) && (bta_ag_cb.sco.p_curr_scb == p_scb)) + { + bta_ag_codec_negotiate (p_scb); + } + } + else + { + p_scb->peer_codecs = BTA_AG_CODEC_NONE; + APPL_TRACE_ERROR0("Unexpected CMD:AT+BAC, Codec Negotiation is not supported"); + } + break; + + case BTA_AG_HF_CMD_BCS: + /* stop cn timer */ + bta_sys_stop_timer(&p_scb->cn_timer); + + switch(int_arg) + { + case UUID_CODEC_CVSD: codec_type = BTA_AG_CODEC_CVSD; break; + case UUID_CODEC_MSBC: codec_type = BTA_AG_CODEC_MSBC; break; + default: + APPL_TRACE_ERROR1("Unknown codec_uuid %d", int_arg); + codec_type = 0xFFFF; + break; + } + + if (p_scb->codec_fallback) + codec_sent = BTA_AG_CODEC_CVSD; + else + codec_sent = p_scb->sco_codec; + + if(codec_type == codec_sent) + bta_ag_sco_codec_nego(p_scb, TRUE); + else + bta_ag_sco_codec_nego(p_scb, FALSE); + + bta_ag_send_ok(p_scb); + break; + + case BTA_AG_HF_CMD_BCC: + bta_ag_send_ok(p_scb); + bta_ag_sco_open(p_scb, NULL); + break; +#endif + + default: + break; + } + + /* call callback */ + if (event != 0) + { + (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &val); + } +} + +/******************************************************************************* +** +** Function bta_ag_at_err_cback +** +** Description AT command parser error callback. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg) +{ + tBTA_AG_VAL val; + + if(unknown && (!strlen(p_arg))) + { + APPL_TRACE_DEBUG0("Empty AT cmd string received"); + bta_ag_send_ok(p_scb); + return; + } + + /* if unknown AT command and configured to pass these to app */ + if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT)) + { + val.hdr.handle = bta_ag_scb_to_idx(p_scb); + val.hdr.app_id = p_scb->app_id; + val.num = 0; + BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN); + val.str[BTA_AG_AT_MAX_LEN] = 0; + (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val); + } + else + { + bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); + } +} + +/******************************************************************************* +** +** Function bta_ag_hsp_result +** +** Description Handle API result for HSP connections. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_hsp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result) +{ + UINT8 code = bta_ag_trans_result[p_result->result]; + + APPL_TRACE_DEBUG1("bta_ag_hsp_result : res = %d", p_result->result); + + switch(p_result->result) + { + case BTA_AG_SPK_RES: + case BTA_AG_MIC_RES: + bta_ag_send_result(p_scb, code, NULL, p_result->data.num); + break; + + case BTA_AG_IN_CALL_RES: + /* tell sys to stop av if any */ + bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + /* if sco already opened or no inband ring send ring now */ + if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) || + (p_scb->features & BTA_AG_FEAT_NOSCO)) + { + bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result); + } + /* else open sco, send ring after sco opened */ + else + { + /* HSPv1.2: AG shall not send RING if using in-band ring tone. */ + if (p_scb->hsp_version >= HSP_VERSION_1_2) + p_scb->post_sco = BTA_AG_POST_SCO_NONE; + else + p_scb->post_sco = BTA_AG_POST_SCO_RING; + + bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result); + } + break; + + case BTA_AG_IN_CALL_CONN_RES: + case BTA_AG_OUT_CALL_ORIG_RES: + /* if incoming call connected stop ring timer */ + if (p_result->result == BTA_AG_IN_CALL_CONN_RES) + { + bta_sys_stop_timer(&p_scb->act_timer); + } + + if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + /* if audio connected to this scb open sco */ + if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) + { + bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result); + } + /* else if no audio at call close sco */ + else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) + { + bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result); + } + } + break; + + case BTA_AG_END_CALL_RES: + /* stop ring timer */ + bta_sys_stop_timer(&p_scb->act_timer); + + /* close sco */ + if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result); + } + else + { + /* if av got suspended by this call, let it resume. */ + bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + } + break; + + case BTA_AG_INBAND_RING_RES: + p_scb->inband_enabled = p_result->data.state; + APPL_TRACE_DEBUG1("inband_enabled set to %d", p_scb->inband_enabled); + break; + + case BTA_AG_UNAT_RES: + if (p_result->data.ok_flag != BTA_AG_OK_ERROR) + { + if (p_result->data.str[0] != 0) + { + bta_ag_send_result(p_scb, code, p_result->data.str, 0); + } + + if (p_result->data.ok_flag == BTA_AG_OK_DONE) + bta_ag_send_ok(p_scb); + } + else + { + bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR); + } + break; + + default: + /* ignore all others */ + break; + } +} + +/******************************************************************************* +** +** Function bta_ag_hfp_result +** +** Description Handle API result for HFP connections. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result) +{ + UINT8 code = bta_ag_trans_result[p_result->result]; + + APPL_TRACE_DEBUG1("bta_ag_hfp_result : res = %d", p_result->result); + + switch(p_result->result) + { + case BTA_AG_SPK_RES: + case BTA_AG_MIC_RES: + bta_ag_send_result(p_scb, code, NULL, p_result->data.num); + break; + + case BTA_AG_IN_CALL_RES: + /* tell sys to stop av if any */ + bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + /* store caller id string. + * append type info at the end. + * make sure a valid type info is passed. + * otherwise add 129 as default type */ + if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) || (p_result->data.num > BTA_AG_CLIP_TYPE_MAX)) + { + if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP) + p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT; + } + + APPL_TRACE_DEBUG1("CLIP type :%d", p_result->data.num); + p_scb->clip[0] = 0; + if (p_result->data.str[0] != 0) + sprintf(p_scb->clip,"%s,%d", p_result->data.str, p_result->data.num); + + /* send callsetup indicator */ + if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END) + { + /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO close. */ + p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL; + } + else + { + bta_ag_send_call_inds(p_scb, p_result->result); + + /* if sco already opened or no inband ring send ring now */ + if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) || + (p_scb->features & BTA_AG_FEAT_NOSCO)) + { + bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result); + } + /* else open sco, send ring after sco opened */ + else + { + p_scb->post_sco = BTA_AG_POST_SCO_RING; + bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result); + } + } + break; + + case BTA_AG_IN_CALL_CONN_RES: + /* stop ring timer */ + bta_sys_stop_timer(&p_scb->act_timer); + + /* if sco not opened and we need to open it, open sco first + ** then send indicators + */ + if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && + !bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN; + bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result); + } + /* else if sco open and we need to close it, close sco first + ** then send indicators + */ + else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE && + bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + p_scb->post_sco = BTA_AG_POST_SCO_CALL_CONN; + bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result); + } + /* else send indicators now */ + else + { + bta_ag_send_call_inds(p_scb, p_result->result); + } + break; + + case BTA_AG_IN_CALL_HELD_RES: + /* stop ring timer */ + bta_sys_stop_timer(&p_scb->act_timer); + + bta_ag_send_call_inds(p_scb, p_result->result); + + break; + + case BTA_AG_OUT_CALL_ORIG_RES: + /* if sco open and we need to close it, close sco first + ** then send indicators; else send indicators now + */ + if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE && + bta_ag_sco_is_open(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + p_scb->post_sco = BTA_AG_POST_SCO_CALL_ORIG; + bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result); + } + else + { + bta_ag_send_call_inds(p_scb, p_result->result); + if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && + !(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result); + } + } + break; + + case BTA_AG_OUT_CALL_ALERT_RES: + /* send indicators */ + bta_ag_send_call_inds(p_scb, p_result->result); + if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && + !(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result); + } + break; + + case BTA_AG_OUT_CALL_CONN_RES: + /* send indicators */ + bta_ag_send_call_inds(p_scb, p_result->result); + + /* open or close sco */ + if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) + { + bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result); + } + else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) + { + bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result); + } + } + break; + + case BTA_AG_CALL_CANCEL_RES: + /* send indicators */ + bta_ag_send_call_inds(p_scb, p_result->result); + break; + + case BTA_AG_END_CALL_RES: + /* stop ring timer */ + bta_sys_stop_timer(&p_scb->act_timer); + + /* if sco open, close sco then send indicator values */ + if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) + { + p_scb->post_sco = BTA_AG_POST_SCO_CALL_END; + bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result); + } + else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL) + { + /* sco closing for outgoing call because of incoming call */ + /* Send only callsetup end indicator after sco close */ + p_scb->post_sco = BTA_AG_POST_SCO_CALL_END; + } + else + { + bta_ag_send_call_inds(p_scb, p_result->result); + + /* if av got suspended by this call, let it resume. */ + bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + } + break; + + case BTA_AG_INBAND_RING_RES: + p_scb->inband_enabled = p_result->data.state; + APPL_TRACE_DEBUG1("inband_enabled set to %d", p_scb->inband_enabled); + bta_ag_send_result(p_scb, code, NULL, p_result->data.state); + break; + + case BTA_AG_CIND_RES: + /* store local values */ + p_scb->call_ind = p_result->data.str[0] - '0'; + p_scb->callsetup_ind = p_result->data.str[2] - '0'; + p_scb->service_ind = p_result->data.str[4] - '0'; + p_scb->signal_ind = p_result->data.str[6] - '0'; + p_scb->roam_ind = p_result->data.str[8] - '0'; + p_scb->battchg_ind = p_result->data.str[10] - '0'; + APPL_TRACE_DEBUG2("cind call:%d callsetup:%d", p_scb->call_ind, p_scb->callsetup_ind); + + bta_ag_send_result(p_scb, code, p_result->data.str, 0); + bta_ag_send_ok(p_scb); + break; + + case BTA_AG_BINP_RES: + case BTA_AG_CNUM_RES: + case BTA_AG_CLCC_RES: + case BTA_AG_COPS_RES: + if (p_result->data.ok_flag != BTA_AG_OK_ERROR) + { + if (p_result->data.str[0] != 0) + { + bta_ag_send_result(p_scb, code, p_result->data.str, 0); + } + + if (p_result->data.ok_flag == BTA_AG_OK_DONE) + bta_ag_send_ok(p_scb); + } + else + { + bta_ag_send_error(p_scb, p_result->data.errcode); + } + break; + + + case BTA_AG_UNAT_RES: + if (p_result->data.ok_flag != BTA_AG_OK_ERROR) + { + if (p_result->data.str[0] != 0) + { + bta_ag_process_unat_res(p_result->data.str); + APPL_TRACE_DEBUG1("BTA_AG_RES :%s",p_result->data.str); + bta_ag_send_result(p_scb, code, p_result->data.str, 0); + } + + if (p_result->data.ok_flag == BTA_AG_OK_DONE) + bta_ag_send_ok(p_scb); + } + else + { + bta_ag_send_error(p_scb, p_result->data.errcode); + } + break; + + case BTA_AG_CALL_WAIT_RES: + if (p_scb->ccwa_enabled) + { + bta_ag_send_result(p_scb, code, p_result->data.str, 0); + } + bta_ag_send_call_inds(p_scb, p_result->result); + break; + + case BTA_AG_IND_RES: + bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value, FALSE); + break; + + case BTA_AG_BVRA_RES: + bta_ag_send_result(p_scb, code, NULL, p_result->data.state); + break; + + case BTA_AG_BTRH_RES: + if (p_result->data.ok_flag != BTA_AG_OK_ERROR) + { + /* Don't respond to read if not in response & hold state */ + if (p_result->data.num != BTA_AG_BTRH_NO_RESP) + { + bta_ag_send_result(p_scb, code, NULL, p_result->data.num); + } + + /* In case of a response to a read request we need to send OK */ + if (p_result->data.ok_flag == BTA_AG_OK_DONE) + bta_ag_send_ok(p_scb); + } + else + { + bta_ag_send_error(p_scb, p_result->data.errcode); + } + break; + + default: + break; + } +} + + +/******************************************************************************* +** +** Function bta_ag_result +** +** Description Handle API result. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + if (p_scb->conn_service == BTA_AG_HSP) + { + bta_ag_hsp_result(p_scb, &p_data->api_result); + } + else + { + bta_ag_hfp_result(p_scb, &p_data->api_result); + } +} + +/******************************************************************************* +** +** Function bta_ag_setcodec +** +** Description Handle API SetCodec +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ +#if (BTM_WBS_INCLUDED == TRUE ) + tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec; + + /* Check if the requested codec type is valid */ + if((codec_type != BTA_AG_CODEC_NONE) && + (codec_type != BTA_AG_CODEC_CVSD) && + (codec_type != BTA_AG_CODEC_MSBC)) + { + APPL_TRACE_ERROR1("bta_ag_setcodec error: unsupported codec type %d", codec_type); + return; + } + + if((p_scb->peer_codecs & codec_type) || (codec_type == BTA_AG_CODEC_NONE) || (codec_type == BTA_AG_CODEC_CVSD)) + { + p_scb->sco_codec = codec_type; + p_scb->codec_updated = TRUE; + APPL_TRACE_DEBUG1("bta_ag_setcodec: Updated codec type %d", codec_type); + } + else + { + APPL_TRACE_ERROR1("bta_ag_setcodec error: unsupported codec type %d", codec_type); + } +#endif +} + + +#if (BTM_WBS_INCLUDED == TRUE ) +/******************************************************************************* +** +** Function bta_ag_send_bcs +** +** Description Send +BCS AT command to peer. +** +** Returns void +** +*******************************************************************************/ +void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + UINT16 codec_uuid; + + if (p_scb->codec_fallback) + { + codec_uuid = UUID_CODEC_CVSD; + } + else + { + switch(p_scb->sco_codec) + { + case BTA_AG_CODEC_NONE: codec_uuid = UUID_CODEC_CVSD; break; + case BTA_AG_CODEC_CVSD: codec_uuid = UUID_CODEC_CVSD; break; + case BTA_AG_CODEC_MSBC: codec_uuid = UUID_CODEC_MSBC; break; + default: + APPL_TRACE_ERROR1("bta_ag_send_bcs: unknown codec %d, use CVSD", p_scb->sco_codec); + codec_uuid = UUID_CODEC_CVSD; + break; + } + } + + /* send +BCS */ + bta_ag_send_result(p_scb, BTA_AG_RES_BCS, NULL, codec_uuid); + +} +#endif + +/******************************************************************************* +** +** Function bta_ag_send_ring +** +** Description Send RING result code to peer. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ +#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE) + tBTA_AG_MULTI_RESULT_CB m_res_cb; + + if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0) + { + memset(&m_res_cb, NULL, sizeof(tBTA_AG_MULTI_RESULT_CB)); + + m_res_cb.num_result = 2; + AT_SET_RES_CB(m_res_cb.res_cb[0], BTA_AG_RES_RING, NULL, 0) + AT_SET_RES_CB(m_res_cb.res_cb[1], BTA_AG_RES_CLIP, p_scb->clip, 0) + + bta_ag_send_multi_result(p_scb, &m_res_cb); + } + else + { + /* send RING ONLY */ + bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0); + } +#else + /* send RING */ + bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0); + + /* if HFP and clip enabled and clip data send CLIP */ + if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0) + { + bta_ag_send_result(p_scb, BTA_AG_RES_CLIP, p_scb->clip, 0); + } +#endif + + /* restart ring timer */ + bta_sys_start_timer(&p_scb->act_timer, BTA_AG_RING_TOUT_EVT, BTA_AG_RING_TOUT); +} + + diff --git a/bta/ag/bta_ag_int.h b/bta/ag/bta_ag_int.h new file mode 100644 index 0000000..b0d1b1d --- /dev/null +++ b/bta/ag/bta_ag_int.h @@ -0,0 +1,423 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 private interface file for the BTA audio gateway. + * + ******************************************************************************/ +#ifndef BTA_AG_INT_H +#define BTA_AG_INT_H + +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_ag_api.h" +#include "bta_ag_at.h" + +/* Send RING & CLIP in one AT cmd */ +#ifndef BTA_AG_MULTI_RESULT_INCLUDED +#define BTA_AG_MULTI_RESULT_INCLUDED FALSE +#endif + +/* Replace : in VGS and VGM for HSP */ +#ifndef BTA_HSP_RESULT_REPLACE_COLON +#define BTA_HSP_RESULT_REPLACE_COLON TRUE +#endif + +/***************************************************************************** +** Constants +*****************************************************************************/ +#define HFP_VERSION_1_1 0x0101 +#define HFP_VERSION_1_5 0x0105 +#define HFP_VERSION_1_6 0x0106 + +#define HSP_VERSION_1_0 0x0100 +#define HSP_VERSION_1_2 0x0102 + +/* Number of SCBs (AG service instances that can be registered) */ +#ifndef BTA_AG_NUM_SCB +#define BTA_AG_NUM_SCB 2 +#endif + +/* Timer to wait for retry in case of collision */ +#ifndef BTA_AG_COLLISION_TIMER +#define BTA_AG_COLLISION_TIMER 2000 +#endif + +/* RFCOMM MTU SIZE */ +#define BTA_AG_MTU 256 + +/* Internal profile indexes */ +#define BTA_AG_HSP 0 /* index for HSP */ +#define BTA_AG_HFP 1 /* index for HFP */ +#define BTA_AG_NUM_IDX 2 /* number of profile indexes */ + +/* profile role for connection */ +#define BTA_AG_ACP 0 /* accepted connection */ +#define BTA_AG_INT 1 /* initiating connection */ + +/* feature mask that matches spec */ +#define BTA_AG_BSRF_FEAT_SPEC (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | \ + BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND | \ + BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT | \ + BTA_AG_FEAT_ECS | BTA_AG_FEAT_ECC | \ + BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_CODEC | \ + BTA_AG_FEAT_VOIP) + +#define BTA_AG_SDP_FEAT_SPEC (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | \ + BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND | \ + BTA_AG_FEAT_VTAG) + +enum +{ + /* these events are handled by the state machine */ + BTA_AG_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_AG), + BTA_AG_API_DEREGISTER_EVT, + BTA_AG_API_OPEN_EVT, + BTA_AG_API_CLOSE_EVT, + BTA_AG_API_AUDIO_OPEN_EVT, + BTA_AG_API_AUDIO_CLOSE_EVT, + BTA_AG_API_RESULT_EVT, + BTA_AG_API_SETCODEC_EVT, + BTA_AG_RFC_OPEN_EVT, + BTA_AG_RFC_CLOSE_EVT, + BTA_AG_RFC_SRV_CLOSE_EVT, + BTA_AG_RFC_DATA_EVT, + BTA_AG_SCO_OPEN_EVT, + BTA_AG_SCO_CLOSE_EVT, + BTA_AG_DISC_ACP_RES_EVT, + BTA_AG_DISC_INT_RES_EVT, + BTA_AG_DISC_OK_EVT, + BTA_AG_DISC_FAIL_EVT, + BTA_AG_CI_RX_WRITE_EVT, + BTA_AG_RING_TOUT_EVT, + BTA_AG_SVC_TOUT_EVT, + BTA_AG_CI_SCO_DATA_EVT, + BTA_AG_CI_SLC_READY_EVT, + BTA_AG_MAX_EVT, + + /* these events are handled outside of the state machine */ + BTA_AG_API_ENABLE_EVT, + BTA_AG_API_DISABLE_EVT +}; + +/* Actions to perform after a SCO event */ +enum +{ + BTA_AG_POST_SCO_NONE, /* no action */ + BTA_AG_POST_SCO_CLOSE_RFC, /* close RFCOMM channel after SCO closes */ + BTA_AG_POST_SCO_RING, /* send RING result code after SCO opens */ + BTA_AG_POST_SCO_CALL_CONN, /* send call indicators after SCO opens/closes */ + BTA_AG_POST_SCO_CALL_ORIG, /* send call indicators after SCO closes */ + BTA_AG_POST_SCO_CALL_END, /* send call indicators after SCO closes */ + BTA_AG_POST_SCO_CALL_END_INCALL /* send call indicators for end call & incoming call after SCO closes */ +}; + +/* sco states */ +enum +{ + BTA_AG_SCO_SHUTDOWN_ST, /* no sco listening, all sco connections closed */ + BTA_AG_SCO_LISTEN_ST, /* sco listening */ +#if (BTM_WBS_INCLUDED == TRUE ) + BTA_AG_SCO_CODEC_ST, /* sco codec negotiation */ +#endif + BTA_AG_SCO_OPENING_ST, /* sco connection opening */ + BTA_AG_SCO_OPEN_CL_ST, /* opening sco connection being closed */ + BTA_AG_SCO_OPEN_XFER_ST, /* opening sco connection being transferred */ + BTA_AG_SCO_OPEN_ST, /* sco open */ + BTA_AG_SCO_CLOSING_ST, /* sco closing */ + BTA_AG_SCO_CLOSE_OP_ST, /* closing sco being opened */ + BTA_AG_SCO_CLOSE_XFER_ST, /* closing sco being transferred */ + BTA_AG_SCO_SHUTTING_ST /* sco shutting down */ +}; + +/***************************************************************************** +** Data types +*****************************************************************************/ + +/* data type for BTA_AG_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_AG_PARSE_MODE parse_mode; + tBTA_AG_CBACK *p_cback; +} tBTA_AG_API_ENABLE; + +/* data type for BTA_AG_API_REGISTER_EVT */ +typedef struct +{ + BT_HDR hdr; + char p_name[2][BTA_SERVICE_NAME_LEN+1]; + tBTA_SERVICE_MASK services; + tBTA_SEC sec_mask; + tBTA_AG_FEAT features; + UINT8 app_id; +} tBTA_AG_API_REGISTER; + +/* data type for BTA_AG_API_OPEN_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_SERVICE_MASK services; + tBTA_SEC sec_mask; +} tBTA_AG_API_OPEN; + +/* data type for BTA_AG_API_RESULT_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_AG_RES result; + tBTA_AG_RES_DATA data; +} tBTA_AG_API_RESULT; + +/* data type for BTA_AG_API_SETCODEC_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_AG_PEER_CODEC codec; +} tBTA_AG_API_SETCODEC; + +/* data type for BTA_AG_DISC_RESULT_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 status; +} tBTA_AG_DISC_RESULT; + +/* data type for RFCOMM events */ +typedef struct +{ + BT_HDR hdr; + UINT16 port_handle; +} tBTA_AG_RFC; + +/* data type for BTA_AG_CI_RX_WRITE_EVT */ +typedef struct +{ + BT_HDR hdr; +// char p_data[BTA_AG_MTU+1]; +} tBTA_AG_CI_RX_WRITE; + +/* union of all event datatypes */ +typedef union +{ + BT_HDR hdr; + tBTA_AG_API_ENABLE api_enable; + tBTA_AG_API_REGISTER api_register; + tBTA_AG_API_OPEN api_open; + tBTA_AG_API_RESULT api_result; +#if (BTM_WBS_INCLUDED == TRUE ) + tBTA_AG_API_SETCODEC api_setcodec; +#endif + tBTA_AG_DISC_RESULT disc_result; + tBTA_AG_RFC rfc; + tBTA_AG_CI_RX_WRITE ci_rx_write; +} tBTA_AG_DATA; + +/* type for each profile */ +typedef struct +{ + UINT32 sdp_handle; + UINT8 scn; +} tBTA_AG_PROFILE; + +/* type for each service control block */ +typedef struct +{ + char clip[BTA_AG_AT_MAX_LEN+1]; /* number string used for CLIP */ + UINT16 serv_handle[BTA_AG_NUM_IDX]; /* RFCOMM server handles */ + tBTA_AG_AT_CB at_cb; /* AT command interpreter */ + TIMER_LIST_ENT act_timer; /* ring timer */ + BD_ADDR peer_addr; /* peer bd address */ + tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */ + tBTA_SERVICE_MASK reg_services; /* services specified in register API */ + tBTA_SERVICE_MASK open_services; /* services specified in open API */ + UINT16 conn_handle; /* RFCOMM handle of connected service */ + tBTA_SEC serv_sec_mask; /* server security mask */ + tBTA_SEC cli_sec_mask; /* client security mask */ + tBTA_AG_FEAT features; /* features registered by application */ + tBTA_AG_PEER_FEAT peer_features; /* peer device features */ + UINT16 peer_version; /* profile version of peer device */ + UINT16 hsp_version; /* HSP profile version */ +#if (BTM_WBS_INCLUDED == TRUE ) + tBTA_AG_PEER_CODEC peer_codecs; /* codecs for eSCO supported by the peer */ + tBTA_AG_PEER_CODEC sco_codec; /* codec to be used for eSCO connection */ + tBTA_AG_PEER_CODEC inuse_codec; /* codec being used for the current SCO connection */ + BOOLEAN codec_updated; /* set to TRUE whenever the app updates codec type */ + BOOLEAN codec_fallback; /* If sco nego fails for mSBC, fallback to CVSD */ + TIMER_LIST_ENT cn_timer; /* codec negotiation timer */ +#endif + UINT16 sco_idx; /* SCO handle */ + BOOLEAN in_use; /* scb in use */ + BOOLEAN dealloc; /* TRUE if service shutting down */ + BOOLEAN clip_enabled; /* set to TRUE if HF enables CLIP reporting */ + BOOLEAN ccwa_enabled; /* set to TRUE if HF enables CCWA reporting */ + BOOLEAN cmer_enabled; /* set to TRUE if HF enables CMER reporting */ + BOOLEAN cmee_enabled; /* set to TRUE if HF enables CME ERROR reporting */ + BOOLEAN inband_enabled; /* set to TRUE if inband ring enabled */ + BOOLEAN svc_conn; /* set to TRUE when service level connection up */ + TIMER_LIST_ENT colli_timer; /* Collision timer */ + BOOLEAN colli_tmr_on; /* TRUE if collision timer is active */ + UINT8 state; /* state machine state */ + UINT8 conn_service; /* connected service */ + UINT8 peer_scn; /* peer scn */ + UINT8 app_id; /* application id */ + UINT8 role; /* initiator/acceptor role */ + UINT8 post_sco; /* action to perform after sco event */ + UINT8 call_ind; /* CIEV call indicator value */ + UINT8 callsetup_ind; /* CIEV callsetup indicator value */ + UINT8 service_ind; /* CIEV service indicator value */ + UINT8 signal_ind; /* CIEV signal indicator value */ + UINT8 roam_ind; /* CIEV roam indicator value */ + UINT8 battchg_ind; /* CIEV battery charge indicator value */ + UINT8 callheld_ind; /* CIEV call held indicator value */ + BOOLEAN retry_with_sco_only; /* indicator to try with SCO only when eSCO fails */ + UINT32 bia_masked_out; /* indicators HF does not want us to send */ +} tBTA_AG_SCB; + +/* type for sco data */ +typedef struct +{ + tBTM_ESCO_CONN_REQ_EVT_DATA conn_data; /* SCO data for pending conn request */ + tBTA_AG_SCB *p_curr_scb; /* SCB associated with SCO connection */ + tBTA_AG_SCB *p_xfer_scb; /* SCB associated with SCO transfer */ + UINT16 cur_idx; /* SCO handle */ + UINT8 state; /* SCO state variable */ + BOOLEAN param_updated; /* if params were updated to non-default */ + tBTM_ESCO_PARAMS params; /* ESCO parameters */ +} tBTA_AG_SCO_CB; + + +/* type for AG control block */ +typedef struct +{ + tBTA_AG_SCB scb[BTA_AG_NUM_SCB]; /* service control blocks */ + tBTA_AG_PROFILE profile[BTA_AG_NUM_IDX]; /* profile-specific data */ + tBTA_AG_SCO_CB sco; /* SCO data */ + tBTA_AG_CBACK *p_cback; /* application callback */ + tBTA_AG_PARSE_MODE parse_mode; /* parse/pass-through mode */ +} tBTA_AG_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* constant lookup tables */ +extern const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX]; +extern const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX]; +extern const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX]; + +/* control block declaration */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_AG_CB bta_ag_cb; +#else +extern tBTA_AG_CB *bta_ag_cb_ptr; +#define bta_ag_cb (*bta_ag_cb_ptr) +#endif + +/* config struct */ +extern tBTA_AG_CFG *p_bta_ag_cfg; + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +/* main functions */ +extern void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb); +extern UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb); +extern tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx); +extern UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services); +extern UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr); +extern BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb); +extern tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb); +extern void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data); +extern BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg); +extern void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, + UINT8 app_id, BD_ADDR peer_addr); +extern void bta_ag_resume_open (tBTA_AG_SCB *p_scb); + +/* SDP functions */ +extern BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn, + tBTA_AG_FEAT features, UINT32 sdp_handle); +extern void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service); +extern void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service); +extern void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); + +/* RFCOMM functions */ +extern void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services); +extern void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services); +extern BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb); +extern void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); + +/* SCO functions */ +extern BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb); +extern BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb); +extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data); + +/* AT command functions */ +extern void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type, + char *p_arg, INT16 int_arg); +extern void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type, + char *p_arg, INT16 int_arg); +extern void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg); +extern BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb); +extern void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result); + +/* Action functions */ +extern void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +#if (BTM_WBS_INCLUDED == TRUE ) +extern void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result); +extern void bta_ag_codec_negotiate (tBTA_AG_SCB *p_scb); +#endif +extern void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +#if (BTM_WBS_INCLUDED == TRUE ) +extern void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +#endif +extern void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param); +extern void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); +#endif /* BTA_AG_INT_H */ diff --git a/bta/ag/bta_ag_main.c b/bta/ag/bta_ag_main.c new file mode 100644 index 0000000..9b28067 --- /dev/null +++ b/bta/ag/bta_ag_main.c @@ -0,0 +1,1012 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 main implementation file for the BTA audio gateway. + * + ******************************************************************************/ + +#include <string.h> +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_ag_co.h" +#include "bta_ag_int.h" +#include "bd.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ +#ifndef BTA_AG_DEBUG +#define BTA_AG_DEBUG FALSE +#endif + +#if BTA_AG_DEBUG == TRUE +static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result); +static char *bta_ag_state_str(UINT8 state); +#endif + +/* state machine states */ +enum +{ + BTA_AG_INIT_ST, + BTA_AG_OPENING_ST, + BTA_AG_OPEN_ST, + BTA_AG_CLOSING_ST +}; + +/* state machine action enumeration list */ +enum +{ + BTA_AG_REGISTER, + BTA_AG_DEREGISTER, + BTA_AG_START_OPEN, + BTA_AG_RFC_DO_OPEN, + BTA_AG_RFC_DO_CLOSE, + BTA_AG_START_DEREG, + BTA_AG_START_CLOSE, + BTA_AG_RFC_OPEN, + BTA_AG_OPEN_FAIL, + BTA_AG_RFC_ACP_OPEN, + BTA_AG_RFC_CLOSE, + BTA_AG_RFC_FAIL, + BTA_AG_RFC_DATA, + BTA_AG_DISC_INT_RES, + BTA_AG_DISC_FAIL, + BTA_AG_DISC_ACP_RES, + BTA_AG_FREE_DB, + BTA_AG_SCO_CONN_OPEN, + BTA_AG_SCO_CONN_CLOSE, + BTA_AG_SCO_LISTEN, + BTA_AG_SCO_OPEN, + BTA_AG_SCO_CLOSE, + BTA_AG_SCO_SHUTDOWN, + BTA_AG_POST_SCO_OPEN, + BTA_AG_POST_SCO_CLOSE, + BTA_AG_SVC_CONN_OPEN, + BTA_AG_RESULT, + BTA_AG_SETCODEC, + BTA_AG_SEND_RING, + BTA_AG_CI_SCO_DATA, + BTA_AG_CI_RX_DATA, + BTA_AG_RCVD_SLC_READY, + BTA_AG_NUM_ACTIONS +}; + +#define BTA_AG_IGNORE BTA_AG_NUM_ACTIONS + +/* type for action functions */ +typedef void (*tBTA_AG_ACTION)(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data); + +/* action functions */ +const tBTA_AG_ACTION bta_ag_action[] = +{ + bta_ag_register, + bta_ag_deregister, + bta_ag_start_open, + bta_ag_rfc_do_open, + bta_ag_rfc_do_close, + bta_ag_start_dereg, + bta_ag_start_close, + bta_ag_rfc_open, + bta_ag_open_fail, + bta_ag_rfc_acp_open, + bta_ag_rfc_close, + bta_ag_rfc_fail, + bta_ag_rfc_data, + bta_ag_disc_int_res, + bta_ag_disc_fail, + bta_ag_disc_acp_res, + bta_ag_free_db, + bta_ag_sco_conn_open, + bta_ag_sco_conn_close, + bta_ag_sco_listen, + bta_ag_sco_open, + bta_ag_sco_close, + bta_ag_sco_shutdown, + bta_ag_post_sco_open, + bta_ag_post_sco_close, + bta_ag_svc_conn_open, + bta_ag_result, + bta_ag_setcodec, + bta_ag_send_ring, + bta_ag_ci_sco_data, + bta_ag_ci_rx_data, + bta_ag_rcvd_slc_ready +}; + +/* state table information */ +#define BTA_AG_ACTIONS 2 /* number of actions */ +#define BTA_AG_NEXT_STATE 2 /* position of next state */ +#define BTA_AG_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for init state */ +const UINT8 bta_ag_st_init[][BTA_AG_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* API_REGISTER_EVT */ {BTA_AG_REGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* API_DEREGISTER_EVT */ {BTA_AG_DEREGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* API_OPEN_EVT */ {BTA_AG_START_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* RFC_OPEN_EVT */ {BTA_AG_RFC_ACP_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST}, +/* RFC_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST} +}; + +/* state table for opening state */ +const UINT8 bta_ag_st_opening[][BTA_AG_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* API_DEREGISTER_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_START_DEREG, BTA_AG_CLOSING_ST}, +/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* API_CLOSE_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* RFC_OPEN_EVT */ {BTA_AG_RFC_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST}, +/* RFC_CLOSE_EVT */ {BTA_AG_RFC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* DISC_ACP_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* DISC_INT_RES_EVT */ {BTA_AG_DISC_INT_RES, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* DISC_OK_EVT */ {BTA_AG_RFC_DO_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* DISC_FAIL_EVT */ {BTA_AG_DISC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}, +/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST} +}; + +/* state table for open state */ +const UINT8 bta_ag_st_open[][BTA_AG_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* API_DEREGISTER_EVT */ {BTA_AG_START_CLOSE, BTA_AG_START_DEREG, BTA_AG_CLOSING_ST}, +/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* API_CLOSE_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_AUDIO_OPEN_EVT */ {BTA_AG_SCO_OPEN, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* API_AUDIO_CLOSE_EVT */ {BTA_AG_SCO_CLOSE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* API_RESULT_EVT */ {BTA_AG_RESULT, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* API_SETCODEC_EVT */ {BTA_AG_SETCODEC, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* RFC_DATA_EVT */ {BTA_AG_RFC_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_POST_SCO_OPEN, BTA_AG_OPEN_ST}, +/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE, BTA_AG_OPEN_ST}, +/* DISC_ACP_RES_EVT */ {BTA_AG_DISC_ACP_RES, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* CI_RX_WRITE_EVT */ {BTA_AG_CI_RX_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* RING_TOUT_EVT */ {BTA_AG_SEND_RING, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* CI_SCO_DATA_EVT */ {BTA_AG_CI_SCO_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST}, +/* CI_SLC_READY_EVT */ {BTA_AG_RCVD_SLC_READY, BTA_AG_IGNORE, BTA_AG_OPEN_ST} +}; + +/* state table for closing state */ +const UINT8 bta_ag_st_closing[][BTA_AG_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_DEREGISTER_EVT */ {BTA_AG_START_DEREG, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE, BTA_AG_CLOSING_ST}, +/* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* DISC_INT_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST}, +/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}, +/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS]; + +/* state table */ +const tBTA_AG_ST_TBL bta_ag_st_tbl[] = +{ + bta_ag_st_init, + bta_ag_st_opening, + bta_ag_st_open, + bta_ag_st_closing +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* AG control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_AG_CB bta_ag_cb; +#endif + +/******************************************************************************* +** +** Function bta_ag_timer_cback +** +** Description AG timer callback. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_timer_cback(void *p) +{ + BT_HDR *p_buf; + TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *) p; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = p_tle->event; + p_buf->layer_specific = bta_ag_scb_to_idx((tBTA_AG_SCB *) p_tle->param); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_ag_scb_alloc +** +** Description Allocate an AG service control block. +** +** +** Returns pointer to the scb, or NULL if none could be allocated. +** +*******************************************************************************/ +static tBTA_AG_SCB *bta_ag_scb_alloc(void) +{ + tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; + int i; + + for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) + { + if (!p_scb->in_use) + { + /* initialize variables */ + p_scb->in_use = TRUE; + p_scb->sco_idx = BTM_INVALID_SCO_INDEX; + + /* set up timers */ + p_scb->act_timer.param = (UINT32) p_scb; + p_scb->act_timer.p_cback = bta_ag_timer_cback; + + APPL_TRACE_DEBUG1("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb)); + break; + } + } + + if (i == BTA_AG_NUM_SCB) + { + /* out of scbs */ + p_scb = NULL; + APPL_TRACE_WARNING0("Out of ag scbs"); + } + return p_scb; +} + +/******************************************************************************* +** +** Function bta_ag_scb_dealloc +** +** Description Deallocate a service control block. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb) +{ + UINT8 idx; + BOOLEAN allocated = FALSE; + + APPL_TRACE_DEBUG1("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb)); + + /* stop timers */ + bta_sys_stop_timer(&p_scb->act_timer); +#if (BTM_WBS_INCLUDED == TRUE) + bta_sys_stop_timer(&p_scb->cn_timer); +#endif + + /* initialize control block */ + memset(p_scb, 0, sizeof(tBTA_AG_SCB)); + p_scb->sco_idx = BTM_INVALID_SCO_INDEX; + + /* If all scbs are deallocated, callback with disable event */ + if (!bta_sys_is_register (BTA_ID_AG)) + { + for (idx = 0; idx < BTA_AG_NUM_SCB; idx++) + { + if (bta_ag_cb.scb[idx].in_use) + { + allocated = TRUE; + break; + } + } + + if (!allocated) + { + (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL); + } + } + +} + +/******************************************************************************* +** +** Function bta_ag_scb_to_idx +** +** Description Given a pointer to an scb, return its index. +** +** +** Returns Index of scb. +** +*******************************************************************************/ +UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb) +{ + /* use array arithmetic to determine index */ + return ((UINT16) (p_scb - bta_ag_cb.scb)) + 1; +} + +/******************************************************************************* +** +** Function bta_ag_scb_by_idx +** +** Description Given an scb index return pointer to scb. +** +** +** Returns Pointer to scb or NULL if not allocated. +** +*******************************************************************************/ +tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx) +{ + tBTA_AG_SCB *p_scb; + + /* verify index */ + if (idx > 0 && idx <= BTA_AG_NUM_SCB) + { + p_scb = &bta_ag_cb.scb[idx - 1]; + if (!p_scb->in_use) + { + p_scb = NULL; + APPL_TRACE_WARNING1("ag scb idx %d not allocated", idx); + } + } + else + { + p_scb = NULL; + APPL_TRACE_DEBUG1("ag scb idx %d out of range", idx); + } + return p_scb; +} + +/******************************************************************************* +** +** Function bta_ag_service_to_idx +** +** Description Given a BTA service mask convert to profile index. +** +** +** Returns Profile ndex of scb. +** +*******************************************************************************/ +UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services) +{ + if (services & BTA_HFP_SERVICE_MASK) + { + return BTA_AG_HFP; + } + else + { + return BTA_AG_HSP; + } +} + +/******************************************************************************* +** +** Function bta_ag_idx_by_bdaddr +** +** Description Find SCB associated with peer BD address. +** +** +** Returns Index of SCB or zero if none found. +** +*******************************************************************************/ +UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr) +{ + tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; + UINT16 i; + + if (peer_addr != NULL) + { + for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) + { + if (p_scb->in_use && !bdcmp(peer_addr, p_scb->peer_addr)) + { + return (i + 1); + } + } + } + + /* no scb found */ + APPL_TRACE_WARNING0("No ag scb for peer addr"); + return 0; +} + +/******************************************************************************* +** +** Function bta_ag_other_scb_open +** +** Description Check whether any other scb is in open state. +** +** +** Returns TRUE if another scb is in open state, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb) +{ + tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; + int i; + + for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) + { + if (p_scb->in_use && p_scb != p_curr_scb && p_scb->state == BTA_AG_OPEN_ST) + { + return TRUE; + } + } + + /* no other scb found */ + APPL_TRACE_DEBUG0("No other ag scb open"); + return FALSE; +} + +/******************************************************************************* +** +** Function bta_ag_get_other_idle_scb +** +** Description Return other scb if it is in INIT st. +** +** +** Returns Pointer to other scb if INIT st, NULL otherwise. +** +*******************************************************************************/ +tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb) +{ + tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; + UINT8 xx; + + for (xx = 0; xx < BTA_AG_NUM_SCB; xx++, p_scb++) + { + if (p_scb->in_use && (p_scb != p_curr_scb) && (p_scb->state == BTA_AG_INIT_ST)) + { + return p_scb; + } + } + + /* no other scb found */ + APPL_TRACE_DEBUG0("bta_ag_get_other_idle_scb: No idle AG scb"); + return NULL; +} + +/******************************************************************************* +** +** Function bta_ag_colli_timer_cback +** +** Description AG connection collision timer callback +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_colli_timer_cback (TIMER_LIST_ENT *p_tle) +{ + tBTA_AG_SCB *p_scb; + + APPL_TRACE_DEBUG0 ("bta_ag_colli_timer_cback"); + + if (p_tle) + { + p_scb = (tBTA_AG_SCB *)p_tle->param; + + if (p_scb) + { + p_scb->colli_tmr_on = FALSE; + + /* If the peer haven't opened AG connection */ + /* we will restart opening process. */ + bta_ag_resume_open (p_scb); + } + } +} + +/******************************************************************************* +** +** Function bta_ag_collision_cback +** +** Description Get notified about collision. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, + UINT8 app_id, BD_ADDR peer_addr) +{ + UINT16 handle; + tBTA_AG_SCB *p_scb; + + /* Check if we have opening scb for the peer device. */ + handle = bta_ag_idx_by_bdaddr (peer_addr); + p_scb = bta_ag_scb_by_idx (handle); + + if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) + { + if (id == BTA_ID_SYS) /* ACL collision */ + { + APPL_TRACE_WARNING0 ("AG found collision (ACL) ..."); + } + else if (id == BTA_ID_AG) /* RFCOMM collision */ + { + APPL_TRACE_WARNING0 ("AG found collision (RFCOMM) ..."); + } + else + { + APPL_TRACE_WARNING0 ("AG found collision (\?\?\?) ..."); + } + + p_scb->state = BTA_AG_INIT_ST; + + /* Cancel SDP if it had been started. */ + if(p_scb->p_disc_db) + { + (void)SDP_CancelServiceSearch (p_scb->p_disc_db); + bta_ag_free_db(p_scb, NULL); + } + + /* reopen registered servers */ + /* Collision may be detected before or after we close servers. */ + if (bta_ag_is_server_closed (p_scb)) + bta_ag_start_servers(p_scb, p_scb->reg_services); + + /* Start timer to han */ + p_scb->colli_timer.p_cback = (TIMER_CBACK*)&bta_ag_colli_timer_cback; + p_scb->colli_timer.param = (INT32)p_scb; + bta_sys_start_timer(&p_scb->colli_timer, 0, BTA_AG_COLLISION_TIMER); + p_scb->colli_tmr_on = TRUE; + } + +} + +/******************************************************************************* +** +** Function bta_ag_resume_open +** +** Description Resume opening process. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_resume_open (tBTA_AG_SCB *p_scb) +{ + if (p_scb) + { + APPL_TRACE_DEBUG1 ("bta_ag_resume_open, Handle(%d)", bta_ag_scb_to_idx(p_scb)); + + /* resume opening process. */ + if (p_scb->state == BTA_AG_INIT_ST) + { + p_scb->state = BTA_AG_OPENING_ST; + bta_ag_start_open (p_scb, NULL); + } + } + else + { + APPL_TRACE_ERROR0 ("bta_ag_resume_open, Null p_scb"); + } +} + +/******************************************************************************* +** +** Function bta_ag_api_enable +** +** Description Handle an API enable event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_api_enable(tBTA_AG_DATA *p_data) +{ + /* initialize control block */ + memset(&bta_ag_cb, 0, sizeof(tBTA_AG_CB)); + + /* store callback function */ + bta_ag_cb.p_cback = p_data->api_enable.p_cback; + bta_ag_cb.parse_mode = p_data->api_enable.parse_mode; + + /* call init call-out */ + bta_ag_co_init(); + + bta_sys_collision_register (BTA_ID_AG, bta_ag_collision_cback); + + /* call callback with enable event */ + (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, NULL); +} + +/******************************************************************************* +** +** Function bta_ag_api_disable +** +** Description Handle an API disable event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_api_disable(tBTA_AG_DATA *p_data) +{ + /* deregister all scbs in use */ + tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; + BOOLEAN do_dereg = FALSE; + int i; + + if (!bta_sys_is_register (BTA_ID_AG)) + { + APPL_TRACE_ERROR0("BTA AG is already disabled, ignoring ..."); + return; + } + + /* De-register with BTA system manager */ + GKI_sched_lock(); + bta_sys_deregister(BTA_ID_AG); + GKI_sched_unlock(); + + for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) + { + if (p_scb->in_use) + { + bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, p_data); + do_dereg = TRUE; + } + } + + if (!do_dereg) + { + /* Done, send callback evt to app */ + (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL); + } + + bta_sys_collision_register (BTA_ID_AG, NULL); +} + +/******************************************************************************* +** +** Function bta_ag_api_register +** +** Description Handle an API event registers a new service. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_api_register(tBTA_AG_DATA *p_data) +{ + tBTA_AG_SCB *p_scb; + tBTA_AG_REGISTER reg; + + /* allocate an scb */ + if ((p_scb = bta_ag_scb_alloc()) != NULL) + { + bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data); + } + else + { + reg.status = BTA_AG_FAIL_RESOURCES; + (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) ®); + } +} + +/******************************************************************************* +** +** Function bta_ag_api_result +** +** Description Handle an API result event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_api_result(tBTA_AG_DATA *p_data) +{ + tBTA_AG_SCB *p_scb; + int i; + + if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL) + { + if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL) + { + bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data); + } + } + else + { + for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++) + { + if (p_scb->in_use) + { + bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data); + } + } + } +} + +/******************************************************************************* +** +** Function bta_ag_sm_execute +** +** Description State machine event handling function for AG +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data) +{ + tBTA_AG_ST_TBL state_table; + UINT8 action; + int i; + +#if BTA_AG_DEBUG == TRUE + UINT16 in_event = event; + UINT8 in_state = p_scb->state; + + /* Ignore displaying of AT results when not connected (Ignored in state machine) */ + if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST) + { + APPL_TRACE_EVENT5("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)", + bta_ag_scb_to_idx(p_scb), + p_scb->state, bta_ag_state_str(p_scb->state), + event, bta_ag_evt_str(event, p_data->api_result.result)); + } +#else + APPL_TRACE_EVENT3("AG evt (hdl 0x%04x): State %d, Event 0x%04x", + bta_ag_scb_to_idx(p_scb), p_scb->state, event); +#endif + + event &= 0x00FF; + if (event >= (BTA_AG_MAX_EVT & 0x00FF)) + { + APPL_TRACE_ERROR0("AG evt out of range, ignoring..."); + return; + } + + /* look up the state table for the current state */ + state_table = bta_ag_st_tbl[p_scb->state]; + + /* set next state */ + p_scb->state = state_table[event][BTA_AG_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_AG_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_AG_IGNORE) + { + (*bta_ag_action[action])(p_scb, p_data); + } + else + { + break; + } + } +#if BTA_AG_DEBUG == TRUE + if (p_scb->state != in_state) + { + APPL_TRACE_EVENT3("BTA AG State Change: [%s] -> [%s] after Event [%s]", + bta_ag_state_str(in_state), + bta_ag_state_str(p_scb->state), + bta_ag_evt_str(in_event, p_data->api_result.result)); + } +#endif +} + +/******************************************************************************* +** +** Function bta_ag_hdl_event +** +** Description Data gateway main event handling function. +** +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg) +{ + tBTA_AG_SCB *p_scb; + + switch (p_msg->event) + { + /* handle enable event */ + case BTA_AG_API_ENABLE_EVT: + bta_ag_api_enable((tBTA_AG_DATA *) p_msg); + break; + + /* handle disable event */ + case BTA_AG_API_DISABLE_EVT: + bta_ag_api_disable((tBTA_AG_DATA *) p_msg); + break; + + /* handle register event */ + case BTA_AG_API_REGISTER_EVT: + bta_ag_api_register((tBTA_AG_DATA *) p_msg); + break; + + /* handle result event */ + case BTA_AG_API_RESULT_EVT: + bta_ag_api_result((tBTA_AG_DATA *) p_msg); + break; + + /* all others reference scb by handle */ + default: + if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL) + { + bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg); + } + break; + } + return TRUE; +} + +#if BTA_AG_DEBUG == TRUE +static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result) +{ + switch (event) + { + case BTA_AG_API_REGISTER_EVT: + return "Register Request"; + case BTA_AG_API_DEREGISTER_EVT: + return "Deregister Request"; + case BTA_AG_API_OPEN_EVT: + return "Open SLC Request"; + case BTA_AG_API_CLOSE_EVT: + return "Close SLC Request"; + case BTA_AG_API_AUDIO_OPEN_EVT: + return "Open Audio Request"; + case BTA_AG_API_AUDIO_CLOSE_EVT: + return "Close Audio Request"; + case BTA_AG_API_RESULT_EVT: + switch (result) + { + case BTA_AG_SPK_RES: return ("AT Result BTA_AG_SPK_RES"); + case BTA_AG_MIC_RES: return ("AT Result BTA_AG_MIC_RES"); + case BTA_AG_INBAND_RING_RES: return ("AT Result BTA_AG_INBAND_RING_RES"); + case BTA_AG_CIND_RES: return ("AT Result BTA_AG_CIND_RES"); + case BTA_AG_BINP_RES: return ("AT Result BTA_AG_BINP_RES"); + case BTA_AG_IND_RES: return ("AT Result BTA_AG_IND_RES"); + case BTA_AG_BVRA_RES: return ("AT Result BTA_AG_BVRA_RES"); + case BTA_AG_CNUM_RES: return ("AT Result BTA_AG_CNUM_RES"); + case BTA_AG_BTRH_RES: return ("AT Result BTA_AG_BTRH_RES"); + case BTA_AG_CLCC_RES: return ("AT Result BTA_AG_CLCC_RES"); + case BTA_AG_COPS_RES: return ("AT Result BTA_AG_COPS_RES"); + case BTA_AG_IN_CALL_RES: return ("AT Result BTA_AG_IN_CALL_RES"); + case BTA_AG_IN_CALL_CONN_RES: return ("AT Result BTA_AG_IN_CALL_CONN_RES"); + case BTA_AG_CALL_WAIT_RES: return ("AT Result BTA_AG_CALL_WAIT_RES"); + case BTA_AG_OUT_CALL_ORIG_RES: return ("AT Result BTA_AG_OUT_CALL_ORIG_RES"); + case BTA_AG_OUT_CALL_ALERT_RES: return ("AT Result BTA_AG_OUT_CALL_ALERT_RES"); + case BTA_AG_OUT_CALL_CONN_RES: return ("AT Result BTA_AG_OUT_CALL_CONN_RES"); + case BTA_AG_CALL_CANCEL_RES: return ("AT Result BTA_AG_CALL_CANCEL_RES"); + case BTA_AG_END_CALL_RES: return ("AT Result BTA_AG_END_CALL_RES"); + case BTA_AG_UNAT_RES: return ("AT Result BTA_AG_UNAT_RES"); + default: return ("Unknown AG Result"); + } + case BTA_AG_API_SETCODEC_EVT: + return "Set Codec Request"; + case BTA_AG_RFC_OPEN_EVT: + return "RFC Opened"; + case BTA_AG_RFC_CLOSE_EVT: + return "RFC Closed"; + case BTA_AG_RFC_SRV_CLOSE_EVT: + return "RFC SRV Closed"; + case BTA_AG_RFC_DATA_EVT: + return "RFC Data"; + case BTA_AG_SCO_OPEN_EVT: + return "Audio Opened"; + case BTA_AG_SCO_CLOSE_EVT: + return "Audio Closed"; + case BTA_AG_DISC_ACP_RES_EVT: + return "Discovery ACP Result"; + case BTA_AG_DISC_INT_RES_EVT: + return "Discovery INT Result"; + case BTA_AG_DISC_OK_EVT: + return "Discovery OK"; + case BTA_AG_DISC_FAIL_EVT: + return "Discovery Failed"; + case BTA_AG_CI_RX_WRITE_EVT: + return "CI RX Write"; + case BTA_AG_RING_TOUT_EVT: + return "Ring Timeout"; + case BTA_AG_SVC_TOUT_EVT: + return "Service Timeout"; + case BTA_AG_API_ENABLE_EVT: + return "Enable AG"; + case BTA_AG_API_DISABLE_EVT: + return "Disable AG"; + case BTA_AG_CI_SCO_DATA_EVT: + return "SCO data Callin"; + case BTA_AG_CI_SLC_READY_EVT: + return "SLC Ready Callin"; + default: + return "Unknown AG Event"; + } +} + +static char *bta_ag_state_str(UINT8 state) +{ + switch (state) + { + case BTA_AG_INIT_ST: + return "Initial"; + case BTA_AG_OPENING_ST: + return "Opening"; + case BTA_AG_OPEN_ST: + return "Open"; + case BTA_AG_CLOSING_ST: + return "Closing"; + default: + return "Unknown AG State"; + } +} + +#endif diff --git a/bta/ag/bta_ag_rfc.c b/bta/ag/bta_ag_rfc.c new file mode 100644 index 0000000..3575020 --- /dev/null +++ b/bta/ag/bta_ag_rfc.c @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * 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 file contains the audio gateway functions controlling the RFCOMM + * connections. + * + ******************************************************************************/ + +#include <string.h> +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_ag_api.h" +#include "bta_ag_int.h" +#include "bta_ag_co.h" +#include "btm_api.h" +#include "port_api.h" +#include "rfcdefs.h" +#include "gki.h" +#include "bd.h" + +/* Event mask for RfCOMM port callback */ +#define BTA_AG_PORT_EV_MASK PORT_EV_RXCHAR + +/* each scb has its own rfcomm callbacks */ +void bta_ag_port_cback_1(UINT32 code, UINT16 port_handle); +void bta_ag_port_cback_2(UINT32 code, UINT16 port_handle); +void bta_ag_port_cback_3(UINT32 code, UINT16 port_handle); + +void bta_ag_mgmt_cback_1(UINT32 code, UINT16 port_handle); +void bta_ag_mgmt_cback_2(UINT32 code, UINT16 port_handle); +void bta_ag_mgmt_cback_3(UINT32 code, UINT16 port_handle); + +int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len); +int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len); +int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len); + +/* rfcomm callback function tables */ +typedef tPORT_CALLBACK *tBTA_AG_PORT_CBACK; +const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] = +{ + bta_ag_port_cback_1, + bta_ag_port_cback_2, + bta_ag_port_cback_3 +}; + +const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] = +{ + bta_ag_mgmt_cback_1, + bta_ag_mgmt_cback_2, + bta_ag_mgmt_cback_3 +}; + +typedef tPORT_DATA_CALLBACK *tBTA_AG_DATA_CBACK; +const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] = +{ + bta_ag_data_cback_1, + bta_ag_data_cback_2, + bta_ag_data_cback_3 +}; + +/******************************************************************************* +** +** Function bta_ag_port_cback +** +** Description RFCOMM Port callback +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_port_cback(UINT32 code, UINT16 port_handle, UINT16 handle) +{ + BT_HDR *p_buf; + tBTA_AG_SCB *p_scb; + + if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) + { + /* ignore port events for port handles other than connected handle */ + if (port_handle != p_scb->conn_handle) + { + APPL_TRACE_DEBUG3("ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d", + port_handle, p_scb->conn_handle, handle); + return; + } + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_RFC_DATA_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } + } +} + +/******************************************************************************* +** +** Function bta_ag_mgmt_cback +** +** Description RFCOMM management callback +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_mgmt_cback(UINT32 code, UINT16 port_handle, UINT16 handle) +{ + tBTA_AG_RFC *p_buf; + tBTA_AG_SCB *p_scb; + UINT16 event; + UINT8 i; + BOOLEAN found_handle = FALSE; + + APPL_TRACE_DEBUG3("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d", + code, port_handle, handle); + + if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) + { + /* ignore close event for port handles other than connected handle */ + if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) + { + APPL_TRACE_DEBUG1("ag_mgmt_cback ignoring handle:%d", port_handle); + return; + } + + if (code == PORT_SUCCESS) + { + if (p_scb->conn_handle) /* Outgoing connection */ + { + if (port_handle == p_scb->conn_handle) + found_handle = TRUE; + } + else /* Incoming connection */ + { + for (i = 0; i < BTA_AG_NUM_IDX; i++) + { + if (port_handle == p_scb->serv_handle[i]) + found_handle = TRUE; + } + } + + if (!found_handle) + { + APPL_TRACE_ERROR1 ("bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle); + return; + } + + event = BTA_AG_RFC_OPEN_EVT; + } + /* distinguish server close events */ + else if (port_handle == p_scb->conn_handle) + { + event = BTA_AG_RFC_CLOSE_EVT; + } + else + { + event = BTA_AG_RFC_SRV_CLOSE_EVT; + } + + if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL) + { + p_buf->hdr.event = event; + p_buf->hdr.layer_specific = handle; + p_buf->port_handle = port_handle; + bta_sys_sendmsg(p_buf); + } + } +} + +/******************************************************************************* +** +** Function bta_ag_data_cback +** +** Description RFCOMM data callback +** +** +** Returns void +** +*******************************************************************************/ +static int bta_ag_data_cback(UINT16 port_handle, void *p_data, UINT16 len, UINT16 handle) +{ + /* call data call-out directly */ + bta_ag_co_tx_write(handle, (UINT8 *) p_data, len); + return 0; +} + +/******************************************************************************* +** +** Function bta_ag_port_cback_1 to 3 +** bta_ag_mgmt_cback_1 to 3 +** +** Description RFCOMM callback functions. This is an easy way to +** distinguish scb from the callback. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_mgmt_cback_1(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 1);} +void bta_ag_mgmt_cback_2(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 2);} +void bta_ag_mgmt_cback_3(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 3);} +void bta_ag_port_cback_1(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 1);} +void bta_ag_port_cback_2(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 2);} +void bta_ag_port_cback_3(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 3);} + +/******************************************************************************* +** +** Function bta_ag_data_cback_1 to 3 +** +** Description RFCOMM data callback functions. This is an easy way to +** distinguish scb from the callback. +** +** +** Returns void +** +*******************************************************************************/ +int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len) +{ + return bta_ag_data_cback(port_handle, p_data, len, 1); +} +int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len) +{ + return bta_ag_data_cback(port_handle, p_data, len, 2); +} +int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len) +{ + return bta_ag_data_cback(port_handle, p_data, len, 3); +} + +/******************************************************************************* +** +** Function bta_ag_setup_port +** +** Description Setup RFCOMM port for use by AG. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_setup_port(tBTA_AG_SCB *p_scb, UINT16 handle) +{ + UINT16 i = bta_ag_scb_to_idx(p_scb) - 1; + + /* set up data callback if using pass through mode */ + if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) + { + PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]); + } + + PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK); + PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]); +} + +/******************************************************************************* +** +** Function bta_ag_start_servers +** +** Description Setup RFCOMM servers for use by AG. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services) +{ + int i; + int bta_ag_port_status; + + services >>= BTA_HSP_SERVICE_ID; + for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) + { + /* if service is set in mask */ + if (services & 1) + { + BTM_SetSecurityLevel(FALSE, "", bta_ag_sec_id[i], p_scb->serv_sec_mask, + BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_ag_cb.profile[i].scn); + + bta_ag_port_status = RFCOMM_CreateConnection(bta_ag_uuid[i], bta_ag_cb.profile[i].scn, + TRUE, BTA_AG_MTU, (UINT8 *) bd_addr_any, &(p_scb->serv_handle[i]), + bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]); + + if( bta_ag_port_status == PORT_SUCCESS ) + { + bta_ag_setup_port(p_scb, p_scb->serv_handle[i]); + } + else + { + /* TODO: CR#137125 to handle to error properly */ + APPL_TRACE_DEBUG1("bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d", bta_ag_port_status); + } + } + } +} + +/******************************************************************************* +** +** Function bta_ag_close_servers +** +** Description Close RFCOMM servers port for use by AG. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services) +{ + int i; + + services >>= BTA_HSP_SERVICE_ID; + for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) + { + /* if service is set in mask */ + if (services & 1) + { + RFCOMM_RemoveServer(p_scb->serv_handle[i]); + p_scb->serv_handle[i] = 0; + } + } +} + +/******************************************************************************* +** +** Function bta_ag_is_server_closed +** +** Description Returns TRUE if all servers are closed. +** +** +** Returns TRUE if all servers are closed, FALSE otherwise +** +*******************************************************************************/ +BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb) +{ + UINT8 xx; + BOOLEAN is_closed = TRUE; + + for (xx = 0; xx < BTA_AG_NUM_IDX; xx++) + { + if (p_scb->serv_handle[xx] != 0) + is_closed = FALSE; + } + + return is_closed; +} + +/******************************************************************************* +** +** Function bta_ag_rfc_do_open +** +** Description Open an RFCOMM connection to the peer device. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + BTM_SetSecurityLevel(TRUE, "", bta_ag_sec_id[p_scb->conn_service], + p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, p_scb->peer_scn); + + if (RFCOMM_CreateConnection(bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, + FALSE, BTA_AG_MTU, p_scb->peer_addr, &(p_scb->conn_handle), + bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == PORT_SUCCESS) + { + bta_ag_setup_port(p_scb, p_scb->conn_handle); + APPL_TRACE_DEBUG1("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle); + } + /* RFCOMM create connection failed; send ourselves RFCOMM close event */ + else + { + bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_ag_rfc_do_close +** +** Description Close RFCOMM connection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + tBTA_AG_RFC *p_buf; + + if (p_scb->conn_handle) + { + RFCOMM_RemoveConnection(p_scb->conn_handle); + } + else + { + /* Close API was called while AG is in Opening state. */ + /* Need to trigger the state machine to send callback to the app */ + /* and move back to INIT state. */ + if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL) + { + p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT; + p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb); + bta_sys_sendmsg(p_buf); + } + + /* Cancel SDP if it had been started. */ + /* + if(p_scb->p_disc_db) + { + (void)SDP_CancelServiceSearch (p_scb->p_disc_db); + } + */ + } + +#ifdef _WIN32_WCE + { + /* Windows versions of RFCOMM does NOT generate a closed callback when we close */ + tPORT_CALLBACK *rfc_mgmt_cback = bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]; + + if (rfc_mgmt_cback) + { + (rfc_mgmt_cback)(PORT_CLOSED, p_scb->conn_handle); + } + } +#endif +} + diff --git a/bta/ag/bta_ag_sco.c b/bta/ag/bta_ag_sco.c new file mode 100644 index 0000000..0c811b4 --- /dev/null +++ b/bta/ag/bta_ag_sco.c @@ -0,0 +1,1662 @@ +/****************************************************************************** + * + * 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 file contains functions for managing the SCO connection used in AG. + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bta_ag_api.h" +#include "bta_ag_co.h" +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +#include "bta_dm_co.h" +#endif +#include "bta_ag_int.h" +#include "btm_api.h" +#include "gki.h" + +#ifndef BTA_AG_SCO_DEBUG +#define BTA_AG_SCO_DEBUG FALSE +#endif + +#ifndef BTA_AG_CODEC_NEGO_TIMEOUT +#define BTA_AG_CODEC_NEGO_TIMEOUT 3000 +#endif + +#if BTA_AG_SCO_DEBUG == TRUE +static char *bta_ag_sco_evt_str(UINT8 event); +static char *bta_ag_sco_state_str(UINT8 state); +#endif + +#define BTA_AG_NO_EDR_ESCO (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \ + BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \ + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \ + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5) + +/* sco events */ +enum +{ + BTA_AG_SCO_LISTEN_E, /* listen request */ + BTA_AG_SCO_OPEN_E, /* open request */ + BTA_AG_SCO_XFER_E, /* transfer request */ +#if (BTM_WBS_INCLUDED == TRUE ) + BTA_AG_SCO_CN_DONE_E, /* codec negotiation done */ + BTA_AG_SCO_REOPEN_E, /* Retry with other codec when failed */ +#endif + BTA_AG_SCO_CLOSE_E, /* close request */ + BTA_AG_SCO_SHUTDOWN_E, /* shutdown request */ + BTA_AG_SCO_CONN_OPEN_E, /* sco open */ + BTA_AG_SCO_CONN_CLOSE_E, /* sco closed */ + BTA_AG_SCO_CI_DATA_E /* SCO data ready */ +}; + +#if (BTM_WBS_INCLUDED == TRUE ) +#define BTA_AG_NUM_CODECS 2 +static const tBTM_ESCO_PARAMS bta_ag_esco_params[BTA_AG_NUM_CODECS] = +{ + /* CVSD */ + { + BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */ + BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */ + 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */ + BTM_VOICE_SETTING_CVSD, /* Inp Linear, Air CVSD, 2s Comp, 16bit */ + (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */ + BTM_SCO_PKT_TYPES_MASK_HV2 + + BTM_SCO_PKT_TYPES_MASK_HV3 + + BTM_SCO_PKT_TYPES_MASK_EV3 + + BTM_SCO_PKT_TYPES_MASK_EV4 + + BTM_SCO_PKT_TYPES_MASK_EV5 + + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 + + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5), + BTM_ESCO_RETRANS_POWER /* Retransmission effort */ + }, + /* mSBC */ + { + BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec), 8000 */ + BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec), 8000 */ + 13, /* 13 ms */ + BTM_VOICE_SETTING_TRANS, /* Inp Linear, Transparent, 2s Comp, 16bit */ + (BTM_SCO_PKT_TYPES_MASK_EV3 | /* Packet Types : EV3 + 2-EV3 */ + BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5), + BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */ + } +}; +#else +static const tBTM_ESCO_PARAMS bta_ag_esco_params = +{ + BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */ + BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */ + 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */ + 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */ + (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */ + BTM_SCO_PKT_TYPES_MASK_HV2 + + BTM_SCO_PKT_TYPES_MASK_HV3 + + BTM_SCO_PKT_TYPES_MASK_EV3 + + BTM_SCO_PKT_TYPES_MASK_EV4 + + BTM_SCO_PKT_TYPES_MASK_EV5 + + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 + + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5), + BTM_ESCO_RETRANS_POWER /* Retransmission effort */ +}; +#endif + +/******************************************************************************* +** +** Function bta_ag_sco_conn_cback +** +** Description BTM SCO connection callback. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_sco_conn_cback(UINT16 sco_idx) +{ + UINT16 handle; + BT_HDR *p_buf; + tBTA_AG_SCB *p_scb; + + /* match callback to scb; first check current sco scb */ + if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use) + { + handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb); + } + /* then check for scb connected to this peer */ + else + { + /* Check if SLC is up */ + handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_idx)); + p_scb = bta_ag_scb_by_idx(handle); + if(p_scb && !p_scb->svc_conn) + handle = 0; + } + + if (handle != 0) + { + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_SCO_OPEN_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } + } + /* no match found; disconnect sco, init sco variables */ + else + { + bta_ag_cb.sco.p_curr_scb = NULL; + bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST; + BTM_RemoveSco(sco_idx); + } +} + +/******************************************************************************* +** +** Function bta_ag_sco_disc_cback +** +** Description BTM SCO disconnection callback. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_sco_disc_cback(UINT16 sco_idx) +{ + BT_HDR *p_buf; + UINT16 handle = 0; + + APPL_TRACE_DEBUG3 ("bta_ag_sco_disc_cback(): sco_idx: 0x%x p_cur_scb: 0x%08x sco.state: %d", sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state); + + APPL_TRACE_DEBUG4 ("bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u", + &bta_ag_cb.scb[0], bta_ag_cb.scb[0].in_use, bta_ag_cb.scb[0].sco_idx, bta_ag_cb.scb[0].state); + APPL_TRACE_DEBUG4 ("bta_ag_sco_disc_cback(): scb[1] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u", + &bta_ag_cb.scb[1], bta_ag_cb.scb[1].in_use, bta_ag_cb.scb[1].sco_idx, bta_ag_cb.scb[1].state); + + /* match callback to scb */ + if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use) + { + /* We only care about callbacks for the active SCO */ + if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx) + { + if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF) + return; + } + handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb); + } + + if (handle != 0) + { +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, TRUE); + APPL_TRACE_DEBUG1("bta_ag_sco_disc_cback sco close config status = %d", status); + /* SCO clean up here */ + bta_dm_sco_co_close(); +#endif + +#if (BTM_WBS_INCLUDED == TRUE ) + /* Restore settings */ + if(bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC) + { + BTM_SetWBSCodec (BTM_SCO_CODEC_NONE); + BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD); + + /* If SCO open was initiated by AG and failed for mSBC, try CVSD again. */ + if (bta_ag_sco_is_opening (bta_ag_cb.sco.p_curr_scb)) + { + bta_ag_cb.sco.p_curr_scb->codec_fallback = TRUE; + APPL_TRACE_DEBUG0("Fallback to CVSD"); + } + } + + bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE; +#endif + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_SCO_CLOSE_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } + } + /* no match found */ + else + { + APPL_TRACE_DEBUG0("no scb for ag_sco_disc_cback"); + + /* sco could be closed after scb dealloc'ed */ + if (bta_ag_cb.sco.p_curr_scb != NULL) + { + bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX; + bta_ag_cb.sco.p_curr_scb = NULL; + bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST; + } + } +} +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +/******************************************************************************* +** +** Function bta_ag_sco_read_cback +** +** Description Callback function is the callback function for incoming +** SCO data over HCI. +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_sco_read_cback (UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status) +{ + if (status != BTM_SCO_DATA_CORRECT) + { + APPL_TRACE_DEBUG1("bta_ag_sco_read_cback: status(%d)", status); + } + + /* Callout function must free the data. */ + bta_dm_sco_co_in_data (p_data, status); +} +#endif +/******************************************************************************* +** +** Function bta_ag_remove_sco +** +** Description Removes the specified SCO from the system. +** If only_active is TRUE, then SCO is only removed if connected +** +** Returns BOOLEAN - TRUE if Sco removal was started +** +*******************************************************************************/ +static BOOLEAN bta_ag_remove_sco(tBTA_AG_SCB *p_scb, BOOLEAN only_active) +{ + BOOLEAN removed_started = FALSE; + tBTM_STATUS status; + + if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) + { + if (!only_active || p_scb->sco_idx == bta_ag_cb.sco.cur_idx) + { + status = BTM_RemoveSco(p_scb->sco_idx); + + APPL_TRACE_DEBUG2("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx, status); + + if (status == BTM_CMD_STARTED) + { + /* Sco is connected; set current control block */ + bta_ag_cb.sco.p_curr_scb = p_scb; + + removed_started = TRUE; + } + /* If no connection reset the sco handle */ + else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) ) + { + p_scb->sco_idx = BTM_INVALID_SCO_INDEX; + } + } + } + return removed_started; +} + + +/******************************************************************************* +** +** Function bta_ag_esco_connreq_cback +** +** Description BTM eSCO connection requests and eSCO change requests +** Only the connection requests are processed by BTA. +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data) +{ + tBTA_AG_SCB *p_scb; + UINT16 handle; + UINT16 sco_inx = p_data->conn_evt.sco_inx; + + /* Only process connection requests */ + if (event == BTM_ESCO_CONN_REQ_EVT) + { + if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 && + ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn) + { + p_scb->sco_idx = sco_inx; + + /* If no other SCO active, allow this one */ + if (!bta_ag_cb.sco.p_curr_scb) + { + APPL_TRACE_EVENT1("bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)", sco_inx); + bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt); + + bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST; + bta_ag_cb.sco.p_curr_scb = p_scb; + bta_ag_cb.sco.cur_idx = p_scb->sco_idx; + } + else /* Begin a transfer: Close current SCO before responding */ + { + APPL_TRACE_DEBUG0("bta_ag_esco_connreq_cback: Begin XFER"); + bta_ag_cb.sco.p_xfer_scb = p_scb; + bta_ag_cb.sco.conn_data = p_data->conn_evt; + bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST; + + if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, TRUE)) + { + APPL_TRACE_ERROR1("bta_ag_esco_connreq_cback: Nothing to remove so accept Conn Request (sco_inx 0x%04x)", sco_inx); + bta_ag_cb.sco.p_xfer_scb = NULL; + bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST; + + bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt); + } + } + } + /* If error occurred send reject response immediately */ + else + { + APPL_TRACE_WARNING0("no scb for bta_ag_esco_connreq_cback or no resources"); + BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL); + } + } + /* Received a change in the esco link */ + else if (event == BTM_ESCO_CHG_EVT) + { + APPL_TRACE_EVENT5("eSCO change event (inx %d): rtrans %d, rxlen %d, txlen %d, txint %d", + p_data->chg_evt.sco_inx, + p_data->chg_evt.retrans_window, p_data->chg_evt.rx_pkt_len, + p_data->chg_evt.tx_pkt_len, p_data->chg_evt.tx_interval); + } +} + +/******************************************************************************* +** +** Function bta_ag_cback_sco +** +** Description Call application callback function with SCO event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_cback_sco(tBTA_AG_SCB *p_scb, UINT8 event) +{ + tBTA_AG_HDR sco; + + sco.handle = bta_ag_scb_to_idx(p_scb); + sco.app_id = p_scb->app_id; + + /* call close cback */ + (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &sco); +} + +/******************************************************************************* +** +** Function bta_ag_create_sco +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_create_sco(tBTA_AG_SCB *p_scb, BOOLEAN is_orig) +{ + tBTM_STATUS status; + UINT8 *p_bd_addr = NULL; + tBTM_ESCO_PARAMS params; +#if (BTM_WBS_INCLUDED == TRUE ) + tBTA_AG_PEER_CODEC esco_codec = BTM_SCO_CODEC_CVSD; + int codec_index = 0; +#endif +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + tBTM_SCO_ROUTE_TYPE sco_route; + tBTA_CODEC_INFO codec_info = {BTA_SCO_CODEC_PCM}; + UINT32 pcm_sample_rate; +#endif + + /* Make sure this sco handle is not already in use */ + if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) + { + APPL_TRACE_WARNING1("bta_ag_create_sco: Index 0x%04x Already In Use!", + p_scb->sco_idx); + return; + } + +#if (BTM_WBS_INCLUDED == TRUE ) + if ((p_scb->sco_codec == BTM_SCO_CODEC_MSBC) && + !p_scb->codec_fallback && + !p_scb->retry_with_sco_only) + esco_codec = BTM_SCO_CODEC_MSBC; + + if (p_scb->codec_fallback) + { + p_scb->codec_fallback = FALSE; + + /* Force AG to send +BCS for the next audio connection. */ + p_scb->codec_updated = TRUE; + } + + if (esco_codec == BTM_SCO_CODEC_MSBC) + codec_index = esco_codec - 1; + + params = bta_ag_esco_params[codec_index]; +#else + params = bta_ag_esco_params; +#endif + + if(bta_ag_cb.sco.param_updated) /* If we do not use the default parameters */ + params = bta_ag_cb.sco.params; + + if(!bta_ag_cb.sco.param_updated) + { +#if (BTM_WBS_INCLUDED == TRUE) + if (!codec_index) /* For non-WBS */ +#endif + { + /* Use the application packet types (5 slot EV packets not allowed) */ + params.packet_types = p_bta_ag_cfg->sco_pkt_types | + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5; + } + } + + /* if initiating set current scb and peer bd addr */ + if (is_orig) + { + /* Attempt to use eSCO if remote host supports HFP >= 1.5 */ + /* Need to find out from SIG if HSP can use eSCO; for now use SCO */ + if (p_scb->conn_service == BTA_AG_HFP && p_scb->peer_version >= HFP_VERSION_1_5 && !p_scb->retry_with_sco_only) + { + + BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, ¶ms); + /* If ESCO or EDR ESCO, retry with SCO only in case of failure */ + if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK) + ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_AG_NO_EDR_ESCO)) + { +#if (BTM_WBS_INCLUDED == TRUE ) + if (esco_codec != BTA_AG_CODEC_MSBC) + { + p_scb->retry_with_sco_only = TRUE; + APPL_TRACE_API0("Setting retry_with_sco_only to TRUE"); + } + else /* Do not use SCO when using mSBC */ + { + p_scb->retry_with_sco_only = FALSE; + APPL_TRACE_API0("Setting retry_with_sco_only to FALSE"); + } +#else + p_scb->retry_with_sco_only = TRUE; + APPL_TRACE_API0("Setting retry_with_sco_only to TRUE"); +#endif + } + } + else + { + if(p_scb->retry_with_sco_only) + APPL_TRACE_API0("retrying with SCO only"); + p_scb->retry_with_sco_only = FALSE; + + BTM_SetEScoMode(BTM_LINK_TYPE_SCO, ¶ms); + } + + bta_ag_cb.sco.p_curr_scb = p_scb; + + /* tell sys to stop av if any */ + bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + /* Allow any platform specific pre-SCO set up to take place */ + bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP); + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) +#if (BTM_WBS_INCLUDED == TRUE) + if (esco_codec == BTA_AG_CODEC_MSBC) + pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_16K; + else +#endif + pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K; + + sco_route = bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id); +#endif + +#if (BTM_WBS_INCLUDED == TRUE ) + if (esco_codec == BTA_AG_CODEC_MSBC) + { + /* Enable mSBC codec in fw */ + BTM_SetWBSCodec (esco_codec); + } + + /* Specify PCM input for SBC codec in fw */ + BTM_ConfigI2SPCM (esco_codec, (UINT8)HCI_BRCM_I2SPCM_IS_DEFAULT_ROLE, (UINT8)HCI_BRCM_I2SPCM_SAMPLE_DEFAULT, (UINT8)HCI_BRCM_I2SPCM_CLOCK_DEFAULT); + + /* This setting may not be necessary */ + /* To be verified with stable 2049 boards */ + if (esco_codec == BTA_AG_CODEC_MSBC) + BTM_WriteVoiceSettings (BTM_VOICE_SETTING_TRANS); + else + BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD); + + /* save the current codec because sco_codec can be updated while SCO is open. */ + p_scb->inuse_codec = esco_codec; +#endif + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */ + BTM_ConfigScoPath(sco_route, bta_ag_sco_read_cback, NULL, TRUE); +#endif + bta_ag_cb.sco.cur_idx = p_scb->sco_idx; + } + else + p_scb->retry_with_sco_only = FALSE; + + p_bd_addr = p_scb->peer_addr; + + status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types, + &p_scb->sco_idx, bta_ag_sco_conn_cback, + bta_ag_sco_disc_cback); + if (status == BTM_CMD_STARTED) + { + if (!is_orig) + { + BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback); + } + else /* Initiating the connection, set the current sco handle */ + { + bta_ag_cb.sco.cur_idx = p_scb->sco_idx; + } + } + + APPL_TRACE_API4("ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x", + is_orig, p_scb->sco_idx, status, params.packet_types); +} + +#if (BTM_WBS_INCLUDED == TRUE ) +/******************************************************************************* +** +** Function bta_ag_cn_timer_cback +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_cn_timer_cback (TIMER_LIST_ENT *p_tle) +{ + tBTA_AG_SCB *p_scb; + + if (p_tle) + { + p_scb = (tBTA_AG_SCB *)p_tle->param; + + if (p_scb) + { + /* Announce that codec negotiation failed. */ + bta_ag_sco_codec_nego(p_scb, FALSE); + + /* call app callback */ + bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT); + } + } +} + +/******************************************************************************* +** +** Function bta_ag_codec_negotiate +** +** Description Initiate codec negotiation by sending AT command. +** If not necessary, skip negotiation. +** +** Returns void +** +*******************************************************************************/ +void bta_ag_codec_negotiate(tBTA_AG_SCB *p_scb) +{ + bta_ag_cb.sco.p_curr_scb = p_scb; + + if (p_scb->codec_updated || p_scb->codec_fallback) + { + /* Change the power mode to Active until sco open is completed. */ + bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + /* Send +BCS to the peer */ + bta_ag_send_bcs(p_scb, NULL); + + /* Start timer to handle timeout */ + p_scb->cn_timer.p_cback = (TIMER_CBACK*)&bta_ag_cn_timer_cback; + p_scb->cn_timer.param = (INT32)p_scb; + bta_sys_start_timer(&p_scb->cn_timer, 0, BTA_AG_CODEC_NEGO_TIMEOUT); + } + else + { + /* use same codec type as previous SCO connection, skip codec negotiation */ + bta_ag_sco_codec_nego(p_scb, TRUE); + } +} +#endif + +/******************************************************************************* +** +** Function bta_ag_sco_event +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event) +{ + tBTA_AG_SCO_CB *p_sco = &bta_ag_cb.sco; +#if (BTM_WBS_INCLUDED == TRUE ) + tBTA_AG_SCB *p_cn_scb = NULL; /* For codec negotiation */ +#endif +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + BT_HDR *p_buf; +#endif +#if BTA_AG_SCO_DEBUG == TRUE + UINT8 in_state = p_sco->state; + + APPL_TRACE_EVENT5("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)", + p_scb->sco_idx, + p_sco->state, bta_ag_sco_state_str(p_sco->state), + event, bta_ag_sco_evt_str(event)); +#else + APPL_TRACE_EVENT3("BTA ag sco evt (hdl 0x%04x): State %d, Event %d", + p_scb->sco_idx, p_sco->state, event); +#endif + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + if (event == BTA_AG_SCO_CI_DATA_E) + { + while (TRUE) + { + bta_dm_sco_co_out_data(&p_buf); + if (p_buf) + { + if (p_sco->state == BTA_AG_SCO_OPEN_ST) + BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf); + else + GKI_freebuf(p_buf); + } + else + break; + } + + return; + } +#endif + + switch (p_sco->state) + { + case BTA_AG_SCO_SHUTDOWN_ST: + switch (event) + { + case BTA_AG_SCO_LISTEN_E: + /* create sco listen connection */ + bta_ag_create_sco(p_scb, FALSE); + p_sco->state = BTA_AG_SCO_LISTEN_ST; + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d", event); + break; + } + break; + + case BTA_AG_SCO_LISTEN_ST: + switch (event) + { + case BTA_AG_SCO_LISTEN_E: + /* create sco listen connection (Additional channel) */ + bta_ag_create_sco(p_scb, FALSE); + break; + + case BTA_AG_SCO_OPEN_E: + /* remove listening connection */ + bta_ag_remove_sco(p_scb, FALSE); + +#if (BTM_WBS_INCLUDED == TRUE ) + /* start codec negotiation */ + p_sco->state = BTA_AG_SCO_CODEC_ST; + p_cn_scb = p_scb; +#else + /* create sco connection to peer */ + bta_ag_create_sco(p_scb, TRUE); + p_sco->state = BTA_AG_SCO_OPENING_ST; +#endif + break; + + case BTA_AG_SCO_SHUTDOWN_E: + /* remove listening connection */ + bta_ag_remove_sco(p_scb, FALSE); + + if (p_scb == p_sco->p_curr_scb) + p_sco->p_curr_scb = NULL; + + /* If last SCO instance then finish shutting down */ + if (!bta_ag_other_scb_open(p_scb)) + { + p_sco->state = BTA_AG_SCO_SHUTDOWN_ST; + } + break; + + case BTA_AG_SCO_CLOSE_E: + /* remove listening connection */ + /* Ignore the event. We need to keep listening SCO for the active SLC */ + APPL_TRACE_WARNING1("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event); + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* sco failed; create sco listen connection */ + bta_ag_create_sco(p_scb, FALSE); + p_sco->state = BTA_AG_SCO_LISTEN_ST; + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event); + break; + } + break; + +#if (BTM_WBS_INCLUDED == TRUE ) + case BTA_AG_SCO_CODEC_ST: + switch (event) + { + case BTA_AG_SCO_LISTEN_E: + /* create sco listen connection (Additional channel) */ + bta_ag_create_sco(p_scb, FALSE); + break; + + case BTA_AG_SCO_CN_DONE_E: + /* create sco connection to peer */ + bta_ag_create_sco(p_scb, TRUE); + p_sco->state = BTA_AG_SCO_OPENING_ST; + break; + + case BTA_AG_SCO_XFER_E: + /* save xfer scb */ + p_sco->p_xfer_scb = p_scb; + p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST; + break; + + case BTA_AG_SCO_SHUTDOWN_E: + /* remove listening connection */ + bta_ag_remove_sco(p_scb, FALSE); + + if (p_scb == p_sco->p_curr_scb) + p_sco->p_curr_scb = NULL; + + /* If last SCO instance then finish shutting down */ + if (!bta_ag_other_scb_open(p_scb)) + { + p_sco->state = BTA_AG_SCO_SHUTDOWN_ST; + } + break; + + case BTA_AG_SCO_CLOSE_E: + /* sco open is not started yet. just go back to listening */ + p_sco->state = BTA_AG_SCO_LISTEN_ST; + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* sco failed; create sco listen connection */ + bta_ag_create_sco(p_scb, FALSE); + p_sco->state = BTA_AG_SCO_LISTEN_ST; + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_CODEC_ST: Ignoring event %d", event); + break; + } + break; +#endif + + case BTA_AG_SCO_OPENING_ST: + switch (event) + { + case BTA_AG_SCO_LISTEN_E: + /* second headset has now joined */ + /* create sco listen connection (Additional channel) */ + if (p_scb != p_sco->p_curr_scb) + { + bta_ag_create_sco(p_scb, FALSE); + } + break; + +#if (BTM_WBS_INCLUDED == TRUE) + case BTA_AG_SCO_REOPEN_E: + /* start codec negotiation */ + p_sco->state = BTA_AG_SCO_CODEC_ST; + p_cn_scb = p_scb; + break; +#endif + + case BTA_AG_SCO_XFER_E: + /* save xfer scb */ + p_sco->p_xfer_scb = p_scb; + p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST; + break; + + case BTA_AG_SCO_CLOSE_E: + p_sco->state = BTA_AG_SCO_OPEN_CL_ST; + break; + + case BTA_AG_SCO_SHUTDOWN_E: + /* If not opening scb, just close it */ + if (p_scb != p_sco->p_curr_scb) + { + /* remove listening connection */ + bta_ag_remove_sco(p_scb, FALSE); + } + else + p_sco->state = BTA_AG_SCO_SHUTTING_ST; + + break; + + case BTA_AG_SCO_CONN_OPEN_E: + p_sco->state = BTA_AG_SCO_OPEN_ST; + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* sco failed; create sco listen connection */ + bta_ag_create_sco(p_scb, FALSE); + p_sco->state = BTA_AG_SCO_LISTEN_ST; + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_OPENING_ST: Ignoring event %d", event); + break; + } + break; + + case BTA_AG_SCO_OPEN_CL_ST: + switch (event) + { + case BTA_AG_SCO_XFER_E: + /* save xfer scb */ + p_sco->p_xfer_scb = p_scb; + + p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST; + break; + + case BTA_AG_SCO_OPEN_E: + p_sco->state = BTA_AG_SCO_OPENING_ST; + break; + + case BTA_AG_SCO_SHUTDOWN_E: + /* If not opening scb, just close it */ + if (p_scb != p_sco->p_curr_scb) + { + /* remove listening connection */ + bta_ag_remove_sco(p_scb, FALSE); + } + else + p_sco->state = BTA_AG_SCO_SHUTTING_ST; + + break; + + case BTA_AG_SCO_CONN_OPEN_E: + /* close sco connection */ + bta_ag_remove_sco(p_scb, TRUE); + + p_sco->state = BTA_AG_SCO_CLOSING_ST; + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* sco failed; create sco listen connection */ + + p_sco->state = BTA_AG_SCO_LISTEN_ST; + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d", event); + break; + } + break; + + case BTA_AG_SCO_OPEN_XFER_ST: + switch (event) + { + case BTA_AG_SCO_CLOSE_E: + /* close sco connection */ + bta_ag_remove_sco(p_scb, TRUE); + + p_sco->state = BTA_AG_SCO_CLOSING_ST; + break; + + case BTA_AG_SCO_SHUTDOWN_E: + /* remove all connection */ + bta_ag_remove_sco(p_scb, FALSE); + p_sco->state = BTA_AG_SCO_SHUTTING_ST; + + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* closed sco; place in listen mode and + accept the transferred connection */ + bta_ag_create_sco(p_scb, FALSE); /* Back into listen mode */ + + /* Accept sco connection with xfer scb */ + bta_ag_sco_conn_rsp(p_sco->p_xfer_scb, &p_sco->conn_data); + p_sco->state = BTA_AG_SCO_OPENING_ST; + p_sco->p_curr_scb = p_sco->p_xfer_scb; + p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx; + p_sco->p_xfer_scb = NULL; + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d", event); + break; + } + break; + + case BTA_AG_SCO_OPEN_ST: + switch (event) + { + case BTA_AG_SCO_LISTEN_E: + /* second headset has now joined */ + /* create sco listen connection (Additional channel) */ + if (p_scb != p_sco->p_curr_scb) + { + bta_ag_create_sco(p_scb, FALSE); + } + break; + + case BTA_AG_SCO_XFER_E: + /* close current sco connection */ + bta_ag_remove_sco(p_sco->p_curr_scb, TRUE); + + /* save xfer scb */ + p_sco->p_xfer_scb = p_scb; + + p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST; + break; + + case BTA_AG_SCO_CLOSE_E: + /* close sco connection if active */ + if (bta_ag_remove_sco(p_scb, TRUE)) + { + p_sco->state = BTA_AG_SCO_CLOSING_ST; + } + break; + + case BTA_AG_SCO_SHUTDOWN_E: + /* remove all listening connections */ + bta_ag_remove_sco(p_scb, FALSE); + + /* If SCO was active on this scb, close it */ + if (p_scb == p_sco->p_curr_scb) + { + p_sco->state = BTA_AG_SCO_SHUTTING_ST; + } + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* peer closed sco; create sco listen connection */ + bta_ag_create_sco(p_scb, FALSE); + p_sco->state = BTA_AG_SCO_LISTEN_ST; + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_OPEN_ST: Ignoring event %d", event); + break; + } + break; + + case BTA_AG_SCO_CLOSING_ST: + switch (event) + { + case BTA_AG_SCO_LISTEN_E: + /* create sco listen connection (Additional channel) */ + if (p_scb != p_sco->p_curr_scb) + { + bta_ag_create_sco(p_scb, FALSE); + } + break; + + case BTA_AG_SCO_OPEN_E: + p_sco->state = BTA_AG_SCO_CLOSE_OP_ST; + break; + + case BTA_AG_SCO_XFER_E: + /* save xfer scb */ + p_sco->p_xfer_scb = p_scb; + + p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST; + break; + + case BTA_AG_SCO_SHUTDOWN_E: + /* If not closing scb, just close it */ + if (p_scb != p_sco->p_curr_scb) + { + /* remove listening connection */ + bta_ag_remove_sco(p_scb, FALSE); + } + else + p_sco->state = BTA_AG_SCO_SHUTTING_ST; + + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* peer closed sco; create sco listen connection */ + bta_ag_create_sco(p_scb, FALSE); + + p_sco->state = BTA_AG_SCO_LISTEN_ST; + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSING_ST: Ignoring event %d", event); + break; + } + break; + + case BTA_AG_SCO_CLOSE_OP_ST: + switch (event) + { + case BTA_AG_SCO_CLOSE_E: + p_sco->state = BTA_AG_SCO_CLOSING_ST; + break; + + case BTA_AG_SCO_SHUTDOWN_E: + p_sco->state = BTA_AG_SCO_SHUTTING_ST; + break; + + case BTA_AG_SCO_CONN_CLOSE_E: +#if (BTM_WBS_INCLUDED == TRUE ) + /* start codec negotiation */ + p_sco->state = BTA_AG_SCO_CODEC_ST; + p_cn_scb = p_scb; +#else + /* open sco connection */ + bta_ag_create_sco(p_scb, TRUE); + p_sco->state = BTA_AG_SCO_OPENING_ST; +#endif + break; + + case BTA_AG_SCO_LISTEN_E: + /* create sco listen connection (Additional channel) */ + if (p_scb != p_sco->p_curr_scb) + { + bta_ag_create_sco(p_scb, FALSE); + } + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d", event); + break; + } + break; + + case BTA_AG_SCO_CLOSE_XFER_ST: + switch (event) + { + case BTA_AG_SCO_CONN_OPEN_E: + /* close sco connection so headset can be transferred + Probably entered this state from "opening state" */ + bta_ag_remove_sco(p_scb, TRUE); + break; + + case BTA_AG_SCO_CLOSE_E: + /* clear xfer scb */ + p_sco->p_xfer_scb = NULL; + + p_sco->state = BTA_AG_SCO_CLOSING_ST; + break; + + case BTA_AG_SCO_SHUTDOWN_E: + /* clear xfer scb */ + p_sco->p_xfer_scb = NULL; + + p_sco->state = BTA_AG_SCO_SHUTTING_ST; + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* closed sco; place old sco in listen mode, + take current sco out of listen, and + create originating sco for current */ + bta_ag_create_sco(p_scb, FALSE); + bta_ag_remove_sco(p_sco->p_xfer_scb, FALSE); + +#if (BTM_WBS_INCLUDED == TRUE ) + /* start codec negotiation */ + p_sco->state = BTA_AG_SCO_CODEC_ST; + p_cn_scb = p_sco->p_xfer_scb; + p_sco->p_xfer_scb = NULL; +#else + /* create sco connection to peer */ + bta_ag_create_sco(p_sco->p_xfer_scb, TRUE); + p_sco->p_xfer_scb = NULL; + p_sco->state = BTA_AG_SCO_OPENING_ST; +#endif + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d", event); + break; + } + break; + + case BTA_AG_SCO_SHUTTING_ST: + switch (event) + { + case BTA_AG_SCO_CONN_OPEN_E: + /* close sco connection; wait for conn close event */ + bta_ag_remove_sco(p_scb, TRUE); + break; + + case BTA_AG_SCO_CONN_CLOSE_E: + /* If last SCO instance then finish shutting down */ + if (!bta_ag_other_scb_open(p_scb)) + { + p_sco->state = BTA_AG_SCO_SHUTDOWN_ST; + } + else /* Other instance is still listening */ + { + p_sco->state = BTA_AG_SCO_LISTEN_ST; + } + + if (p_scb == p_sco->p_curr_scb) + { + p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX; + p_sco->p_curr_scb = NULL; + } + break; + + case BTA_AG_SCO_LISTEN_E: + /* create sco listen connection (Additional channel) */ + if (p_scb != p_sco->p_curr_scb) + { + bta_ag_create_sco(p_scb, FALSE); + } + break; + + case BTA_AG_SCO_SHUTDOWN_E: + if (!bta_ag_other_scb_open(p_scb)) + { + p_sco->state = BTA_AG_SCO_SHUTDOWN_ST; + } + else /* Other instance is still listening */ + { + p_sco->state = BTA_AG_SCO_LISTEN_ST; + } + + if (p_scb == p_sco->p_curr_scb) + { + p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX; + p_sco->p_curr_scb = NULL; + } + break; + + default: + APPL_TRACE_WARNING1("BTA_AG_SCO_SHUTTING_ST: Ignoring event %d", event); + break; + } + break; + + default: + break; + } +#if BTA_AG_SCO_DEBUG == TRUE + if (p_sco->state != in_state) + { + APPL_TRACE_EVENT3("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]", + bta_ag_sco_state_str(in_state), + bta_ag_sco_state_str(p_sco->state), + bta_ag_sco_evt_str(event)); + } +#endif + +#if (BTM_WBS_INCLUDED == TRUE ) + if (p_cn_scb) + { + bta_ag_codec_negotiate(p_cn_scb); + } +#endif +} + +/******************************************************************************* +** +** Function bta_ag_sco_is_open +** +** Description Check if sco is open for this scb. +** +** +** Returns TRUE if sco open for this scb, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb) +{ + return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_ST) && + (bta_ag_cb.sco.p_curr_scb == p_scb)); +} + +/******************************************************************************* +** +** Function bta_ag_sco_is_opening +** +** Description Check if sco is in Opening state. +** +** +** Returns TRUE if sco is in Opening state for this scb, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb) +{ +#if (BTM_WBS_INCLUDED == TRUE ) + return (((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) || + (bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST)) && + (bta_ag_cb.sco.p_curr_scb == p_scb)); +#else + return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) && + (bta_ag_cb.sco.p_curr_scb == p_scb)); +#endif +} + +/******************************************************************************* +** +** Function bta_ag_sco_listen +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E); +} + +/******************************************************************************* +** +** Function bta_ag_sco_open +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + UINT8 event; + + /* if another scb using sco, this is a transfer */ + if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb) + { + event = BTA_AG_SCO_XFER_E; + } + /* else it is an open */ + else + { + event = BTA_AG_SCO_OPEN_E; + } + + bta_ag_sco_event(p_scb, event); +} + +/******************************************************************************* +** +** Function bta_ag_sco_close +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + /* if scb is in use */ +#if (BTM_WBS_INCLUDED == TRUE ) + /* sco_idx is not allocated in SCO_CODEC_ST, we still need to move to listening state. */ + if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) || (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST)) +#else + if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) +#endif + { + APPL_TRACE_DEBUG1("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx); + bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E); + } +} + +#if (BTM_WBS_INCLUDED == TRUE ) + +/******************************************************************************* +** +** Function bta_ag_sco_codec_nego +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result) +{ + if(result == TRUE) + { + /* Subsequent sco connection will skip codec negotiation */ + p_scb->codec_updated = FALSE; + + bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E); + } + else /* codec negotiation failed */ + bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E); +} +#endif + +/******************************************************************************* +** +** Function bta_ag_sco_shutdown +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E); +} + +/******************************************************************************* +** +** Function bta_ag_sco_conn_open +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E); + + bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_ON); + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + /* open SCO codec if SCO is routed through transport */ + bta_dm_sco_co_open(bta_ag_scb_to_idx(p_scb), BTA_SCO_OUT_PKT_SIZE, BTA_AG_CI_SCO_DATA_EVT); +#endif + + /* call app callback */ + bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT); + + p_scb->retry_with_sco_only = FALSE; +} + +/******************************************************************************* +** +** Function bta_ag_sco_conn_close +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + UINT16 handle = bta_ag_scb_to_idx(p_scb); + + /* clear current scb */ + bta_ag_cb.sco.p_curr_scb = NULL; + p_scb->sco_idx = BTM_INVALID_SCO_INDEX; + +#if (BTM_WBS_INCLUDED == TRUE) + /* codec_fallback is set when AG is initiator and connection failed for mSBC. */ + if (p_scb->codec_fallback && p_scb->svc_conn) + { + bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E); + } + else if (p_scb->retry_with_sco_only && p_scb->svc_conn) + { + /* retry_with_sco_only is set when AG is initiator and connection failed for eSCO */ + bta_ag_create_sco(p_scb, TRUE); + } +#else + /* retry_with_sco_only, will be set only when AG is initiator + ** and AG is first trying to establish an eSCO connection */ + if (p_scb->retry_with_sco_only && p_scb->svc_conn) + { + bta_ag_create_sco(p_scb, TRUE); + } +#endif + else + { + /* Indicate if the closing of audio is because of transfer */ + if (bta_ag_cb.sco.p_xfer_scb) + bta_ag_co_audio_state(handle, p_scb->app_id, BTA_AG_CO_AUD_STATE_OFF_XFER); + else + bta_ag_co_audio_state(handle, p_scb->app_id, BTA_AG_CO_AUD_STATE_OFF); + + bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E); + + bta_sys_sco_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + /* if av got suspended by this call, let it resume. */ + /* In case call stays alive regardless of sco, av should not be affected. */ + if(((p_scb->call_ind == BTA_AG_CALL_INACTIVE) && (p_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE)) + || (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END)) + { + bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + } + + /* call app callback */ + bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT); + } + p_scb->retry_with_sco_only = FALSE; +} + +/******************************************************************************* +** +** Function bta_ag_sco_conn_rsp +** +** Description Process the SCO connection request +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data) +{ + tBTM_ESCO_PARAMS resp; + UINT8 hci_status = HCI_SUCCESS; +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + tBTA_CODEC_INFO codec_info = {BTA_SCO_CODEC_PCM}; + UINT32 pcm_sample_rate; +#endif + + if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST || + bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST || + bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST) + { + /* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */ + if (bta_ag_cb.sco.param_updated) + { + resp = bta_ag_cb.sco.params; + } + else + { + resp.rx_bw = BTM_64KBITS_RATE; + resp.tx_bw = BTM_64KBITS_RATE; + resp.max_latency = 10; + resp.voice_contfmt = 0x60; + resp.retrans_effort = BTM_ESCO_RETRANS_POWER; + + if (p_data->link_type == BTM_LINK_TYPE_SCO) + { + resp.packet_types = (BTM_SCO_LINK_ONLY_MASK | + BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | + BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5); + } + else /* Allow controller to use all types available except 5-slot EDR */ + { + resp.packet_types = (BTM_SCO_LINK_ALL_PKT_MASK | + BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | + BTM_SCO_PKT_TYPES_MASK_NO_3_EV5); + } + } + + /* tell sys to stop av if any */ + bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); + + /* Allow any platform specific pre-SCO set up to take place */ + bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP); + +#if (BTM_WBS_INCLUDED == TRUE ) + /* When HS initiated SCO, it cannot be WBS. */ + BTM_ConfigI2SPCM (BTM_SCO_CODEC_CVSD, (UINT8)HCI_BRCM_I2SPCM_IS_DEFAULT_ROLE, (UINT8)HCI_BRCM_I2SPCM_SAMPLE_DEFAULT, (UINT8)HCI_BRCM_I2SPCM_CLOCK_DEFAULT); +#endif + +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K; + + /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */ + BTM_ConfigScoPath(bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id), + bta_ag_sco_read_cback, NULL, TRUE); +#endif + } + else + hci_status = HCI_ERR_HOST_REJECT_DEVICE; + +#if (BTM_WBS_INCLUDED == TRUE ) + /* If SCO open was initiated from HS, it must be CVSD */ + p_scb->inuse_codec = BTA_AG_CODEC_NONE; +#endif + + BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp); +} + +/******************************************************************************* +** +** Function bta_ag_ci_sco_data +** +** Description Process the SCO data ready callin event +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ +#if (BTM_SCO_HCI_INCLUDED == TRUE ) + bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E); +#endif +} + +/******************************************************************************* +** +** Function bta_ag_set_esco_param +** +** Description Update esco parameters from script wrapper. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param) +{ + if(set_reset == FALSE) /* reset the parameters to default */ + { + bta_ag_cb.sco.param_updated = FALSE; + APPL_TRACE_DEBUG0("bta_ag_set_esco_param : Resetting ESCO parameters to default"); + } + else + { + bta_ag_cb.sco.param_updated = TRUE; + bta_ag_cb.sco.params = *param; + APPL_TRACE_DEBUG0("bta_ag_set_esco_param : Setting ESCO parameters"); + } +} + +/******************************************************************************* +** Debugging functions +*******************************************************************************/ + +#if BTA_AG_SCO_DEBUG == TRUE +static char *bta_ag_sco_evt_str(UINT8 event) +{ + switch (event) + { + case BTA_AG_SCO_LISTEN_E: + return "Listen Request"; + case BTA_AG_SCO_OPEN_E: + return "Open Request"; + case BTA_AG_SCO_XFER_E: + return "Transfer Request"; +#if (BTM_WBS_INCLUDED == TRUE ) + case BTA_AG_SCO_CN_DONE_E: + return "Codec Negotiation Done"; + case BTA_AG_SCO_REOPEN_E: + return "Reopen Request"; +#endif + case BTA_AG_SCO_CLOSE_E: + return "Close Request"; + case BTA_AG_SCO_SHUTDOWN_E: + return "Shutdown Request"; + case BTA_AG_SCO_CONN_OPEN_E: + return "Opened"; + case BTA_AG_SCO_CONN_CLOSE_E: + return "Closed"; + case BTA_AG_SCO_CI_DATA_E : + return "Sco Data"; + default: + return "Unknown SCO Event"; + } +} + +static char *bta_ag_sco_state_str(UINT8 state) +{ + switch (state) + { + case BTA_AG_SCO_SHUTDOWN_ST: + return "Shutdown"; + case BTA_AG_SCO_LISTEN_ST: + return "Listening"; +#if (BTM_WBS_INCLUDED == TRUE ) + case BTA_AG_SCO_CODEC_ST: + return "Codec Negotiation"; +#endif + case BTA_AG_SCO_OPENING_ST: + return "Opening"; + case BTA_AG_SCO_OPEN_CL_ST: + return "Open while closing"; + case BTA_AG_SCO_OPEN_XFER_ST: + return "Opening while Transferring"; + case BTA_AG_SCO_OPEN_ST: + return "Open"; + case BTA_AG_SCO_CLOSING_ST: + return "Closing"; + case BTA_AG_SCO_CLOSE_OP_ST: + return "Close while Opening"; + case BTA_AG_SCO_CLOSE_XFER_ST: + return "Close while Transferring"; + case BTA_AG_SCO_SHUTTING_ST: + return "Shutting Down"; + default: + return "Unknown SCO State"; + } +} + +#endif diff --git a/bta/ag/bta_ag_sdp.c b/bta/ag/bta_ag_sdp.c new file mode 100644 index 0000000..d708cf2 --- /dev/null +++ b/bta/ag/bta_ag_sdp.c @@ -0,0 +1,500 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the audio gateway functions performing SDP + * operations. + * + ******************************************************************************/ + +#include <string.h> +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_ag_api.h" +#include "bta_ag_int.h" +#include "sdp_api.h" +#include "btm_api.h" +#include "gki.h" + +/* Number of protocol elements in protocol element list. */ +#define BTA_AG_NUM_PROTO_ELEMS 2 + +/* Number of elements in service class id list. */ +#define BTA_AG_NUM_SVC_ELEMS 2 + +/* size of database for service discovery */ +#ifndef BTA_AG_DISC_BUF_SIZE +#define BTA_AG_DISC_BUF_SIZE GKI_MAX_BUF_SIZE +#endif + +/* declare sdp callback functions */ +void bta_ag_sdp_cback_1(UINT16 status); +void bta_ag_sdp_cback_2(UINT16 status); +void bta_ag_sdp_cback_3(UINT16 status); + +/* SDP callback function table */ +typedef tSDP_DISC_CMPL_CB *tBTA_AG_SDP_CBACK; +const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] = +{ + bta_ag_sdp_cback_1, + bta_ag_sdp_cback_2, + bta_ag_sdp_cback_3 +}; + +/******************************************************************************* +** +** Function bta_ag_sdp_cback +** +** Description SDP callback function. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_sdp_cback(UINT16 status, UINT8 idx) +{ + tBTA_AG_DISC_RESULT *p_buf; + UINT16 event; + tBTA_AG_SCB *p_scb; + + APPL_TRACE_DEBUG1("bta_ag_sdp_cback status:0x%x", status); + + if ((p_scb = bta_ag_scb_by_idx(idx)) != NULL) + { + /* set event according to int/acp */ + if (p_scb->role == BTA_AG_ACP) + { + event = BTA_AG_DISC_ACP_RES_EVT; + } + else + { + event = BTA_AG_DISC_INT_RES_EVT; + } + + if ((p_buf = (tBTA_AG_DISC_RESULT *) GKI_getbuf(sizeof(tBTA_AG_DISC_RESULT))) != NULL) + { + p_buf->hdr.event = event; + p_buf->hdr.layer_specific = idx; + p_buf->status = status; + bta_sys_sendmsg(p_buf); + } + } +} + +/******************************************************************************* +** +** Function bta_ag_sdp_cback_1 to 3 +** +** Description SDP callback functions. Since there is no way to +** distinguish scb from the callback we need separate +** callbacks for each scb. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_sdp_cback_1(UINT16 status) {bta_ag_sdp_cback(status, 1);} +void bta_ag_sdp_cback_2(UINT16 status) {bta_ag_sdp_cback(status, 2);} +void bta_ag_sdp_cback_3(UINT16 status) {bta_ag_sdp_cback(status, 3);} + +/****************************************************************************** +** +** Function bta_ag_add_record +** +** Description This function is called by a server application to add +** HSP or HFP information to an SDP record. Prior to +** calling this function the application must call +** SDP_CreateRecord() to create an SDP record. +** +** Returns TRUE if function execution succeeded, +** FALSE if function execution failed. +** +******************************************************************************/ +BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn, + tBTA_AG_FEAT features, UINT32 sdp_handle) +{ + tSDP_PROTOCOL_ELEM proto_elem_list[BTA_AG_NUM_PROTO_ELEMS]; + UINT16 svc_class_id_list[BTA_AG_NUM_SVC_ELEMS]; + UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP}; + UINT16 version; + UINT16 profile_uuid; + UINT8 network; + BOOLEAN result = TRUE; + BOOLEAN codec_supported = FALSE; + UINT8 buf[2]; + + APPL_TRACE_DEBUG1("bta_ag_add_record uuid: %x", service_uuid); + + memset( proto_elem_list, 0 , BTA_AG_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM)); + + /* add the protocol element sequence */ + proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + proto_elem_list[0].num_params = 0; + proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM; + proto_elem_list[1].num_params = 1; + proto_elem_list[1].params[0] = scn; + result &= SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list); + + /* add service class id list */ + svc_class_id_list[0] = service_uuid; + svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO; + result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS, svc_class_id_list); + + /* add profile descriptor list */ + if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) + { + profile_uuid = UUID_SERVCLASS_HF_HANDSFREE; + version = HFP_VERSION_1_6; + } + else + { + profile_uuid = UUID_SERVCLASS_HEADSET; + version = HSP_VERSION_1_2; + } + result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version); + + /* add service name */ + if (p_service_name != NULL && p_service_name[0] != 0) + { + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name); + } + + /* add features and network */ + if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) + { + network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0; + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK, + UINT_DESC_TYPE, 1, &network); + + if (features & BTA_AG_FEAT_CODEC) + codec_supported = TRUE; + + features &= BTA_AG_SDP_FEAT_SPEC; + + /* Codec bit position is different in SDP and in BRSF */ + if (codec_supported) + features |= 0x0020; + + UINT16_TO_BE_FIELD(buf, features); + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf); + } + + /* add browse group list */ + result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); + + return result; +} + +/******************************************************************************* +** +** Function bta_ag_create_records +** +** Description Create SDP records for registered services. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + int i; + tBTA_SERVICE_MASK services; + + services = p_scb->reg_services >> BTA_HSP_SERVICE_ID; + for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) + { + /* if service is set in mask */ + if (services & 1) + { + /* add sdp record if not already registered */ + if (bta_ag_cb.profile[i].sdp_handle == 0) + { + bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord(); + bta_ag_cb.profile[i].scn = BTM_AllocateSCN(); + bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i], + bta_ag_cb.profile[i].scn, p_data->api_register.features, + bta_ag_cb.profile[i].sdp_handle); + bta_sys_add_uuid(bta_ag_uuid[i]); + } + } + } + + p_scb->hsp_version = HSP_VERSION_1_2; + +} + +/******************************************************************************* +** +** Function bta_ag_del_records +** +** Description Delete SDP records for any registered services. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + tBTA_AG_SCB *p = &bta_ag_cb.scb[0]; + tBTA_SERVICE_MASK services; + tBTA_SERVICE_MASK others = 0; + int i; + + /* get services of all other registered servers */ + for (i = 0; i < BTA_AG_NUM_IDX; i++, p++) + { + if (p_scb == p) + { + continue; + } + + if (p->in_use && p->dealloc == FALSE) + { + others |= p->reg_services; + } + } + + others >>= BTA_HSP_SERVICE_ID; + services = p_scb->reg_services >> BTA_HSP_SERVICE_ID; + for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1, others >>= 1) + { + /* if service registered for this scb and not registered for any other scb */ + if (((services & 1) == 1) && ((others & 1) == 0)) + { + APPL_TRACE_DEBUG1("bta_ag_del_records %d", i); + if (bta_ag_cb.profile[i].sdp_handle != 0) + { + SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle); + bta_ag_cb.profile[i].sdp_handle = 0; + } + BTM_FreeSCN(bta_ag_cb.profile[i].scn); + BTM_SecClrService(bta_ag_sec_id[i]); + bta_sys_remove_uuid(bta_ag_uuid[i]); + } + } +} + +/******************************************************************************* +** +** Function bta_ag_sdp_find_attr +** +** Description Process SDP discovery results to find requested attributes +** for requested service. +** +** +** Returns TRUE if results found, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) +{ + tSDP_DISC_REC *p_rec = NULL; + tSDP_DISC_ATTR *p_attr; + tSDP_PROTOCOL_ELEM pe; + UINT16 uuid; + BOOLEAN result = FALSE; + + if (service & BTA_HFP_SERVICE_MASK) + { + uuid = UUID_SERVCLASS_HF_HANDSFREE; + p_scb->peer_version = HFP_VERSION_1_1; /* Default version */ + } + else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) + { + uuid = UUID_SERVCLASS_HEADSET_HS; + p_scb->peer_version = 0x0100; /* Default version */ + } + else + { + return result; + } + + /* loop through all records we found */ + while (TRUE) + { + /* get next record; if none found, we're done */ + if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) + { + if (uuid == UUID_SERVCLASS_HEADSET_HS) + { + /* Search again in case the peer device is HSP v1.0 */ + uuid = UUID_SERVCLASS_HEADSET; + if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) + { + break; + } + } + else + break; + } + + /* get scn from proto desc list if initiator */ + if (p_scb->role == BTA_AG_INT) + { + if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) + { + p_scb->peer_scn = (UINT8) pe.params[0]; + } + else + { + continue; + } + } + + /* get profile version (if failure, version parameter is not updated) */ + SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version); + + /* get features if HFP */ + if (service & BTA_HFP_SERVICE_MASK) + { + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) + { + /* Found attribute. Get value. */ + /* There might be race condition between SDP and BRSF. */ + /* Do not update if we already received BRSF. */ + if (p_scb->peer_features == 0) + p_scb->peer_features = p_attr->attr_value.v.u16; + } + } + else /* HSP */ + { + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL) + { + /* Remote volume control of HSP */ + if (p_attr->attr_value.v.u8) + p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL; + else + p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL; + } + + } + + /* found what we needed */ + result = TRUE; + break; + } + return result; +} + +/******************************************************************************* +** +** Function bta_ag_do_disc +** +** Description Do service discovery. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) +{ + tSDP_UUID uuid_list[2]; + UINT16 num_uuid = 1; + UINT16 attr_list[4]; + UINT8 num_attr; + BOOLEAN db_inited = FALSE; + + /* HFP initiator; get proto list and features */ + if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT) + { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; + attr_list[3] = ATTR_ID_SUPPORTED_FEATURES; + num_attr = 4; + uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE; + } + /* HFP acceptor; get features */ + else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP) + { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST; + attr_list[2] = ATTR_ID_SUPPORTED_FEATURES; + num_attr = 3; + uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE; + } + /* HSP initiator; get proto list */ + else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) + { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; + attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL; + num_attr = 4; + + uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET; /* Legacy from HSP v1.0 */ + if (p_scb->hsp_version >= HSP_VERSION_1_2) + { + uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS; + num_uuid = 2; + } + } + /* HSP acceptor; no discovery */ + else + { + return; + } + + /* allocate buffer for sdp database */ + p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AG_DISC_BUF_SIZE); + + if(p_scb->p_disc_db) + { + /* set up service discovery database; attr happens to be attr_list len */ + uuid_list[0].len = LEN_UUID_16; + uuid_list[1].len = LEN_UUID_16; + db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid, + uuid_list, num_attr, attr_list); + } + + if(db_inited) + { + /*Service discovery not initiated */ + db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db, + bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]); + } + + if(!db_inited) + { + /*free discover db */ + bta_ag_free_db(p_scb, NULL); + /* sent failed event */ + bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL); + } + +} + +/******************************************************************************* +** +** Function bta_ag_free_db +** +** Description Free discovery database. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + if (p_scb->p_disc_db != NULL) + { + GKI_freebuf(p_scb->p_disc_db); + p_scb->p_disc_db = NULL; + } +} diff --git a/bta/ar/bta_ar.c b/bta/ar/bta_ar.c new file mode 100644 index 0000000..89b732a --- /dev/null +++ b/bta/ar/bta_ar.c @@ -0,0 +1,348 @@ +/****************************************************************************** + * + * Copyright (C) 2008-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 for the audio/video registration module. + * + ******************************************************************************/ + +#include <string.h> +#include "bta_ar_api.h" +#include "bta_ar_int.h" + + +/* AV control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_AR_CB bta_ar_cb; +#endif + +/******************************************************************************* +** +** Function bta_ar_id +** +** Description This function maps sys_id to ar id mask. +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_ar_id(tBTA_SYS_ID sys_id) +{ + UINT8 mask = 0; + if (sys_id == BTA_ID_AV) + { + mask = BTA_AR_AV_MASK; + } + else if (sys_id == BTA_ID_AVK) + { + mask = BTA_AR_AVK_MASK; + } + + return mask; +} + +/******************************************************************************* +** +** Function bta_ar_init +** +** Description This function is called to register to AVDTP. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_init(void) +{ + /* initialize control block */ + memset(&bta_ar_cb, 0, sizeof(tBTA_AR_CB)); +} + +/******************************************************************************* +** +** Function bta_ar_reg_avdt +** +** Description This function is called to register to AVDTP. +** +** Returns void +** +*******************************************************************************/ +static void bta_ar_avdt_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + /* route the AVDT registration callback to av or avk */ + if (bta_ar_cb.p_av_conn_cback) + (*bta_ar_cb.p_av_conn_cback)(handle, bd_addr, event, p_data); + if (bta_ar_cb.p_avk_conn_cback) + (*bta_ar_cb.p_avk_conn_cback)(handle, bd_addr, event, p_data); +} + +/******************************************************************************* +** +** Function bta_ar_reg_avdt +** +** Description AR module registration to AVDT. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_reg_avdt(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback, tBTA_SYS_ID sys_id) +{ + UINT8 mask = 0; + + if (sys_id == BTA_ID_AV) + { + bta_ar_cb.p_av_conn_cback = p_cback; + mask = BTA_AR_AV_MASK; + } + else if (sys_id == BTA_ID_AVK) + { + bta_ar_cb.p_avk_conn_cback = p_cback; + mask = BTA_AR_AVK_MASK; + } +#if (BTA_AR_DEBUG == TRUE) + else + { + APPL_TRACE_ERROR1("bta_ar_reg_avdt: the registration is from wrong sys_id:%d", sys_id); + } +#endif + + if (mask) + { + if (bta_ar_cb.avdt_registered == 0) + { + AVDT_Register(p_reg, bta_ar_avdt_cback); + } + bta_ar_cb.avdt_registered |= mask; + } +} + +/******************************************************************************* +** +** Function bta_ar_dereg_avdt +** +** Description This function is called to de-register from AVDTP. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id) +{ + UINT8 mask = 0; + + if (sys_id == BTA_ID_AV) + { + bta_ar_cb.p_av_conn_cback = NULL; + mask = BTA_AR_AV_MASK; + } + else if (sys_id == BTA_ID_AVK) + { + bta_ar_cb.p_avk_conn_cback = NULL; + mask = BTA_AR_AVK_MASK; + } + bta_ar_cb.avdt_registered &= ~mask; + + if (bta_ar_cb.avdt_registered == 0) + AVDT_Deregister(); +} + +/******************************************************************************* +** +** Function bta_ar_avdt_conn +** +** Description This function is called to let ar know that some AVDTP profile +** is connected for this sys_id. +** If the other sys modules started a timer for PENDING_EVT, +** the timer can be stopped now. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr) +{ + UINT8 event = BTA_AR_AVDT_CONN_EVT; + tAVDT_CTRL data; + + if (sys_id == BTA_ID_AV) + { + if (bta_ar_cb.p_avk_conn_cback) + { + (*bta_ar_cb.p_avk_conn_cback)(0, bd_addr, event, &data); + } + } + else if (sys_id == BTA_ID_AVK) + { + if (bta_ar_cb.p_av_conn_cback) + { + (*bta_ar_cb.p_av_conn_cback)(0, bd_addr, event, &data); + } + } +} + +/******************************************************************************* +** +** Function bta_ar_reg_avct +** +** Description This function is called to register to AVCTP. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_reg_avct(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask, tBTA_SYS_ID sys_id) +{ + UINT8 mask = bta_ar_id (sys_id); + + if (mask) + { + if (bta_ar_cb.avct_registered == 0) + { + AVCT_Register(mtu, mtu_br, sec_mask); + } + bta_ar_cb.avct_registered |= mask; + } +} + +/******************************************************************************* +** +** Function bta_ar_dereg_avct +** +** Description This function is called to deregister from AVCTP. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_dereg_avct(tBTA_SYS_ID sys_id) +{ + UINT8 mask = bta_ar_id (sys_id); + + bta_ar_cb.avct_registered &= ~mask; + + if (bta_ar_cb.avct_registered == 0) + AVCT_Deregister(); +} + +/****************************************************************************** +** +** Function bta_ar_reg_avrc +** +** Description This function is called to register an SDP record for AVRCP. +** +** Returns void +** +******************************************************************************/ +void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_name, + UINT16 categories, tBTA_SYS_ID sys_id) +{ + UINT8 mask = bta_ar_id (sys_id); + UINT8 temp[8], *p; + + if (!mask || !categories) + return; + + if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) + { + if (bta_ar_cb.sdp_tg_handle == 0) + { + bta_ar_cb.tg_registered = mask; + bta_ar_cb.sdp_tg_handle = SDP_CreateRecord(); + AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_tg_handle); +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) + bta_sys_add_uuid(service_uuid); +#endif + } + /* only one TG is allowed (first-come, first-served). + * If sdp_tg_handle is non-0, ignore this request */ + } + else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) || (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL)) + { + bta_ar_cb.ct_categories [mask - 1] = categories; + categories = bta_ar_cb.ct_categories[0]|bta_ar_cb.ct_categories[1]; + if (bta_ar_cb.sdp_ct_handle == 0) + { + bta_ar_cb.sdp_ct_handle = SDP_CreateRecord(); + AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_ct_handle); +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) + bta_sys_add_uuid(service_uuid); +#endif + } + else + { + /* multiple CTs are allowed. + * Change supported categories on the second one */ + p = temp; + UINT16_TO_BE_STREAM(p, categories); + SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (UINT32)2, (UINT8*)temp); + } + } +} + +/****************************************************************************** +** +** Function bta_ar_dereg_avrc +** +** Description This function is called to de-register/delete an SDP record for AVRCP. +** +** Returns void +** +******************************************************************************/ +void bta_ar_dereg_avrc(UINT16 service_uuid, tBTA_SYS_ID sys_id) +{ + UINT8 mask = bta_ar_id (sys_id); + UINT16 categories = 0; + UINT8 temp[8], *p; + + if (!mask) + return; + + if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) + { + if (bta_ar_cb.sdp_tg_handle && mask == bta_ar_cb.tg_registered) + { + bta_ar_cb.tg_registered = 0; + SDP_DeleteRecord(bta_ar_cb.sdp_tg_handle); + bta_ar_cb.sdp_tg_handle = 0; +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) + bta_sys_remove_uuid(service_uuid); +#endif + } + } + else if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) + { + if (bta_ar_cb.sdp_ct_handle) + { + bta_ar_cb.ct_categories [mask - 1] = 0; + categories = bta_ar_cb.ct_categories[0]|bta_ar_cb.ct_categories[1]; + if (!categories) + { + /* no CT is still registered - cleaup */ + SDP_DeleteRecord(bta_ar_cb.sdp_ct_handle); + bta_ar_cb.sdp_ct_handle = 0; +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) + bta_sys_remove_uuid(service_uuid); +#endif + } + else + { + /* change supported categories to the remaning one */ + p = temp; + UINT16_TO_BE_STREAM(p, categories); + SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (UINT32)2, (UINT8*)temp); + } + } + } + +} diff --git a/bta/ar/bta_ar_int.h b/bta/ar/bta_ar_int.h new file mode 100644 index 0000000..d230448 --- /dev/null +++ b/bta/ar/bta_ar_int.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright (C) 2008-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 private interface file for the BTA audio/video registration + * module. + * + ******************************************************************************/ +#ifndef BTA_AR_INT_H +#define BTA_AR_INT_H + +#include "bta_av_api.h" + + +#ifndef BTA_AR_DEBUG +#define BTA_AR_DEBUG FALSE +#endif + +#define BTA_AR_AV_MASK 0x01 +#define BTA_AR_AVK_MASK 0x02 + +/* data associated with BTA_AR */ +typedef struct +{ + tAVDT_CTRL_CBACK *p_av_conn_cback; /* av connection callback function */ + tAVDT_CTRL_CBACK *p_avk_conn_cback; /* avk connection callback function */ + UINT8 avdt_registered; + UINT8 avct_registered; + UINT32 sdp_tg_handle; + UINT32 sdp_ct_handle; + UINT16 ct_categories[2]; + UINT8 tg_registered; + tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the connection. */ +} tBTA_AR_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* control block declaration */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_AR_CB bta_ar_cb; +#else +extern tBTA_AR_CB *bta_ar_cb_ptr; +#define bta_ar_cb (*bta_ar_cb_ptr) +#endif + +#endif /* BTA_AR_INT_H */ diff --git a/bta/av/bta_av_aact.c b/bta/av/bta_av_aact.c new file mode 100644 index 0000000..741a5a0 --- /dev/null +++ b/bta/av/bta_av_aact.c @@ -0,0 +1,2733 @@ +/****************************************************************************** + * + * 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 file contains action functions for advanced audio/video stream + * state machine. these functions are shared by both audio and video + * streams. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#include <string.h> +#include "bta_av_int.h" +#include "avdt_api.h" +#include "bd.h" +#include "utl.h" +#include "l2c_api.h" +#include "l2cdefs.h" +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#include "bta_ar_api.h" +#endif + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* the delay time in milliseconds to start service discovery on AVRCP */ +#ifndef BTA_AV_RC_DISC_TIME_VAL +#define BTA_AV_RC_DISC_TIME_VAL 3500 +#endif + +/* the timer in milliseconds to guard against link busy and AVDT_CloseReq failed to be sent */ +#ifndef BTA_AV_CLOSE_REQ_TIME_VAL +#define BTA_AV_CLOSE_REQ_TIME_VAL 4000 +#endif + +/* number to retry on reconfigure failure - some headsets requirs this number to be more than 1 */ +#ifndef BTA_AV_RECONFIG_RETRY +#define BTA_AV_RECONFIG_RETRY 6 +#endif + +/* state machine states */ +enum +{ + BTA_AV_INIT_SST, + BTA_AV_INCOMING_SST, + BTA_AV_OPENING_SST, + BTA_AV_OPEN_SST, + BTA_AV_RCFG_SST, + BTA_AV_CLOSING_SST +}; + + +/* the call out functions for audio stream */ +const tBTA_AV_CO_FUNCTS bta_av_a2d_cos = +{ + bta_av_co_audio_init, + bta_av_co_audio_disc_res, + bta_av_co_audio_getconfig, + bta_av_co_audio_setconfig, + bta_av_co_audio_open, + bta_av_co_audio_close, + bta_av_co_audio_start, + bta_av_co_audio_stop, + bta_av_co_audio_src_data_path, + bta_av_co_audio_delay +}; + +/* ssm action functions for audio stream */ +const tBTA_AV_SACT bta_av_a2d_action[] = +{ + bta_av_do_disc_a2d, /* BTA_AV_DO_DISC */ + bta_av_cleanup, /* BTA_AV_CLEANUP */ + bta_av_free_sdb, /* BTA_AV_FREE_SDB */ + bta_av_config_ind, /* BTA_AV_CONFIG_IND */ + bta_av_disconnect_req, /* BTA_AV_DISCONNECT_REQ */ + bta_av_security_req, /* BTA_AV_SECURITY_REQ */ + bta_av_security_rsp, /* BTA_AV_SECURITY_RSP */ + bta_av_setconfig_rsp, /* BTA_AV_SETCONFIG_RSP */ + bta_av_st_rc_timer, /* BTA_AV_ST_RC_TIMER */ + bta_av_str_opened, /* BTA_AV_STR_OPENED */ + bta_av_security_ind, /* BTA_AV_SECURITY_IND */ + bta_av_security_cfm, /* BTA_AV_SECURITY_CFM */ + bta_av_do_close, /* BTA_AV_DO_CLOSE */ + bta_av_connect_req, /* BTA_AV_CONNECT_REQ */ + bta_av_sdp_failed, /* BTA_AV_SDP_FAILED */ + bta_av_disc_results, /* BTA_AV_DISC_RESULTS */ + bta_av_disc_res_as_acp, /* BTA_AV_DISC_RES_AS_ACP */ + bta_av_open_failed, /* BTA_AV_OPEN_FAILED */ + bta_av_getcap_results, /* BTA_AV_GETCAP_RESULTS */ + bta_av_setconfig_rej, /* BTA_AV_SETCONFIG_REJ */ + bta_av_discover_req, /* BTA_AV_DISCOVER_REQ */ + bta_av_conn_failed, /* BTA_AV_CONN_FAILED */ + bta_av_do_start, /* BTA_AV_DO_START */ + bta_av_str_stopped, /* BTA_AV_STR_STOPPED */ + bta_av_reconfig, /* BTA_AV_RECONFIG */ + bta_av_data_path, /* BTA_AV_DATA_PATH */ + bta_av_start_ok, /* BTA_AV_START_OK */ + bta_av_start_failed, /* BTA_AV_START_FAILED */ + bta_av_str_closed, /* BTA_AV_STR_CLOSED */ + bta_av_clr_cong, /* BTA_AV_CLR_CONG */ + bta_av_suspend_cfm, /* BTA_AV_SUSPEND_CFM */ + bta_av_rcfg_str_ok, /* BTA_AV_RCFG_STR_OK */ + bta_av_rcfg_failed, /* BTA_AV_RCFG_FAILED */ + bta_av_rcfg_connect, /* BTA_AV_RCFG_CONNECT */ + bta_av_rcfg_discntd, /* BTA_AV_RCFG_DISCNTD */ + bta_av_suspend_cont, /* BTA_AV_SUSPEND_CONT */ + bta_av_rcfg_cfm, /* BTA_AV_RCFG_CFM */ + bta_av_rcfg_open, /* BTA_AV_RCFG_OPEN */ + bta_av_security_rej, /* BTA_AV_SECURITY_REJ */ + bta_av_open_rc, /* BTA_AV_OPEN_RC */ + bta_av_chk_2nd_start, /* BTA_AV_CHK_2ND_START */ + bta_av_save_caps, /* BTA_AV_SAVE_CAPS */ + bta_av_set_use_rc, /* BTA_AV_SET_USE_RC */ + bta_av_cco_close, /* BTA_AV_CCO_CLOSE */ + bta_av_switch_role, /* BTA_AV_SWITCH_ROLE */ + bta_av_role_res, /* BTA_AV_ROLE_RES */ + bta_av_delay_co, /* BTA_AV_DELAY_CO */ + bta_av_open_at_inc, /* BTA_AV_OPEN_AT_INC */ + NULL +}; + +/* these tables translate AVDT events to SSM events */ +static const UINT16 bta_av_stream_evt_ok[] = { + BTA_AV_STR_DISC_OK_EVT, /* AVDT_DISCOVER_CFM_EVT */ + BTA_AV_STR_GETCAP_OK_EVT, /* AVDT_GETCAP_CFM_EVT */ + BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_CFM_EVT */ + BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_IND_EVT */ + BTA_AV_STR_CONFIG_IND_EVT, /* AVDT_CONFIG_IND_EVT */ + BTA_AV_STR_START_OK_EVT, /* AVDT_START_CFM_EVT */ + BTA_AV_STR_START_OK_EVT, /* AVDT_START_IND_EVT */ + BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_CFM_EVT */ + BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_IND_EVT */ + BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_CFM_EVT */ + BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_IND_EVT */ + BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */ + 0, /* AVDT_RECONFIG_IND_EVT */ + BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */ + BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */ + BTA_AV_STR_WRITE_CFM_EVT, /* AVDT_WRITE_CFM_EVT */ + BTA_AV_AVDT_CONNECT_EVT, /* AVDT_CONNECT_IND_EVT */ + BTA_AV_AVDT_DISCONNECT_EVT, /* AVDT_DISCONNECT_IND_EVT */ +#if (AVDT_REPORTING == TRUE) + BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */ + BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */ +#endif + BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */ + 0 /* AVDT_DELAY_REPORT_CFM_EVT */ +}; + +static const UINT16 bta_av_stream_evt_fail[] = { + BTA_AV_STR_DISC_FAIL_EVT, /* AVDT_DISCOVER_CFM_EVT */ + BTA_AV_STR_GETCAP_FAIL_EVT, /* AVDT_GETCAP_CFM_EVT */ + BTA_AV_STR_OPEN_FAIL_EVT, /* AVDT_OPEN_CFM_EVT */ + BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_IND_EVT */ + BTA_AV_STR_CONFIG_IND_EVT, /* AVDT_CONFIG_IND_EVT */ + BTA_AV_STR_START_FAIL_EVT, /* AVDT_START_CFM_EVT */ + BTA_AV_STR_START_OK_EVT, /* AVDT_START_IND_EVT */ + BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_CFM_EVT */ + BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_IND_EVT */ + BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_CFM_EVT */ + BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_IND_EVT */ + BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */ + 0, /* AVDT_RECONFIG_IND_EVT */ + BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */ + BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */ + BTA_AV_STR_WRITE_CFM_EVT, /* AVDT_WRITE_CFM_EVT */ + BTA_AV_AVDT_CONNECT_EVT, /* AVDT_CONNECT_IND_EVT */ + BTA_AV_AVDT_DISCONNECT_EVT, /* AVDT_DISCONNECT_IND_EVT */ +#if (AVDT_REPORTING == TRUE) + BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */ + BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */ +#endif + BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */ + 0 /* AVDT_DELAY_REPORT_CFM_EVT */ +}; + +static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#if BTA_AV_NUM_STRS > 2 +static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#endif +#if BTA_AV_NUM_STRS > 3 +static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#endif +#if BTA_AV_NUM_STRS > 4 +static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#endif +#if BTA_AV_NUM_STRS > 5 +static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#endif +/* the array of callback functions to receive events from AVDT control channel */ +tAVDT_CTRL_CBACK * const bta_av_dt_cback[] = +{ + bta_av_stream0_cback + ,bta_av_stream1_cback +#if BTA_AV_NUM_STRS > 2 + ,bta_av_stream2_cback +#endif +#if BTA_AV_NUM_STRS > 3 + ,bta_av_stream3_cback +#endif +#if BTA_AV_NUM_STRS > 4 + ,bta_av_stream4_cback +#endif +#if BTA_AV_NUM_STRS > 5 + ,bta_av_stream5_cback +#endif +}; + +/******************************************************************************* +** +** Function bta_av_save_addr +** +** Description copy the bd_addr and maybe reset the supported flags +** +** +** Returns void +** +*******************************************************************************/ +static void bta_av_save_addr(tBTA_AV_SCB *p_scb, const BD_ADDR b) +{ + APPL_TRACE_DEBUG2("bta_av_save_addr r:%d, s:%d", + p_scb->recfg_sup, p_scb->suspend_sup); + if(bdcmp(p_scb->peer_addr, b) != 0) + { + APPL_TRACE_ERROR0("reset flags"); + /* a new addr, reset the supported flags */ + p_scb->recfg_sup = TRUE; + p_scb->suspend_sup = TRUE; + } + + /* do this copy anyway, just in case the first addr matches + * the control block one by accident */ + bdcpy(p_scb->peer_addr, b); +} + +/******************************************************************************* +** +** Function bta_av_st_rc_timer +** +** Description start the AVRC timer if no RC connection & CT is supported & +** RC is used or +** as ACP (we do not really know if we want AVRC) +** +** Returns void +** +*******************************************************************************/ +void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + + APPL_TRACE_DEBUG2("bta_av_st_rc_timer rc_handle:%d, use_rc: %d", + p_scb->rc_handle, p_scb->use_rc); + /* for outgoing RC connection as INT/CT */ + if( (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) && + /*(bta_av_cb.features & BTA_AV_FEAT_RCCT) &&*/ + (p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP)) ) + { + if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) + bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL); + else + p_scb->wait |= BTA_AV_WAIT_CHECK_RC; + } + +} + +/******************************************************************************* +** +** Function bta_av_next_getcap +** +** Description The function gets the capabilities of the next available +** stream found in the discovery results. +** +** Returns TRUE if we sent request to AVDT, FALSE otherwise. +** +*******************************************************************************/ +static BOOLEAN bta_av_next_getcap(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + int i; + tAVDT_GETCAP_REQ *p_req; + BOOLEAN sent_cmd = FALSE; + + for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++) + { + /* steam not in use, is a sink, and is the right media type (audio/video) */ + if ((p_scb->sep_info[i].in_use == FALSE) && + (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && + (p_scb->sep_info[i].media_type == p_scb->media_type)) + { + p_scb->sep_info_idx = i; + + /* we got a stream; get its capabilities */ + if (p_scb->p_cap == NULL) + { + p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG)); + } + if (p_scb->p_cap == NULL) + { + i = p_scb->num_seps; + break; + } + if (p_scb->avdt_version >= AVDT_VERSION_SYNC) + { + p_req = AVDT_GetAllCapReq; + } + else + { + p_req = AVDT_GetCapReq; + } + (*p_req)(p_scb->peer_addr, + p_scb->sep_info[i].seid, + p_scb->p_cap, bta_av_dt_cback[p_scb->hdi]); + sent_cmd = TRUE; + break; + } + } + + /* if no streams available then stream open fails */ + if (!sent_cmd) + { + bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data); + } + + return sent_cmd; + +} + +/******************************************************************************* +** +** Function bta_av_proc_stream_evt +** +** Description Utility function to compose stream events. +** +** Returns void +** +*******************************************************************************/ +void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data, int index) +{ + tBTA_AV_STR_MSG *p_msg; + UINT16 sec_len = 0; + tBTA_AV_SCB *p_scb = bta_av_cb.p_scb[index]; + int xx; + + if (p_data) + { + if (event == AVDT_SECURITY_IND_EVT) + { + sec_len = (p_data->security_ind.len < BTA_AV_SECURITY_MAX_LEN) ? + p_data->security_ind.len : BTA_AV_SECURITY_MAX_LEN; + } + else if (event == AVDT_SECURITY_CFM_EVT && p_data->hdr.err_code == 0) + { + sec_len = (p_data->security_cfm.len < BTA_AV_SECURITY_MAX_LEN) ? + p_data->security_cfm.len : BTA_AV_SECURITY_MAX_LEN; + } + } + + if (p_scb && (p_msg = (tBTA_AV_STR_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_STR_MSG) + sec_len))) != NULL) + { + + /* copy event data, bd addr, and handle to event message buffer */ + p_msg->hdr.offset = 0; + + if (bd_addr != NULL) + { + bdcpy(p_msg->bd_addr, bd_addr); + APPL_TRACE_DEBUG6(" bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + bd_addr[0], bd_addr[1], + bd_addr[2], bd_addr[3], + bd_addr[4], bd_addr[5]); + } + + if (p_data != NULL) + { + memcpy(&p_msg->msg, p_data, sizeof (tAVDT_CTRL)); + /* copy config params to event message buffer */ + switch (event) + { + case AVDT_CONFIG_IND_EVT: + /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on one L2CAP. + * If we already have a signalling connection with the bd_addr and the streaming + * SST is at INIT state, change it to INCOMING state to handle the signalling + * from the 2nd SEP. */ + if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb))) + { + bta_av_set_scb_sst_incoming (p_scb); + + /* When ACP_CONNECT_EVT was received, we put first available scb to incoming state. + * Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and set its state to + * incoming which we do it above. + * We also have to set the old p_scb state to init to be used later */ + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) + { + if ((bta_av_cb.p_scb[xx]) && (xx != index)) + { + if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST) + { + bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST; + bta_av_cb.p_scb[xx]->coll_mask = 0; + break; + } + } + } + } + + memcpy(&p_msg->cfg, p_data->config_ind.p_cfg, sizeof(tAVDT_CFG)); + break; + + case AVDT_SECURITY_IND_EVT: + p_msg->msg.security_ind.p_data = (UINT8 *) (p_msg + 1); + memcpy(p_msg->msg.security_ind.p_data, p_data->security_ind.p_data, sec_len); + break; + + case AVDT_SECURITY_CFM_EVT: + p_msg->msg.security_cfm.p_data = (UINT8 *) (p_msg + 1); + if (p_data->hdr.err_code == 0) + { + memcpy(p_msg->msg.security_cfm.p_data, p_data->security_cfm.p_data, sec_len); + } + break; + case AVDT_SUSPEND_IND_EVT: + p_msg->msg.hdr.err_code = 0; + break; + + default: + break; + } + } + else + p_msg->msg.hdr.err_code = 0; + + /* look up application event */ + if ((p_data == NULL) || (p_data->hdr.err_code == 0)) + { + p_msg->hdr.event = bta_av_stream_evt_ok[event]; + } + else + { + p_msg->hdr.event = bta_av_stream_evt_fail[event]; + } + + p_msg->initiator = FALSE; + if (event == AVDT_SUSPEND_CFM_EVT) + p_msg->initiator = TRUE; + + APPL_TRACE_EVENT1("hndl:x%x", p_scb->hndl); + p_msg->hdr.layer_specific = p_scb->hndl; + p_msg->handle = handle; + p_msg->avdt_event = event; + bta_sys_sendmsg(p_msg); + } + +/* coverity[var_deref_model]: Variable "p_data" tracked as NULL was passed to function "bta_av_conn_cback" that dereferences it. + * false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event + * these 2 events always have associated p_data + */ + bta_av_conn_cback(handle, bd_addr, event, p_data); +} + +/******************************************************************************* +** +** Function bta_av_stream0_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT2("bta_av_stream0_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0); +} + +/******************************************************************************* +** +** Function bta_av_stream1_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT2("bta_av_stream1_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 1); +} + +#if BTA_AV_NUM_STRS > 2 +/******************************************************************************* +** +** Function bta_av_stream2_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT2("bta_av_stream2_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 2); +} +#endif + +#if BTA_AV_NUM_STRS > 3 +/******************************************************************************* +** +** Function bta_av_stream3_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT2("bta_av_stream3_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 3); +} +#endif + +/******************************************************************************* +** +** Function bta_av_stream4_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +#if BTA_AV_NUM_STRS > 4 +static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT2("bta_av_stream4_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 4); +} +#endif + +/******************************************************************************* +** +** Function bta_av_stream5_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +#if BTA_AV_NUM_STRS > 5 +static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT2("bta_av_stream5_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 5); +} +#endif + +/******************************************************************************* +** +** Function bta_av_a2d_sdp_cback +** +** Description A2DP service discovery callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_a2d_sdp_cback(BOOLEAN found, tA2D_Service *p_service) +{ + tBTA_AV_SDP_RES *p_msg; + tBTA_AV_SCB *p_scb; + + if ((p_msg = (tBTA_AV_SDP_RES *) GKI_getbuf(sizeof(tBTA_AV_SDP_RES))) != NULL) + { + p_msg->hdr.event = (found) ? BTA_AV_SDP_DISC_OK_EVT : BTA_AV_SDP_DISC_FAIL_EVT; + + p_scb = bta_av_hndl_to_scb(bta_av_cb.handle); + if (p_scb) + { + if (found && (p_service != NULL)) + p_scb->avdt_version = p_service->avdt_version; + else + p_scb->avdt_version = 0x00; + + p_msg->hdr.layer_specific = bta_av_cb.handle; + bta_sys_sendmsg(p_msg); + } + else + { + APPL_TRACE_ERROR1 ("bta_av_a2d_sdp_cback, no scb found for handle(0x%x)", bta_av_cb.handle); + } + } +} + +/******************************************************************************* +** +** Function bta_av_adjust_seps_idx +** +** Description adjust the sep_idx +** +** Returns +** +*******************************************************************************/ +static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb) +{ + int xx; + + APPL_TRACE_DEBUG1("bta_av_adjust_seps_idx codec_type: %d", p_scb->codec_type); + for(xx=0; xx<BTA_AV_MAX_SEPS; xx++) + { + APPL_TRACE_DEBUG2("av_handle: %d codec_type: %d", + p_scb->seps[xx].av_handle, p_scb->seps[xx].codec_type); + if(p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type) + { + p_scb->sep_idx = xx; + p_scb->avdt_handle = p_scb->seps[xx].av_handle; + break; + } + } +} + +/******************************************************************************* +** +** Function bta_av_switch_role +** +** Description Switch role was not started and a timer was started. +** another attempt to switch role now - still opening. +** +** Returns void +** +*******************************************************************************/ +void bta_av_switch_role (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RS_RES switch_res = BTA_AV_RS_NONE; + tBTA_AV_API_OPEN *p_buf = &p_scb->q_info.open; + + APPL_TRACE_DEBUG1("bta_av_switch_role wait:x%x", p_scb->wait); + if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START) + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY; + + /* clear the masks set when the timer is started */ + p_scb->wait &= ~(BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START); + + if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN) + { + if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT)) + { + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN; + } + else + { + /* this should not happen in theory. Just in case... + * continue to do_disc_a2d */ + switch_res = BTA_AV_RS_DONE; + } + } + else + { + /* report failure on OPEN */ + switch_res = BTA_AV_RS_FAIL; + } + + if (switch_res != BTA_AV_RS_NONE) + { + if (bta_av_cb.rs_idx == (p_scb->hdi + 1)) + { + bta_av_cb.rs_idx = 0; + } + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_RETRY; + p_scb->q_tag = 0; + p_buf->switch_res = switch_res; + bta_av_do_disc_a2d(p_scb, (tBTA_AV_DATA *)p_buf); + } +} + +/******************************************************************************* +** +** Function bta_av_role_res +** +** Description Handle the role changed event +** +** +** Returns void +** +*******************************************************************************/ +void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + BOOLEAN initiator = FALSE; + tBTA_AV_START start; + tBTA_AV_OPEN av_open; + + APPL_TRACE_DEBUG3("bta_av_role_res q_tag:%d, wait:x%x, role:x%x", p_scb->q_tag, p_scb->wait, p_scb->role); + if (p_scb->role & BTA_AV_ROLE_START_INT) + initiator = TRUE; + + if (p_scb->q_tag == BTA_AV_Q_TAG_START) + { + if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED) + { + p_scb->role &= ~BTA_AV_ROLE_START_INT; + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + if (p_data->role_res.hci_status != HCI_SUCCESS) + { + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + /* start failed because of role switch. */ + start.chnl = p_scb->chnl; + start.status = BTA_AV_FAIL_ROLE; + start.hndl = p_scb->hndl; + start.initiator = initiator; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + } + else + { + bta_av_start_ok(p_scb, p_data); + } + } + else if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START) + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_FAILED; + } + else if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN) + { + if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_OPEN) + { + p_scb->role &= ~BTA_AV_ROLE_START_INT; + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + + if (p_data->role_res.hci_status != HCI_SUCCESS) + { + /* Open failed because of role switch. */ + bdcpy(av_open.bd_addr, p_scb->peer_addr); + av_open.chnl = p_scb->chnl; + av_open.hndl = p_scb->hndl; + start.status = BTA_AV_FAIL_ROLE; + (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *)&av_open); + } + else + { + /* Continue av open process */ + p_scb->q_info.open.switch_res = BTA_AV_RS_DONE; + bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open)); + } + } + else + { + APPL_TRACE_WARNING2 ("Unexpected role switch event: q_tag = %d wait = %d", p_scb->q_tag, p_scb->wait); + } + } + + APPL_TRACE_DEBUG2("wait:x%x, role:x%x", p_scb->wait, p_scb->role); +} + +/******************************************************************************* +** +** Function bta_av_delay_co +** +** Description Call the delay call-out function to report the delay report +** from SNK +** +** Returns void +** +*******************************************************************************/ +void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + p_scb->p_cos->delay(p_scb->hndl, p_data->str_msg.msg.delay_rpt_cmd.delay); +} + +/******************************************************************************* +** +** Function bta_av_do_disc_a2d +** +** Description Do service discovery for A2DP. +** +** Returns void +** +*******************************************************************************/ +void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + BOOLEAN ok_continue = FALSE; + tA2D_SDP_DB_PARAMS db_params; + UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, + ATTR_ID_PROTOCOL_DESC_LIST, + ATTR_ID_BT_PROFILE_DESC_LIST}; + + APPL_TRACE_DEBUG3("bta_av_do_disc_a2d use_rc: %d rs:%d, oc:%d", + p_data->api_open.use_rc, p_data->api_open.switch_res, bta_av_cb.audio_open_cnt); + + memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN)); + + switch(p_data->api_open.switch_res) + { + case BTA_AV_RS_NONE: + if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT)) + { + /* waiting for role switch result. save the api to control block */ + memcpy(&p_scb->q_info.open, &p_data->api_open, sizeof(tBTA_AV_API_OPEN)); + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN; + p_scb->q_tag = BTA_AV_Q_TAG_OPEN; + } + else + { + ok_continue = TRUE; + } + break; + + case BTA_AV_RS_FAIL: + /* report a new failure event */ + p_scb->open_status = BTA_AV_FAIL_ROLE; + bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL); + break; + + case BTA_AV_RS_OK: + p_data = (tBTA_AV_DATA *)&p_scb->q_info.open; + /* continue to open if link role is ok */ + if (bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT)) + { + ok_continue = TRUE; + } + else + { + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN; + } + break; + + case BTA_AV_RS_DONE: + ok_continue = TRUE; + break; + } + + APPL_TRACE_DEBUG3("ok_continue: %d wait:x%x, q_tag: %d", ok_continue, p_scb->wait, p_scb->q_tag); + if (!ok_continue) + return; + + /* clear the role switch bits */ + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + + if (p_scb->wait & BTA_AV_WAIT_CHECK_RC) + { + p_scb->wait &= ~BTA_AV_WAIT_CHECK_RC; + bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL); + } + + if (bta_av_cb.features & BTA_AV_FEAT_MASTER) + { + L2CA_SetDesireRole(L2CAP_ROLE_DISALLOW_SWITCH); + + if (bta_av_cb.audio_open_cnt == 1) + { + /* there's already an A2DP connection. do not allow switch */ + bta_sys_clear_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH); + } + } + /* store peer addr other parameters */ + bta_av_save_addr(p_scb, p_data->api_open.bd_addr); + p_scb->sec_mask = p_data->api_open.sec_mask; + p_scb->use_rc = p_data->api_open.use_rc; + + bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + + /* allocate discovery database */ + if (p_scb->p_disc_db == NULL) + { + p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE); + } + + /* only one A2D find service is active at a time */ + bta_av_cb.handle = p_scb->hndl; + + if(p_scb->p_disc_db) + { + /* set up parameters */ + db_params.db_len = BTA_AV_DISC_BUF_SIZE; + db_params.num_attr = 3; + db_params.p_db = p_scb->p_disc_db; + db_params.p_attrs = attr_list; + + if(A2D_FindService(UUID_SERVCLASS_AUDIO_SINK, p_scb->peer_addr, &db_params, + bta_av_a2d_sdp_cback) == A2D_SUCCESS) + { + return; + } + } + + /* when the code reaches here, either the DB is NULL + * or A2D_FindService is not successful */ + bta_av_a2d_sdp_cback(FALSE, NULL); +} + +/******************************************************************************* +** +** Function bta_av_cleanup +** +** Description cleanup AV stream control block. +** +** Returns void +** +*******************************************************************************/ +void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_CONN_CHG msg; + int xx; + UINT8 role = BTA_AV_ROLE_AD_INT; + + APPL_TRACE_DEBUG0("bta_av_cleanup"); + + /* free any buffers */ + utl_freebuf((void **) &p_scb->p_cap); + utl_freebuf((void **) &p_scb->p_disc_db); + p_scb->avdt_version = 0; + + /* initialize some control block variables */ + p_scb->open_status = BTA_AV_SUCCESS; + + /* if de-registering shut everything down */ + msg.hdr.layer_specific = p_scb->hndl; + p_scb->started = FALSE; + p_scb->cong = FALSE; + p_scb->role = role; + p_scb->cur_psc_mask = 0; + p_scb->wait = 0; + p_scb->num_disc_snks = 0; + bta_sys_stop_timer(&p_scb->timer); + if (p_scb->deregistring) + { + /* remove stream */ + for(xx=0; xx<BTA_AV_MAX_SEPS; xx++) + { + if(p_scb->seps[xx].av_handle) + AVDT_RemoveStream(p_scb->seps[xx].av_handle); + p_scb->seps[xx].av_handle = 0; + } + + bta_av_dereg_comp((tBTA_AV_DATA *) &msg); + } + else + { + /* report stream closed to main SM */ + msg.is_up = FALSE; + bdcpy(msg.peer_addr, p_scb->peer_addr); + bta_av_conn_chg((tBTA_AV_DATA *) &msg); + } +} + +/******************************************************************************* +** +** Function bta_av_free_sdb +** +** Description Free service discovery db buffer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_free_sdb(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + utl_freebuf((void **) &p_scb->p_disc_db); +} + +/******************************************************************************* +** +** Function bta_av_config_ind +** +** Description Handle a stream configuration indication from the peer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_CI_SETCONFIG setconfig; + tAVDT_SEP_INFO *p_info; + tAVDT_CFG *p_evt_cfg = &p_data->str_msg.cfg; + UINT8 psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask); + + p_scb->avdt_label = p_data->str_msg.msg.hdr.label; + memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE); + p_scb->codec_type = p_evt_cfg->codec_info[BTA_AV_CODEC_TYPE_IDX]; + bta_av_save_addr(p_scb, p_data->str_msg.bd_addr); + + /* Clear collision mask */ + p_scb->coll_mask = 0; + bta_sys_stop_timer(&bta_av_cb.acp_sig_tmr); + + /* if no codec parameters in configuration, fail */ + if ((p_evt_cfg->num_codec == 0) || + /* or the peer requests for a service we do not support */ + ((psc_mask != p_scb->cfg.psc_mask) && + (psc_mask != (p_scb->cfg.psc_mask&~AVDT_PSC_DELAY_RPT))) ) + { + setconfig.hndl = p_scb->hndl; /* we may not need this */ + setconfig.err_code = AVDT_ERR_UNSUP_CFG; + bta_av_ssm_execute(p_scb, BTA_AV_CI_SETCONFIG_FAIL_EVT, (tBTA_AV_DATA *) &setconfig); + } + else + { + p_info = &p_scb->sep_info[0]; + p_info->in_use = 0; + p_info->media_type = p_scb->media_type; + p_info->seid = p_data->str_msg.msg.config_ind.int_seid; + p_info->tsep = AVDT_TSEP_SNK; + p_scb->role |= BTA_AV_ROLE_AD_ACP; + p_scb->cur_psc_mask = p_evt_cfg->psc_mask; + if (bta_av_cb.features & BTA_AV_FEAT_RCTG) + p_scb->use_rc = TRUE; + else + p_scb->use_rc = FALSE; + + p_scb->num_seps = 1; + p_scb->sep_info_idx = 0; + APPL_TRACE_DEBUG3("bta_av_config_ind: SEID: %d use_rc: %d cur_psc_mask:0x%x", p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask); + + p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type, + p_evt_cfg->codec_info, + p_info->seid, + p_scb->peer_addr, + p_evt_cfg->num_protect, + p_evt_cfg->protect_info); + } +} + +/******************************************************************************* +** +** Function bta_av_disconnect_req +** +** Description Disconnect AVDTP connection. +** +** Returns void +** +*******************************************************************************/ +void bta_av_disconnect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + APPL_TRACE_DEBUG1("bta_av_disconnect_req conn_lcb: 0x%x", bta_av_cb.conn_lcb); + + bta_sys_stop_timer(&bta_av_cb.sig_tmr); + bta_sys_stop_timer(&p_scb->timer); + if(bta_av_cb.conn_lcb) + { + p_rcb = bta_av_get_rcb_by_shdl((UINT8)(p_scb->hdi + 1)); + if (p_rcb) + bta_av_del_rc(p_rcb); + AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]); + } + else + { + bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function bta_av_security_req +** +** Description Send an AVDTP security request. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) + { + AVDT_SecurityReq(p_scb->avdt_handle, p_data->api_protect_req.p_data, + p_data->api_protect_req.len); + } +} + +/******************************************************************************* +** +** Function bta_av_security_rsp +** +** Description Send an AVDTP security response. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) + { + AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->api_protect_rsp.error_code, + p_data->api_protect_rsp.p_data, p_data->api_protect_rsp.len); + } + else + { + AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, + NULL, 0); + } +} + +/******************************************************************************* +** +** Function bta_av_setconfig_rsp +** +** Description setconfig is OK +** +** Returns void +** +*******************************************************************************/ +void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 num = p_data->ci_setconfig.num_seid + 1; + UINT8 *p_seid = p_data->ci_setconfig.p_seid; + int i; + + /* we like this codec_type. find the sep_idx */ + bta_av_adjust_seps_idx(p_scb); + APPL_TRACE_DEBUG2("bta_av_setconfig_rsp: sep_idx: %d cur_psc_mask:0x%x", p_scb->sep_idx, p_scb->cur_psc_mask); + AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code, + p_data->ci_setconfig.category); + + bta_sys_stop_timer(&bta_av_cb.sig_tmr); + + if(p_data->ci_setconfig.err_code == AVDT_SUCCESS) + { + p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON; + if(p_data->ci_setconfig.recfg_needed) + p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT; + APPL_TRACE_ERROR3("bta_av_setconfig_rsp recfg_needed:%d role:x%x num:%d", + p_data->ci_setconfig.recfg_needed, p_scb->role, num); + /* callout module tells BTA the number of "good" SEPs and their SEIDs. + * getcap on these SEID */ + p_scb->num_seps = num; + + if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT) + p_scb->avdt_version = AVDT_VERSION_SYNC; + + + if (p_scb->codec_type == BTA_AV_CODEC_SBC || num > 1) + { + /* if SBC is used by the SNK as INT, discover req is not sent in bta_av_config_ind. + * call disc_res now */ + p_scb->p_cos->disc_res(p_scb->hndl, num, num, p_scb->peer_addr); + } + else + { + /* we do not know the peer device and it is using non-SBC codec + * we need to know all the SEPs on SNK */ + bta_av_discover_req(p_scb, NULL); + return; + } + + for (i = 1; i < num; i++) + { + APPL_TRACE_DEBUG2("sep_info[%d] SEID: %d", i, p_seid[i-1]); + /* initialize the sep_info[] to get capabilities */ + p_scb->sep_info[i].in_use = FALSE; + p_scb->sep_info[i].tsep = AVDT_TSEP_SNK; + p_scb->sep_info[i].media_type = p_scb->media_type; + p_scb->sep_info[i].seid = p_seid[i-1]; + } + bta_av_next_getcap(p_scb, p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_str_opened +** +** Description Stream opened OK (incoming/outgoing). +** +** Returns void +** +*******************************************************************************/ +void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_CONN_CHG msg; + tBTA_AV_OPEN open; + UINT8 *p; + UINT16 mtu; + + msg.hdr.layer_specific = p_scb->hndl; + msg.is_up = TRUE; + bdcpy(msg.peer_addr, p_scb->peer_addr); + p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle); + bta_av_conn_chg((tBTA_AV_DATA *) &msg); + /* set the congestion flag, so AV would not send media packets by accident */ + p_scb->cong = TRUE; + + + p_scb->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE; + mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu); + APPL_TRACE_DEBUG3("bta_av_str_opened l2c_cid: 0x%x stream_mtu: %d mtu: %d", + p_scb->l2c_cid, p_scb->stream_mtu, mtu); + if(mtu == 0 || mtu > p_scb->stream_mtu) + mtu = p_scb->stream_mtu; + + /* Set the media channel as medium priority */ + L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM); + L2CA_SetChnlFlushability (p_scb->l2c_cid, TRUE); + + bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO)); + + p_scb->l2c_bufs = 0; + p_scb->p_cos->open(p_scb->hndl, + p_scb->codec_type, p_scb->cfg.codec_info, mtu); + + { + /* TODO check if other audio channel is open. + * If yes, check if reconfig is needed + * Rigt now we do not do this kind of checking. + * BTA-AV is INT for 2nd audio connection. + * The application needs to make sure the current codec_info is proper. + * If one audio connection is open and another SNK attempts to connect to AV, + * the connection will be rejected. + */ + /* check if other audio channel is started. If yes, start */ + bdcpy(open.bd_addr, p_scb->peer_addr); + open.chnl = p_scb->chnl; + open.hndl = p_scb->hndl; + open.status = BTA_AV_SUCCESS; + open.starting = bta_av_chk_start(p_scb); + open.edr = 0; + if( NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr))) + { + if(HCI_EDR_ACL_2MPS_SUPPORTED(p)) + open.edr |= BTA_AV_EDR_2MBPS; + if(HCI_EDR_ACL_3MPS_SUPPORTED(p)) + open.edr |= BTA_AV_EDR_3MBPS; + } +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr); +#endif + (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open); + if(open.starting) + { + bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL); + } + } +} + +/******************************************************************************* +** +** Function bta_av_security_ind +** +** Description Handle an AVDTP security indication. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_PROTECT_REQ protect_req; + + p_scb->avdt_label = p_data->str_msg.msg.hdr.label; + + if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) + { + protect_req.chnl = p_scb->chnl; + protect_req.hndl = p_scb->hndl; + /* + APPL_TRACE_EVENT1("sec ind handle: x%x", protect_req.hndl); + */ + protect_req.p_data = p_data->str_msg.msg.security_ind.p_data; + protect_req.len = p_data->str_msg.msg.security_ind.len; + + (*bta_av_cb.p_cback)(BTA_AV_PROTECT_REQ_EVT, (tBTA_AV *) &protect_req); + } + /* app doesn't support security indication; respond with failure */ + else + { + AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL, 0); + } +} + +/******************************************************************************* +** +** Function bta_av_security_cfm +** +** Description Handle an AVDTP security confirm. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_PROTECT_RSP protect_rsp; + + if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) + { + protect_rsp.chnl = p_scb->chnl; + protect_rsp.hndl = p_scb->hndl; + protect_rsp.p_data = p_data->str_msg.msg.security_cfm.p_data; + protect_rsp.len = p_data->str_msg.msg.security_cfm.len; + protect_rsp.err_code= p_data->str_msg.msg.hdr.err_code; + + (*bta_av_cb.p_cback)(BTA_AV_PROTECT_RSP_EVT, (tBTA_AV *) &protect_rsp); + } +} + +/******************************************************************************* +** +** Function bta_av_do_close +** +** Description Close stream. +** +** Returns void +** +*******************************************************************************/ +void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + /* stop stream if started */ + if (p_scb->co_started) + { + bta_av_str_stopped(p_scb, NULL); + } + bta_sys_stop_timer(&bta_av_cb.sig_tmr); + + /* close stream */ + p_scb->started = FALSE; + + /* drop the buffers queued in L2CAP */ + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + + AVDT_CloseReq(p_scb->avdt_handle); + /* just in case that the link is congested, link is flow controled by peer or + * for whatever reason the the close request can not be sent in time. + * when this timer expires, AVDT_DisconnectReq will be called to disconnect the link + */ + bta_sys_start_timer(&p_scb->timer, + (UINT16)BTA_AV_API_CLOSE_EVT, + BTA_AV_CLOSE_REQ_TIME_VAL); + +} + +/******************************************************************************* +** +** Function bta_av_connect_req +** +** Description Connect AVDTP connection. +** +** Returns void +** +*******************************************************************************/ +void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + utl_freebuf((void **) &p_scb->p_disc_db); + + if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) + { + /* SNK initiated L2C connection while SRC was doing SDP. */ + /* Wait until timeout to check if SNK starts signalling. */ + APPL_TRACE_EVENT1("bta_av_connect_req: coll_mask = 0x%2X", p_scb->coll_mask); + return; + } + + AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]); +} + +/******************************************************************************* +** +** Function bta_av_sdp_failed +** +** Description Service discovery failed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + if (!p_scb->open_status) + p_scb->open_status = BTA_AV_FAIL_SDP; + + utl_freebuf((void **) &p_scb->p_disc_db); + bta_av_str_closed(p_scb, p_data); +} + +/******************************************************************************* +** +** Function bta_av_disc_results +** +** Description Handle the AVDTP discover results. Search through the +** results and find the first available stream, and get +** its capabilities. +** +** Returns void +** +*******************************************************************************/ +void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 num_snks = 0, i; + + /* store number of stream endpoints returned */ + p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps; + + for (i = 0; i < p_scb->num_seps; i++) + { + /* steam not in use, is a sink, and is audio */ + if ((p_scb->sep_info[i].in_use == FALSE) && + (p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && + (p_scb->sep_info[i].media_type == p_scb->media_type)) + { + num_snks++; + } + } + + p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, p_scb->peer_addr); + p_scb->num_disc_snks = num_snks; + + /* if we got any */ + if (p_scb->num_seps > 0) + { + /* initialize index into discovery results */ + p_scb->sep_info_idx = 0; + + /* get the capabilities of the first available stream */ + bta_av_next_getcap(p_scb, p_data); + } + /* else we got discover response but with no streams; we're done */ + else + { + bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_disc_res_as_acp +** +** Description Handle the AVDTP discover results. Search through the +** results and find the first available stream, and get +** its capabilities. +** +** Returns void +** +*******************************************************************************/ +void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 num_snks = 0, i; + + /* store number of stream endpoints returned */ + p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps; + + + + for (i = 0; i < p_scb->num_seps; i++) + { + /* steam is a sink, and is audio */ + if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && + (p_scb->sep_info[i].media_type == p_scb->media_type)) + { + p_scb->sep_info[i].in_use = FALSE; + num_snks++; + } + } + + p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, p_scb->peer_addr); + p_scb->num_disc_snks = num_snks; + + /* if we got any */ + if (p_scb->num_seps > 0) + { + /* initialize index into discovery results */ + p_scb->sep_info_idx = 0; + + /* get the capabilities of the first available stream */ + bta_av_next_getcap(p_scb, p_data); + } + /* else we got discover response but with no streams; we're done */ + else + { + bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_save_caps +** +** Description report the SNK SEP capabilities to application +** +** Returns void +** +*******************************************************************************/ +void bta_av_save_caps(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tAVDT_CFG cfg; + tAVDT_SEP_INFO *p_info = &p_scb->sep_info[p_scb->sep_info_idx]; + UINT8 old_wait = p_scb->wait; + BOOLEAN getcap_done = FALSE; + + APPL_TRACE_DEBUG3("bta_av_save_caps num_seps:%d sep_info_idx:%d wait:x%x", + p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait); + memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG)); + /* let application know the capability of the SNK */ + p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info[BTA_AV_CODEC_TYPE_IDX], + cfg.codec_info, &p_scb->sep_info_idx, p_info->seid, + &cfg.num_protect, cfg.protect_info); + + p_scb->sep_info_idx++; + if(p_scb->num_seps > p_scb->sep_info_idx) + { + /* Some devices have seps at the end of the discover list, which is not */ + /* matching media type(video not audio). */ + /* In this case, we are done with getcap without sending another */ + /* request to AVDT. */ + if (!bta_av_next_getcap(p_scb, p_data)) + getcap_done = TRUE; + } + else + getcap_done = TRUE; + + if (getcap_done) + { + /* we are done getting capabilities. restore the p_cb->sep_info_idx */ + p_scb->sep_info_idx = 0; + p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON|BTA_AV_WAIT_ACP_CAPS_STARTED); + if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED) + { + bta_av_start_ok (p_scb, NULL); + } + } +} + +/******************************************************************************* +** +** Function bta_av_set_use_rc +** +** Description set to use AVRC for this stream control block. +** +** Returns void +** +*******************************************************************************/ +void bta_av_set_use_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + p_scb->use_rc = TRUE; +} + +/******************************************************************************* +** +** Function bta_av_cco_close +** +** Description call close call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT16 mtu; + mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU); + + p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu); +} + +/******************************************************************************* +** +** Function bta_av_open_failed +** +** Description Failed to open an AVDT stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + p_scb->open_status = BTA_AV_FAIL_STREAM; + bta_av_cco_close(p_scb, p_data); + AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]); +} + +/******************************************************************************* +** +** Function bta_av_getcap_results +** +** Description Handle the AVDTP get capabilities results. Check the codec +** type and see if it matches ours. If it does not, get the +** capabilities of the next stream, if any. +** +** Returns void +** +*******************************************************************************/ +void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tAVDT_CFG cfg; + UINT8 media_type; + tAVDT_SEP_INFO *p_info = &p_scb->sep_info[p_scb->sep_info_idx]; + + memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG)); + cfg.num_codec = 1; + cfg.num_protect = p_scb->p_cap->num_protect; + memcpy(cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE); + memcpy(cfg.protect_info, p_scb->p_cap->protect_info, AVDT_PROTECT_SIZE); + media_type = p_scb->p_cap->codec_info[BTA_AV_MEDIA_TYPE_IDX] >> 4; + + APPL_TRACE_DEBUG1("num_codec %d", p_scb->p_cap->num_codec); + APPL_TRACE_DEBUG2("media type x%x, x%x", media_type, p_scb->media_type); +#if AVDT_MULTIPLEXING == TRUE + APPL_TRACE_DEBUG2("mux x%x, x%x", cfg.mux_mask, p_scb->p_cap->mux_mask); +#endif + + /* if codec present and we get a codec configuration */ + if ((p_scb->p_cap->num_codec != 0) && + (media_type == p_scb->media_type) && + (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX], + cfg.codec_info, &p_scb->sep_info_idx, p_info->seid, + &cfg.num_protect, cfg.protect_info) == 0)) + { +#if AVDT_MULTIPLEXING == TRUE + cfg.mux_mask &= p_scb->p_cap->mux_mask; + APPL_TRACE_DEBUG1("mux_mask used x%x", cfg.mux_mask); +#endif + /* save copy of codec type and configuration */ + p_scb->codec_type = cfg.codec_info[BTA_AV_CODEC_TYPE_IDX]; + memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG)); + bta_av_adjust_seps_idx(p_scb); + /* use only the services peer supports */ + cfg.psc_mask &= p_scb->p_cap->psc_mask; + p_scb->cur_psc_mask = cfg.psc_mask; + + /* open the stream */ + AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr, + p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg); + + if (!bta_av_is_rcfg_sst(p_scb)) + { + /* free capabilities buffer */ + utl_freebuf((void **) &p_scb->p_cap); + } + } + else + { + /* try the next stream, if any */ + p_scb->sep_info_idx++; + bta_av_next_getcap(p_scb, p_data); + } + +} + +/******************************************************************************* +** +** Function bta_av_setconfig_rej +** +** Description Send AVDTP set config reject. +** +** Returns void +** +*******************************************************************************/ +void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_REJECT reject; + + APPL_TRACE_DEBUG0("bta_av_setconfig_rej"); + AVDT_ConfigRsp(p_data->str_msg.handle, p_data->str_msg.msg.hdr.label, AVDT_ERR_BAD_STATE, 0); + bdcpy(reject.bd_addr, p_data->str_msg.bd_addr); + reject.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject); +} + +/******************************************************************************* +** +** Function bta_av_discover_req +** +** Description Send an AVDTP discover request to the peer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_discover_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + /* send avdtp discover request */ + + AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]); +} + +/******************************************************************************* +** +** Function bta_av_conn_failed +** +** Description AVDTP connection failed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_conn_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + p_scb->open_status = BTA_AV_FAIL_STREAM; + bta_av_str_closed(p_scb, p_data); +} + +/******************************************************************************* +** +** Function bta_av_do_start +** +** Description Start stream. +** +** Returns void +** +*******************************************************************************/ +void bta_av_do_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + UINT8 cur_role; + + APPL_TRACE_DEBUG3("bta_av_do_start sco_occupied:%d, role:x%x, started:%d", bta_av_cb.sco_occupied, p_scb->role, p_scb->started); + if (bta_av_cb.sco_occupied) + { + bta_av_start_failed(p_scb, p_data); + return; + } + + /* disallow role switch during streaming, only if we are the master role + * i.e. allow role switch, if we are slave. + * It would not hurt us, if the peer device wants us to be master */ + if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) && + (cur_role == BTM_ROLE_MASTER) ) + { + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + } + + bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr); + + if ((p_scb->started == FALSE) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0)) + { + p_scb->role |= BTA_AV_ROLE_START_INT; + bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + + AVDT_StartReq(&p_scb->avdt_handle, 1); + } + else + { + bta_av_start_ok(p_scb, NULL); + } + APPL_TRACE_DEBUG2("started %d role:x%x", p_scb->started, p_scb->role); +} + +/******************************************************************************* +** +** Function bta_av_str_stopped +** +** Description Stream stopped. +** +** Returns void +** +*******************************************************************************/ +void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_SUSPEND suspend_rsp; + UINT8 start = p_scb->started; + BOOLEAN sus_evt = TRUE; + BT_HDR *p_buf; + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + + APPL_TRACE_ERROR2("bta_av_str_stopped:audio_open_cnt=%d, p_data %x", + bta_av_cb.audio_open_cnt, p_data); + + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1) + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr); + + if(p_scb->co_started) + { + bta_av_stream_chg(p_scb, FALSE); + p_scb->co_started = FALSE; + + p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type); + L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO); + } + + /* if q_info.a2d is not empty, drop it now */ + if(BTA_AV_CHNL_AUDIO == p_scb->chnl) + { + while((p_buf = (BT_HDR*)GKI_dequeue (&p_scb->q_info.a2d)) != NULL) + GKI_freebuf(p_buf); + + /* drop the audio buffers queued in L2CAP */ + if(p_data && p_data->api_stop.flush) + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + } + + suspend_rsp.chnl = p_scb->chnl; + suspend_rsp.hndl = p_scb->hndl; + + if (p_data && p_data->api_stop.suspend) + { + APPL_TRACE_DEBUG2("suspending: %d, sup:%d", start, p_scb->suspend_sup); + if ((start) && (p_scb->suspend_sup)) + { + sus_evt = FALSE; + p_scb->l2c_bufs = 0; + AVDT_SuspendReq(&p_scb->avdt_handle, 1); + } + + if(sus_evt) + { + suspend_rsp.status = BTA_AV_SUCCESS; + suspend_rsp.initiator = TRUE; + (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp); + } + } + else + { + suspend_rsp.status = BTA_AV_SUCCESS; + suspend_rsp.initiator = TRUE; + APPL_TRACE_EVENT1("bta_av_str_stopped status %d", suspend_rsp.status); + + (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV *) &suspend_rsp); + } +} + +/******************************************************************************* +** +** Function bta_av_reconfig +** +** Description process the reconfigure request. +** save the parameter in control block and +** suspend, reconfigure or close the stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_reconfig (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tAVDT_CFG *p_cfg; + tBTA_AV_API_STOP stop; + tBTA_AV_RECONFIG evt; + tBTA_AV_API_RCFG *p_rcfg = &p_data->api_reconfig; + + APPL_TRACE_DEBUG4("bta_av_reconfig r:%d, s:%d idx: %d (o:%d)", + p_scb->recfg_sup, p_scb->suspend_sup, + p_scb->rcfg_idx, p_scb->sep_info_idx); + + p_scb->num_recfg = 0; + /* store the new configuration in control block */ + if (p_scb->p_cap == NULL) + { + p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG)); + } + if((p_cfg = p_scb->p_cap) == NULL) + { + /* report failure */ + evt.status = BTA_AV_FAIL_RESOURCES; + evt.chnl = p_scb->chnl; + evt.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + + /* this event is not possible in this state. + * use it to bring the SSM back to open state */ + bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_OK_EVT, NULL); + return; + } + + /*if(bta_av_cb.features & BTA_AV_FEAT_RCCT)*/ + bta_sys_stop_timer(&p_scb->timer); + + memcpy(p_cfg, &p_scb->cfg, sizeof(tAVDT_CFG)); + p_cfg->num_protect = p_rcfg->num_protect; + memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE); + memcpy(p_cfg->protect_info, p_rcfg->p_protect_info, p_rcfg->num_protect); + p_scb->rcfg_idx = p_rcfg->sep_info_idx; + p_scb->p_cap->psc_mask = p_scb->cur_psc_mask; + + /* if the requested index differs from the current one, we can only close/open */ + if ((p_scb->rcfg_idx == p_scb->sep_info_idx) && + (p_rcfg->suspend)&& (p_scb->recfg_sup) && (p_scb->suspend_sup)) + { + if(p_scb->started) + { + stop.flush = FALSE; + stop.suspend = TRUE; + bta_av_str_stopped(p_scb, (tBTA_AV_DATA *)&stop); + } + else + { + APPL_TRACE_DEBUG0("Reconfig"); + AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap); + p_scb->p_cap->psc_mask = p_scb->cur_psc_mask; + } + } + else + { + /* close the stream */ + APPL_TRACE_DEBUG1("close/open num_protect: %d", p_cfg->num_protect); + if(p_scb->started) + bta_av_str_stopped(p_scb, NULL); + p_scb->started = FALSE; + + /* drop the buffers queued in L2CAP */ + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + + AVDT_CloseReq(p_scb->avdt_handle); + + } +} + +/******************************************************************************* +** +** Function bta_av_data_path +** +** Description Handle stream data path. +** +** Returns void +** +*******************************************************************************/ +void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + BT_HDR *p_buf; + UINT32 data_len; + UINT32 timestamp; + BOOLEAN new_buf = FALSE; + UINT8 m_pt = 0x60 | p_scb->codec_type; + + if (!p_scb->cong) + { + /* + APPL_TRACE_ERROR1("q: %d", p_scb->l2c_bufs); + */ + //Always get the current number of bufs que'd up + p_scb->l2c_bufs = (UINT8)L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET); + + p_buf = (BT_HDR *)GKI_dequeue (&p_scb->q_info.a2d); + if(p_buf) + { + /* use q_info.a2d data, read the timestamp */ + timestamp = *(UINT32 *)(p_buf + 1); + } + else + { + new_buf = TRUE; + /* q_info.a2d empty, call co_data, dup data to other channels */ + p_buf = (BT_HDR *)p_scb->p_cos->data(p_scb->codec_type, &data_len, + ×tamp); + + if (p_buf) + { + /* use the offset area for the time stamp */ + *(UINT32 *)(p_buf + 1) = timestamp; + + /* dup the data to other channels */ + bta_av_dup_audio_buf(p_scb, p_buf); + } + } + + if(p_buf) + { + if(p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM)) + { + /* there's a buffer, just queue it to L2CAP */ + /* There's no need to increment it here, it is always read from L2CAP see above */ + /* p_scb->l2c_bufs++; */ + /* + APPL_TRACE_ERROR1("qw: %d", p_scb->l2c_bufs); + */ + AVDT_WriteReq(p_scb->avdt_handle, p_buf, timestamp, m_pt); + p_scb->cong = TRUE; + } + else + { + /* there's a buffer, but L2CAP does not seem to be moving data */ + if(new_buf) + { + /* just got this buffer from co_data, + * put it in queue */ + GKI_enqueue(&p_scb->q_info.a2d, p_buf); + } + else + { + /* just dequeue it from the q_info.a2d */ + if(p_scb->q_info.a2d.count < 3) + { + /* put it back to the queue */ + GKI_enqueue_head (&p_scb->q_info.a2d, p_buf); + } + else + { + /* too many buffers in q_info.a2d, drop it. */ + bta_av_co_audio_drop(p_scb->hndl); + GKI_freebuf(p_buf); + } + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_start_ok +** +** Description Stream started. +** +** Returns void +** +*******************************************************************************/ +void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_START start; + tBTA_AV_API_STOP stop; + BOOLEAN initiator = FALSE; + BOOLEAN suspend = FALSE; + UINT16 flush_to; + UINT8 new_role = p_scb->role; + BT_HDR hdr; + + APPL_TRACE_DEBUG2("bta_av_start_ok wait:x%x, role:x%x", p_scb->wait, p_scb->role); + + p_scb->started = TRUE; + if (p_scb->sco_suspend) + { + p_scb->sco_suspend = FALSE; + } + + if (new_role & BTA_AV_ROLE_START_INT) + initiator = TRUE; + + if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED) + { + /* role switch has failed */ + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_FAILED; + p_data = (tBTA_AV_DATA *)&hdr; + hdr.offset = BTA_AV_RS_FAIL; + } + APPL_TRACE_DEBUG1("wait:x%x", p_scb->wait); + + if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE)) + { + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + if (p_data->hdr.offset == BTA_AV_RS_FAIL) + { + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + start.chnl = p_scb->chnl; + start.status = BTA_AV_FAIL_ROLE; + start.hndl = p_scb->hndl; + start.initiator = initiator; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + return; + } + } + + if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT)) + p_scb->q_tag = BTA_AV_Q_TAG_START; + else + { + /* The wait flag may be set here while we are already master on the link */ + /* this could happen if a role switch complete event occurred during reconfig */ + /* if we are now master on the link, there is no need to wait for the role switch, */ + /* complete anymore so we can clear the wait for role switch flag */ + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + } + + if (p_scb->wait & (BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START)) + { + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_STARTED; + p_scb->q_tag = BTA_AV_Q_TAG_START; + } + + if (p_scb->wait & BTA_AV_WAIT_ACP_CAPS_ON) + { + p_scb->wait |= BTA_AV_WAIT_ACP_CAPS_STARTED; + } + + if (p_scb->wait) + { + APPL_TRACE_DEBUG2("wait:x%x q_tag:%d- not started", p_scb->wait, p_scb->q_tag); + return; + } + + /* tell role manager to check M/S role */ + bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + + bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + + if(p_scb->media_type == AVDT_MEDIA_AUDIO) + { + /* in normal logic, conns should be bta_av_cb.audio_count - 1, + * However, bta_av_stream_chg is not called to increase bta_av_cb.audio_count yet. + * If the code were to be re-arranged for some reasons, this number may need to be changed + */ + p_scb->co_started = bta_av_cb.audio_open_cnt; + flush_to = p_bta_av_cfg->p_audio_flush_to[p_scb->co_started - 1]; + } + else + { + flush_to = p_bta_av_cfg->video_flush_to; + } + L2CA_SetFlushTimeout(p_scb->peer_addr, flush_to ); + + /* clear the congestion flag */ + p_scb->cong = FALSE; + + if (new_role & BTA_AV_ROLE_START_INT) + { + new_role &= ~BTA_AV_ROLE_START_INT; + } + else if ((new_role & BTA_AV_ROLE_AD_ACP) && (new_role & BTA_AV_ROLE_SUSPEND_OPT)) + { + suspend = TRUE; + } + + if (!suspend) + { + p_scb->q_tag = BTA_AV_Q_TAG_STREAM; + bta_av_stream_chg(p_scb, TRUE); + } + + { + p_scb->role = new_role; + p_scb->role &= ~BTA_AV_ROLE_AD_ACP; + p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT; + + p_scb->p_cos->start(p_scb->hndl, p_scb->codec_type); + p_scb->co_started = TRUE; + + APPL_TRACE_DEBUG3("bta_av_start_ok suspending: %d, role:x%x, init %d", + suspend, p_scb->role, initiator); + + start.suspending = suspend; + start.initiator = initiator; + start.chnl = p_scb->chnl; + start.status = BTA_AV_SUCCESS; + start.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + + if(suspend) + { + p_scb->role |= BTA_AV_ROLE_SUSPEND; + p_scb->cong = TRUE; /* do not allow the media data to go through */ + /* do not duplicate the media packets to this channel */ + p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type); + p_scb->co_started = FALSE; + stop.flush = FALSE; + stop.suspend = TRUE; + bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA *)&stop); + } + } +} + +/******************************************************************************* +** +** Function bta_av_start_failed +** +** Description Stream start failed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_start_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_START start; + + if(p_scb->started == FALSE && p_scb->co_started == FALSE) + { + /* if start failed, clear role */ + p_scb->role &= ~BTA_AV_ROLE_START_INT; + + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + start.chnl = p_scb->chnl; + start.status = BTA_AV_FAIL; + start.initiator = TRUE; + start.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + } + + bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_SNIFF_MODE|HCI_ENABLE_MASTER_SLAVE_SWITCH), p_scb->peer_addr); + p_scb->sco_suspend = FALSE; +} + +/******************************************************************************* +** +** Function bta_av_str_closed +** +** Description Stream closed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV data; + tBTA_AV_EVT event; + UINT16 mtu; + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + + if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1) + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr); + if (bta_av_cb.audio_open_cnt <= 1) + { + /* last connection - restore the allow switch flag */ + L2CA_SetDesireRole(L2CAP_ROLE_ALLOW_SWITCH); + } + + if (p_scb->open_status) + { + /* must be failure when opening the stream */ + bdcpy(data.open.bd_addr, p_scb->peer_addr); + data.open.status = p_scb->open_status; + data.open.chnl = p_scb->chnl; + data.open.hndl = p_scb->hndl; + event = BTA_AV_OPEN_EVT; + p_scb->open_status = BTA_AV_SUCCESS; + + bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + bta_av_cleanup(p_scb, p_data); + (*bta_av_cb.p_cback)(event, &data); + } + else + { + /* do stop if we were started */ + if (p_scb->co_started) + { + bta_av_str_stopped(p_scb, NULL); + } + + /* Update common mtu shared by remaining connectons */ + mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU); + + { + p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu); + data.close.chnl = p_scb->chnl; + data.close.hndl = p_scb->hndl; + event = BTA_AV_CLOSE_EVT; + + bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + bta_av_cleanup(p_scb, p_data); + (*bta_av_cb.p_cback)(event, &data); + } + } +} + +/******************************************************************************* +** +** Function bta_av_clr_cong +** +** Description Clear stream congestion flag. +** +** Returns void +** +*******************************************************************************/ +void bta_av_clr_cong (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + if(p_scb->co_started) + p_scb->cong = FALSE; +} + +/******************************************************************************* +** +** Function bta_av_suspend_cfm +** +** Description process the suspend response +** +** Returns void +** +*******************************************************************************/ +void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_SUSPEND suspend_rsp; + UINT8 err_code = p_data->str_msg.msg.hdr.err_code; + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + + APPL_TRACE_DEBUG2 ("bta_av_suspend_cfm:audio_open_cnt = %d, err_code = %d", + bta_av_cb.audio_open_cnt, err_code); + + suspend_rsp.status = BTA_AV_SUCCESS; + if(err_code) + { + p_scb->suspend_sup = FALSE; + suspend_rsp.status = BTA_AV_FAIL; + + APPL_TRACE_ERROR0 ("bta_av_suspend_cfm: suspend failed, closing connection"); + + /* SUSPEND failed. Close connection. */ + bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL); + } + else + { + /* only set started to FALSE when suspend is successful */ + p_scb->started = FALSE; + } + + if(p_scb->role & BTA_AV_ROLE_SUSPEND) + { + p_scb->role &= ~BTA_AV_ROLE_SUSPEND; + p_scb->cong = FALSE; + } + + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1) + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr); + + /* in case that we received suspend_ind, we may need to call co_stop here */ + if(p_scb->co_started) + { + bta_av_stream_chg(p_scb, FALSE); + + { + p_scb->co_started = FALSE; + p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type); + } + L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO); + } + + { + suspend_rsp.chnl = p_scb->chnl; + suspend_rsp.hndl = p_scb->hndl; + suspend_rsp.initiator = p_data->str_msg.initiator; + (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp); + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_str_ok +** +** Description report reconfigure successful +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_str_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RECONFIG evt; + + p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle); + APPL_TRACE_DEBUG1("bta_av_rcfg_str_ok: l2c_cid: %d", p_scb->l2c_cid); + + /* rc listen */ + bta_av_st_rc_timer(p_scb, NULL); + utl_freebuf((void **)&p_scb->p_cap); + + /* No need to keep the role bits once reconfig is done. */ + p_scb->role &= ~BTA_AV_ROLE_AD_ACP; + p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT; + p_scb->role &= ~BTA_AV_ROLE_START_INT; + + { + /* reconfigure success */ + evt.status = BTA_AV_SUCCESS; + evt.chnl = p_scb->chnl; + evt.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_failed +** +** Description process reconfigure failed +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RECONFIG evt; + + APPL_TRACE_DEBUG2("bta_av_rcfg_failed num_recfg: %d, conn_lcb:0x%x", + p_scb->num_recfg, bta_av_cb.conn_lcb); + if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) + { + bta_av_cco_close(p_scb, p_data); + /* report failure */ + evt.status = BTA_AV_FAIL_STREAM; + evt.chnl = p_scb->chnl; + evt.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + /* go to closing state */ + bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL); + } + else + { + /* open failed. try again */ + p_scb->num_recfg++; + if(bta_av_cb.conn_lcb) + { + AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]); + } + else + { + bta_av_connect_req(p_scb, NULL); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_connect +** +** Description stream closed. reconnect the stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_connect (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + p_scb->cong = FALSE; + p_scb->num_recfg++; + APPL_TRACE_DEBUG1("bta_av_rcfg_connect num_recfg: %d", p_scb->num_recfg); + if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) + { + /* let bta_av_rcfg_failed report fail */ + bta_av_rcfg_failed(p_scb, NULL); + } + else + AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]); +} + +/******************************************************************************* +** +** Function bta_av_rcfg_discntd +** +** Description AVDT disconnected. reconnect the stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_discntd (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RECONFIG evt; + + APPL_TRACE_DEBUG1("bta_av_rcfg_discntd num_recfg: %d", p_scb->num_recfg); + p_scb->num_recfg++; + if(p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) + { + /* report failure */ + evt.status = BTA_AV_FAIL_STREAM; + evt.chnl = p_scb->chnl; + evt.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + /* report close event & go to init state */ + bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL); + } + else + AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]); +} + +/******************************************************************************* +** +** Function bta_av_suspend_cont +** +** Description received the suspend response. +** continue to reconfigure the stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 err_code = p_data->str_msg.msg.hdr.err_code; + tBTA_AV_RECONFIG evt; + + p_scb->started = FALSE; + p_scb->cong = FALSE; + if(err_code) + { + if(AVDT_ERR_CONNECT == err_code) + { + /* report failure */ + evt.status = BTA_AV_FAIL; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL); + } + else + { + APPL_TRACE_ERROR0("suspend rejected, try close"); + p_scb->suspend_sup = FALSE; + + /* drop the buffers queued in L2CAP */ + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + + AVDT_CloseReq(p_scb->avdt_handle); + } + } + else + { + APPL_TRACE_DEBUG0("bta_av_suspend_cont calling AVDT_ReconfigReq"); + /* reconfig the stream */ + + AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap); + p_scb->p_cap->psc_mask = p_scb->cur_psc_mask; + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_cfm +** +** Description if reconfigure is successful, report the event +** otherwise, close the stream. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 err_code = p_data->str_msg.msg.hdr.err_code; + + /* + APPL_TRACE_DEBUG0("bta_av_rcfg_cfm"); + */ + if(err_code) + { + APPL_TRACE_ERROR0("reconfig rejected, try close"); + p_scb->recfg_sup = FALSE; + /* started flag is FALSE when reconfigure command is sent */ + /* drop the buffers queued in L2CAP */ + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + AVDT_CloseReq(p_scb->avdt_handle); + } + else + { + /* take the SSM back to OPEN state */ + bta_av_ssm_execute(p_scb, BTA_AV_STR_OPEN_OK_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_open +** +** Description AVDT is connected. open the stream with the new configuration +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + APPL_TRACE_DEBUG1("bta_av_rcfg_open, num_disc_snks = %d", p_scb->num_disc_snks); + + if (p_scb->num_disc_snks == 0) + { + /* Need to update call-out module so that it will be ready for discover */ + p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type); + + /* send avdtp discover request */ + AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]); + } + else + { + p_scb->codec_type = p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX]; + memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE); + /* we may choose to use a different SEP at reconfig. + * adjust the sep_idx now */ + bta_av_adjust_seps_idx(p_scb); + + /* open the stream with the new config */ + p_scb->sep_info_idx = p_scb->rcfg_idx; + AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr, + p_scb->sep_info[p_scb->sep_info_idx].seid, p_scb->p_cap); + } + +} + +/******************************************************************************* +** +** Function bta_av_security_rej +** +** Description Send an AVDTP security reject. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_BAD_STATE, + NULL, 0); +} + +/******************************************************************************* +** +** Function bta_av_chk_2nd_start +** +** Description check if this is 2nd stream and if it needs to be started. +** This function needs to be kept very similar to bta_av_chk_start +** +** Returns void +** +*******************************************************************************/ +void bta_av_chk_2nd_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_SCB *p_scbi; + int i; + BOOLEAN new_started = FALSE; + + + if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2)) + { + /* more than one audio channel is connected */ + if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT)) + { + /* this channel does not need to be reconfigured. + * if there is other channel streaming, start the stream now */ + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + p_scbi = bta_av_cb.p_scb[i]; + if(p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) + { + if (!new_started) + { + /* start the new stream */ + new_started = TRUE; + bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL); + } + /* may need to update the flush timeout of this already started stream */ + if (p_scbi->co_started != bta_av_cb.audio_open_cnt) + { + p_scbi->co_started = bta_av_cb.audio_open_cnt; + L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] ); + } + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_open_rc +** +** Description Send a message to main SM to open RC channel. +** +** Returns void +** +*******************************************************************************/ +void bta_av_open_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_START start; + + APPL_TRACE_DEBUG3("bta_av_open_rc use_rc: %d, wait: x%x role:x%x", p_scb->use_rc, p_scb->wait, p_scb->role); + if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) && (p_scb->q_tag == BTA_AV_Q_TAG_START)) + { + /* waiting for role switch for some reason & the timer expires */ + if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT)) + { + APPL_TRACE_ERROR0 ("failed to start streaming for role management reasons!!"); + bta_sys_stop_timer(&p_scb->timer); + start.chnl = p_scb->chnl; + start.status = BTA_AV_FAIL_ROLE; + start.initiator = TRUE; + start.hndl = p_scb->hndl; + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + bta_av_cb.rs_idx = 0; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + } + else + { + /* role switch is done. continue to start streaming */ + bta_av_cb.rs_idx = 0; + p_data->hdr.offset = BTA_AV_RS_OK; + bta_av_start_ok (p_scb, p_data); + } + return; + } + + if(p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP) ) + { + if(bta_av_cb.disc) + { + /* AVRC discover db is in use */ + if(p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) + { + /* AVRC channel is not connected. delay a little bit */ + if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) + bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL); + else + p_scb->wait |= BTA_AV_WAIT_CHECK_RC; + } + } + else + { + /* use main SM for AVRC SDP activities */ + bta_av_rc_disc((UINT8)(p_scb->hdi + 1)); + } + } + else + { + if(BTA_AV_RC_HANDLE_NONE != p_scb->rc_handle) + { + /* the open API said that this handle does not want a RC connection. + * disconnect it now */ + AVRC_Close(p_scb->rc_handle); + } + } +} + +/******************************************************************************* +** +** Function bta_av_open_at_inc +** +** Description This function is called if API open is called by application +** while state-machine is at incoming state. +** +** Returns void +** +*******************************************************************************/ +void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_API_OPEN *p_buf; + + memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN)); + + if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) + { + p_scb->coll_mask |= BTA_AV_COLL_API_CALLED; + + /* API open will be handled at timeout if SNK did not start signalling. */ + /* API open will be ignored if SNK starts signalling. */ + } + else + { + /* SNK did not start signalling, API was called N seconds timeout. */ + /* We need to switch to INIT state and start opening connection. */ + p_scb->coll_mask = 0; + bta_av_set_scb_sst_init (p_scb); + + if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL) + { + memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN)); + bta_sys_sendmsg(p_buf); + } + } +} + +#endif /* BTA_AV_INCLUDED */ diff --git a/bta/av/bta_av_act.c b/bta/av/bta_av_act.c new file mode 100644 index 0000000..a47921a --- /dev/null +++ b/bta/av/bta_av_act.c @@ -0,0 +1,1941 @@ +/****************************************************************************** + * + * 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 file contains action functions for advanced audio/video main state + * machine. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#include <string.h> +#include "bta_av_api.h" +#include "bta_av_int.h" +#include "avdt_api.h" +#include "bd.h" +#include "utl.h" +#include "l2c_api.h" +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#include "bta_ar_api.h" +#endif + +/***************************************************************************** +** Constants +*****************************************************************************/ +/* the timer in milliseconds to wait for open req after setconfig for incoming connections */ +#ifndef BTA_AV_SIG_TIME_VAL +#define BTA_AV_SIG_TIME_VAL 8000 +#endif + +/* In millisec to wait for signalling from SNK when it is initiated from SNK. */ +/* If not, we will start signalling from SRC. */ +#ifndef BTA_AV_ACP_SIG_TIME_VAL +#define BTA_AV_ACP_SIG_TIME_VAL 2000 +#endif + +static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle); + +/******************************************************************************* +** +** Function bta_av_get_rcb_by_shdl +** +** Description find the RCB associated with the given SCB handle. +** +** Returns tBTA_AV_RCB +** +*******************************************************************************/ +tBTA_AV_RCB * bta_av_get_rcb_by_shdl(UINT8 shdl) +{ + tBTA_AV_RCB *p_rcb = NULL; + int i; + + for (i=0; i<BTA_AV_NUM_RCB; i++) + { + if (bta_av_cb.rcb[i].shdl == shdl && bta_av_cb.rcb[i].handle != BTA_AV_RC_HANDLE_NONE) + { + p_rcb = &bta_av_cb.rcb[i]; + break; + } + } + return p_rcb; +} +#define BTA_AV_STS_NO_RSP 0xFF /* a number not used by tAVRC_STS */ + +/******************************************************************************* +** +** Function bta_av_del_rc +** +** Description delete the given AVRC handle. +** +** Returns void +** +*******************************************************************************/ +void bta_av_del_rc(tBTA_AV_RCB *p_rcb) +{ + tBTA_AV_SCB *p_scb; + UINT8 rc_handle; /* connected AVRCP handle */ + + if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE) + { + if(p_rcb->shdl) + { + p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; + if(p_scb) + { + APPL_TRACE_DEBUG3("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d", p_rcb->shdl, + p_scb->rc_handle, p_rcb->handle); + if(p_scb->rc_handle == p_rcb->handle) + p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE; + /* just in case the RC timer is active + if(bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl == BTA_AV_CHNL_AUDIO) */ + bta_sys_stop_timer(&p_scb->timer); + } + } + + APPL_TRACE_EVENT4("bta_av_del_rc handle: %d status=0x%x, rc_acp_handle:%d, idx:%d", + p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, bta_av_cb.rc_acp_idx); + rc_handle = p_rcb->handle; + if(!(p_rcb->status & BTA_AV_RC_CONN_MASK) || + ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) ) + { + p_rcb->status = 0; + p_rcb->handle = BTA_AV_RC_HANDLE_NONE; + p_rcb->shdl = 0; + p_rcb->lidx = 0; + } + /* else ACP && connected. do not clear the handle yet */ + AVRC_Close(rc_handle); + if (rc_handle == bta_av_cb.rc_acp_handle) + bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE; + APPL_TRACE_EVENT4("end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d", + p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx); + } +} + + +/******************************************************************************* +** +** Function bta_av_close_all_rc +** +** Description close the all AVRC handle. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_close_all_rc(tBTA_AV_CB *p_cb) +{ + int i; + + for(i=0; i<BTA_AV_NUM_RCB; i++) + { + if ((p_cb->disabling == TRUE) || (bta_av_cb.rcb[i].shdl != 0)) + bta_av_del_rc(&bta_av_cb.rcb[i]); + } +} + +/******************************************************************************* +** +** Function bta_av_del_sdp_rec +** +** Description delete the given SDP record handle. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_del_sdp_rec(UINT32 *p_sdp_handle) +{ + if(*p_sdp_handle != 0) + { + SDP_DeleteRecord(*p_sdp_handle); + *p_sdp_handle = 0; + } +} + +/******************************************************************************* +** +** Function bta_av_avrc_sdp_cback +** +** Description AVRCP service discovery callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_avrc_sdp_cback(UINT16 status) +{ + BT_HDR *p_msg; + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_AV_SDP_AVRC_DISC_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_ctrl_cback +** +** Description AVRCP control callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_rc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result, BD_ADDR peer_addr) +{ + tBTA_AV_RC_CONN_CHG *p_msg; + UINT16 msg_event = 0; + +#if (defined(BTA_AV_MIN_DEBUG_TRACES) && BTA_AV_MIN_DEBUG_TRACES == TRUE) + APPL_TRACE_EVENT2("rc_ctrl handle: %d event=0x%x", handle, event); +#else + APPL_TRACE_EVENT2("bta_av_rc_ctrl_cback handle: %d event=0x%x", handle, event); +#endif + if (event == AVRC_OPEN_IND_EVT) + { + /* save handle of opened connection + bta_av_cb.rc_handle = handle;*/ + + msg_event = BTA_AV_AVRC_OPEN_EVT; + } + else if (event == AVRC_CLOSE_IND_EVT) + { + msg_event = BTA_AV_AVRC_CLOSE_EVT; + } + + if (msg_event) + { + if ((p_msg = (tBTA_AV_RC_CONN_CHG *) GKI_getbuf(sizeof(tBTA_AV_RC_CONN_CHG))) != NULL) + { + p_msg->hdr.event = msg_event; + p_msg->handle = handle; + if(peer_addr) + bdcpy(p_msg->peer_addr, peer_addr); + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rc_msg_cback +** +** Description AVRCP message callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_rc_msg_cback(UINT8 handle, UINT8 label, UINT8 opcode, tAVRC_MSG *p_msg) +{ + tBTA_AV_RC_MSG *p_buf; + UINT8 *p_data = NULL; + UINT8 **p_p_data = NULL; + UINT16 data_len = 0; + +#if (defined(BTA_AV_MIN_DEBUG_TRACES) && BTA_AV_MIN_DEBUG_TRACES == TRUE) + APPL_TRACE_ERROR2("rc_msg handle: %d opcode=0x%x", handle, opcode); +#else + APPL_TRACE_EVENT2("bta_av_rc_msg_cback handle: %d opcode=0x%x", handle, opcode); +#endif + /* determine size of buffer we need */ + if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL) + { + p_data = p_msg->vendor.p_vendor_data; + p_p_data = &p_msg->vendor.p_vendor_data; + data_len = (UINT16) p_msg->vendor.vendor_len; + } + else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL) + { + p_data = p_msg->pass.p_pass_data; + p_p_data = &p_msg->pass.p_pass_data; + data_len = (UINT16) p_msg->pass.pass_len; + } + + if ((p_buf = (tBTA_AV_RC_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_RC_MSG) + data_len))) != NULL) + { + p_buf->hdr.event = BTA_AV_AVRC_MSG_EVT; + p_buf->handle = handle; + p_buf->label = label; + p_buf->opcode = opcode; + memcpy(&p_buf->msg, p_msg, sizeof(tAVRC_MSG)); + if (p_data != NULL) + { + memcpy((UINT8 *)(p_buf + 1), p_data, data_len); + *p_p_data = (UINT8 *)(p_buf + 1); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_create +** +** Description alloc RCB and call AVRC_Open +** +** Returns the created rc handle +** +*******************************************************************************/ +UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx) +{ + tAVRC_CONN_CB ccb; + BD_ADDR_PTR bda = (BD_ADDR_PTR)bd_addr_any; + UINT8 status = BTA_AV_RC_ROLE_ACP; + tBTA_AV_SCB *p_scb = p_cb->p_scb[shdl - 1]; + int i; + UINT8 rc_handle; + tBTA_AV_RCB *p_rcb; + + if(role == AVCT_INT) + { + bda = p_scb->peer_addr; + status = BTA_AV_RC_ROLE_INT; + } + else + { + if ((p_rcb = bta_av_get_rcb_by_shdl(shdl)) != NULL ) + { + APPL_TRACE_ERROR1("bta_av_rc_create ACP handle exist for shdl:%d", shdl); + return p_rcb->handle; + } + } + + ccb.p_ctrl_cback = bta_av_rc_ctrl_cback; + ccb.p_msg_cback = bta_av_rc_msg_cback; + ccb.company_id = p_bta_av_cfg->company_id; + ccb.conn = role; + /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL */ + ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | AVRC_CT_PASSIVE); + + + if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS) + return BTA_AV_RC_HANDLE_NONE; + + i = rc_handle; + p_rcb = &p_cb->rcb[i]; + + if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) + { + APPL_TRACE_ERROR1("bta_av_rc_create found duplicated handle:%d", rc_handle); + } + + p_rcb->handle = rc_handle; + p_rcb->status = status; + p_rcb->shdl = shdl; + p_rcb->lidx = lidx; + p_rcb->peer_features = 0; + if(lidx == (BTA_AV_NUM_LINKS + 1)) + { + /* this LIDX is reserved for the AVRCP ACP connection */ + p_cb->rc_acp_handle = p_rcb->handle; + p_cb->rc_acp_idx = (i + 1); + APPL_TRACE_DEBUG2("rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx); + } + APPL_TRACE_DEBUG6("create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x", + i, role, shdl, p_rcb->handle, lidx, p_rcb->status); + + return rc_handle; +} + +/******************************************************************************* +** +** Function bta_av_valid_group_navi_msg +** +** Description Check if it is Group Navigation Msg for Metadata +** +** Returns BTA_AV_RSP_ACCEPT or BTA_AV_RSP_NOT_IMPL. +** +*******************************************************************************/ +static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data) +{ + tBTA_AV_CODE ret=BTA_AV_RSP_NOT_IMPL; + UINT8 *p_ptr = p_data; + UINT16 u16; + UINT32 u32; + + if (p_bta_av_cfg->avrc_group && len == BTA_GROUP_NAVI_MSG_OP_DATA_LEN) + { + BTA_AV_BE_STREAM_TO_CO_ID(u32, p_ptr); + BE_STREAM_TO_UINT16(u16, p_ptr); + + if (u32 == AVRC_CO_METADATA) + { + if (u16 <= AVRC_PDU_PREV_GROUP) + ret = BTA_AV_RSP_ACCEPT; + else + ret = BTA_AV_RSP_REJ; + } + } + + return ret; +} + +/******************************************************************************* +** +** Function bta_av_op_supported +** +** Description Check if remote control operation is supported. +** +** Returns BTA_AV_RSP_ACCEPT of supported, BTA_AV_RSP_NOT_IMPL if not. +** +*******************************************************************************/ +static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id) +{ + tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL; + + if (p_bta_av_rc_id) + { + if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) + { + ret_code = BTA_AV_RSP_ACCEPT; + } + else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) && p_bta_av_rc_id_ac) + { + if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F))) + { + ret_code = BTA_AV_RSP_INTERIM; + } + } + } + return ret_code; +} + +/******************************************************************************* +** +** Function bta_av_find_lcb +** +** Description Given BD_addr, find the associated LCB. +** +** Returns NULL, if not found. +** +*******************************************************************************/ +tBTA_AV_LCB * bta_av_find_lcb(BD_ADDR addr, UINT8 op) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + int xx; + UINT8 mask; + tBTA_AV_LCB *p_lcb = NULL; + + for(xx=0; xx<BTA_AV_NUM_LINKS; xx++) + { + mask = 1 << xx; /* the used mask for this lcb */ + if((mask & p_cb->conn_lcb) && 0 ==( bdcmp(p_cb->lcb[xx].addr, addr))) + { + p_lcb = &p_cb->lcb[xx]; + if(op == BTA_AV_LCB_FREE) + { + p_cb->conn_lcb &= ~mask; /* clear the connect mask */ + APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb); + } + break; + } + } + return p_lcb; +} + +/******************************************************************************* +** +** Function bta_av_rc_opened +** +** Description Set AVRCP state to opened. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RC_OPEN rc_open; + tBTA_AV_SCB *p_scb; + int i; + UINT8 shdl = 0; + tBTA_AV_LCB *p_lcb; + tBTA_AV_RCB *p_rcb; + UINT8 tmp; + UINT8 disc = 0; + + /* find the SCB & stop the timer */ + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + p_scb = p_cb->p_scb[i]; + if(p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0) + { + p_scb->rc_handle = p_data->rc_conn_chg.handle; + APPL_TRACE_DEBUG2("bta_av_rc_opened shdl:%d, srch %d", i + 1, p_scb->rc_handle); + shdl = i+1; + APPL_TRACE_ERROR1("use_rc:%d", p_scb->use_rc); + bta_sys_stop_timer(&p_scb->timer); + disc = p_scb->hndl; + break; + } + } + + i = p_data->rc_conn_chg.handle; + if (p_cb->rcb[i].handle == BTA_AV_RC_HANDLE_NONE) + { + APPL_TRACE_ERROR1("not a valid handle:%d any more", i); + return; + } + + + if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0) + { + /* rc is opened on the RC only ACP channel, but is for a specific + * SCB -> need to switch RCBs */ + p_rcb = bta_av_get_rcb_by_shdl(shdl); + if (p_rcb) + { + p_rcb->shdl = p_cb->rcb[i].shdl; + tmp = p_rcb->lidx; + p_rcb->lidx = p_cb->rcb[i].lidx; + p_cb->rcb[i].lidx = tmp; + p_cb->rc_acp_handle = p_rcb->handle; + p_cb->rc_acp_idx = (p_rcb - p_cb->rcb) + 1; + APPL_TRACE_DEBUG2("switching RCB rc_acp_handle:%d idx:%d", + p_cb->rc_acp_handle, p_cb->rc_acp_idx); + } + } + + p_cb->rcb[i].shdl = shdl; + rc_open.rc_handle = i; + APPL_TRACE_ERROR4("bta_av_rc_opened rcb[%d] shdl:%d lidx:%d/%d", + i, shdl, p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx); + p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK; + + if(!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx) + { + /* no associated SCB -> connected to an RC only device + * update the index to the extra LCB */ + p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS]; + bdcpy(p_lcb->addr, p_data->rc_conn_chg.peer_addr); + APPL_TRACE_DEBUG6("rc_only bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + p_lcb->addr[0], p_lcb->addr[1], + p_lcb->addr[2], p_lcb->addr[3], + p_lcb->addr[4], p_lcb->addr[5]); + p_lcb->lidx = BTA_AV_NUM_LINKS + 1; + p_cb->rcb[i].lidx = p_lcb->lidx; + p_lcb->conn_msk = 1; + APPL_TRACE_ERROR3("rcb[%d].lidx=%d, lcb.conn_msk=x%x", + i, p_cb->rcb[i].lidx, p_lcb->conn_msk); + disc = p_data->rc_conn_chg.handle|BTA_AV_CHNL_MSK; + } + + bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr); + rc_open.peer_features = p_cb->rcb[i].peer_features; + rc_open.status = BTA_AV_SUCCESS; + APPL_TRACE_DEBUG2("local features:x%x peer_features:x%x", p_cb->features, + rc_open.peer_features); + if(rc_open.peer_features == 0) + { + /* we have not done SDP on peer RC capabilities. + * peer must have initiated the RC connection */ + rc_open.peer_features = BTA_AV_FEAT_RCCT; + bta_av_rc_disc(disc); + } + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open); + +} + + +/******************************************************************************* +** +** Function bta_av_rc_remote_cmd +** +** Description Send an AVRCP remote control command. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_remote_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + if (p_cb->features & BTA_AV_FEAT_RCCT) + { + if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB) + { + p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; + if(p_rcb->status & BTA_AV_RC_CONN_MASK) + { + AVRC_PassCmd(p_rcb->handle, p_data->api_remote_cmd.label, + &p_data->api_remote_cmd.msg); + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_rc_vendor_cmd +** +** Description Send an AVRCP vendor specific command. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_vendor_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + if ( (p_cb->features & (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) == + (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) + { + if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB) + { + p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; + AVRC_VendorCmd(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rc_vendor_rsp +** +** Description Send an AVRCP vendor specific response. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_vendor_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + if ( (p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) == + (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) + { + if(p_data->hdr.layer_specific < BTA_AV_NUM_RCB) + { + p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; + AVRC_VendorRsp(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rc_meta_rsp +** +** Description Send an AVRCP metadata/advanced control command/response. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_meta_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + BOOLEAN free = TRUE; + + if ((p_cb->features & BTA_AV_FEAT_METADATA) && (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)) + { + if ((p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCTG)) || + (!p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCCT)) ) + { + p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; + AVRC_MsgReq(p_rcb->handle, p_data->api_meta_rsp.label, p_data->api_meta_rsp.rsp_code, + p_data->api_meta_rsp.p_pkt); + free = FALSE; + } + } + + if (free) + GKI_freebuf (p_data->api_meta_rsp.p_pkt); +} + +/******************************************************************************* +** +** Function bta_av_rc_free_rsp +** +** Description free an AVRCP metadata command buffer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + GKI_freebuf (p_data->api_meta_rsp.p_pkt); +} + +/******************************************************************************* +** +** Function bta_av_rc_meta_req +** +** Description Send an AVRCP metadata command. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ +} + + + +/******************************************************************************* +** +** Function bta_av_chk_notif_evt_id +** +** Description make sure the requested player id is valid. +** +** Returns BTA_AV_STS_NO_RSP, if no error +** +*******************************************************************************/ +static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR *p_vendor) +{ + tAVRC_STS status = BTA_AV_STS_NO_RSP; + UINT8 xx; + UINT16 u16; + UINT8 *p = p_vendor->p_vendor_data + 2; + + BE_STREAM_TO_UINT16 (u16, p); + /* double check the fixed length */ + if ((u16 != 5) || (p_vendor->vendor_len != 9)) + { + status = AVRC_STS_INTERNAL_ERR; + } + else + { + /* make sure the player_id is valid */ + for (xx=0; xx<p_bta_av_cfg->num_evt_ids; xx++) + { + if (*p == p_bta_av_cfg->p_meta_evt_ids[xx]) + { + break; + } + } + if (xx == p_bta_av_cfg->num_evt_ids) + { + status = AVRC_STS_BAD_PARAM; + } + } + + return status; +} + +/******************************************************************************* +** +** Function bta_av_proc_meta_cmd +** +** Description Process an AVRCP metadata command from the peer. +** +** Returns TRUE to respond immediately +** +*******************************************************************************/ +tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_msg, UINT8 *p_ctype) +{ + tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT; + UINT8 u8, pdu, *p; + UINT16 u16; + tAVRC_MSG_VENDOR *p_vendor = &p_msg->msg.vendor; + + pdu = *(p_vendor->p_vendor_data); + p_rc_rsp->pdu = pdu; + *p_ctype = AVRC_RSP_REJ; + /* Metadata messages only use PANEL sub-unit type */ + if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL) + { + APPL_TRACE_DEBUG0("SUBUNIT must be PANEL"); + /* reject it */ + evt=0; + p_vendor->hdr.ctype = BTA_AV_RSP_NOT_IMPL; + AVRC_VendorRsp(p_msg->handle, p_msg->label, &p_msg->msg.vendor); + } + else + { + switch (pdu) + { + case AVRC_PDU_GET_CAPABILITIES: + /* process GetCapabilities command without reporting the event to app */ + evt = 0; + u8 = *(p_vendor->p_vendor_data + 4); + p = p_vendor->p_vendor_data + 2; + p_rc_rsp->get_caps.capability_id = u8; + BE_STREAM_TO_UINT16 (u16, p); + if ((u16 != 1) || (p_vendor->vendor_len != 5)) + { + p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR; + } + else + { + p_rc_rsp->get_caps.status = AVRC_STS_NO_ERROR; + if (u8 == AVRC_CAP_COMPANY_ID) + { + *p_ctype = AVRC_RSP_IMPL_STBL; + p_rc_rsp->get_caps.count = p_bta_av_cfg->num_co_ids; + memcpy(p_rc_rsp->get_caps.param.company_id, p_bta_av_cfg->p_meta_co_ids, + (p_bta_av_cfg->num_co_ids << 2)); + } + else if (u8 == AVRC_CAP_EVENTS_SUPPORTED) + { + *p_ctype = AVRC_RSP_IMPL_STBL; + p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids; + memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids, + p_bta_av_cfg->num_evt_ids); + } + else + { + APPL_TRACE_DEBUG1("Invalid capability ID: 0x%x", u8); + /* reject - unknown capability ID */ + p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM; + } + } + break; + + + case AVRC_PDU_REGISTER_NOTIFICATION: + /* make sure the event_id is implemented */ + p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id (p_vendor); + if (p_rc_rsp->rsp.status != BTA_AV_STS_NO_RSP) + evt = 0; + break; + + } + } + + return evt; +} + + +/******************************************************************************* +** +** Function bta_av_rc_msg +** +** Description Process an AVRCP message from the peer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_EVT evt = 0; + tBTA_AV av; + BT_HDR *p_pkt = NULL; + tAVRC_MSG_VENDOR *p_vendor = &p_data->rc_msg.msg.vendor; + + if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU) + { + /* if this is a pass thru command */ + if (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) + { + /* check if operation is supported */ + if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) + { + p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL; + } + else + { + p_data->rc_msg.msg.hdr.ctype = bta_av_op_supported(p_data->rc_msg.msg.pass.op_id); + } + + /* send response */ + if (p_data->rc_msg.msg.hdr.ctype != BTA_AV_RSP_INTERIM) + AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass); + + /* set up for callback if supported */ + if (p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_ACCEPT || p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_INTERIM) + { + evt = BTA_AV_REMOTE_CMD_EVT; + av.remote_cmd.rc_id = p_data->rc_msg.msg.pass.op_id; + av.remote_cmd.key_state = p_data->rc_msg.msg.pass.state; + av.remote_cmd.p_data = p_data->rc_msg.msg.pass.p_pass_data; + av.remote_cmd.len = p_data->rc_msg.msg.pass.pass_len; + memcpy(&av.remote_cmd.hdr, &p_data->rc_msg.msg.hdr, sizeof (tAVRC_HDR)); + av.remote_cmd.label = p_data->rc_msg.label; + } + } + /* else if this is a pass thru response */ + else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT) + { + /* set up for callback */ + evt = BTA_AV_REMOTE_RSP_EVT; + av.remote_rsp.rc_id = p_data->rc_msg.msg.pass.op_id; + av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state; + av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype; + av.remote_rsp.label = p_data->rc_msg.label; + } + /* must be a bad ctype -> reject*/ + else + { + p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ; + AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass); + } + } + /* else if this is a vendor specific command or response */ + else if (p_data->rc_msg.opcode == AVRC_OP_VENDOR) + { + /* set up for callback */ + av.vendor_cmd.code = p_data->rc_msg.msg.hdr.ctype; + av.vendor_cmd.company_id = p_vendor->company_id; + av.vendor_cmd.label = p_data->rc_msg.label; + av.vendor_cmd.p_data = p_vendor->p_vendor_data; + av.vendor_cmd.len = p_vendor->vendor_len; + + /* if configured to support vendor specific and it's a command */ + if ((p_cb->features & BTA_AV_FEAT_VENDOR) && + p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) + { + evt = BTA_AV_VENDOR_CMD_EVT; + } + /* else if configured to support vendor specific and it's a response */ + else if ((p_cb->features & BTA_AV_FEAT_VENDOR) && + p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT) + { + evt = BTA_AV_VENDOR_RSP_EVT; + + } + /* else if not configured to support vendor specific and it's a command */ + else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) && + p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) + { + if(p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID) + { + /* reject it */ + p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ; + p_data->rc_msg.msg.vendor.p_vendor_data[4] = AVRC_STS_BAD_CMD; + } + else + p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL; + AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.vendor); + } + } + + /* call callback */ + if (evt != 0) + { + av.remote_cmd.rc_handle = p_data->rc_msg.handle; + (*p_cb->p_cback)(evt, &av); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_close +** +** Description close the specified AVRC handle. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + UINT16 handle = p_data->hdr.layer_specific; + tBTA_AV_SCB *p_scb; + tBTA_AV_RCB *p_rcb; + + if(handle < BTA_AV_NUM_RCB) + { + p_rcb = &p_cb->rcb[handle]; + + APPL_TRACE_DEBUG2("bta_av_rc_close handle: %d, status=0x%x", p_rcb->handle, p_rcb->status); + if(p_rcb->handle != BTA_AV_RC_HANDLE_NONE) + { + if(p_rcb->shdl) + { + p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; + if(p_scb) + { + /* just in case the RC timer is active + if(bta_av_cb.features & BTA_AV_FEAT_RCCT && + p_scb->chnl == BTA_AV_CHNL_AUDIO) */ + bta_sys_stop_timer(&p_scb->timer); + } + } + + AVRC_Close(p_rcb->handle); + } + } +} + +/******************************************************************************* +** +** Function bta_av_get_shdl +** +** Returns The index to p_scb[] +** +*******************************************************************************/ +static UINT8 bta_av_get_shdl(tBTA_AV_SCB *p_scb) +{ + int i; + UINT8 shdl = 0; + /* find the SCB & stop the timer */ + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + if(p_scb == bta_av_cb.p_scb[i]) + { + shdl = i+1; + break; + } + } + return shdl; +} + +/******************************************************************************* +** +** Function bta_av_stream_chg +** +** Description audio streaming status changed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_stream_chg(tBTA_AV_SCB *p_scb, BOOLEAN started) +{ + UINT8 started_msk; + int i; + UINT8 *p_streams; + BOOLEAN no_streams = FALSE; + tBTA_AV_SCB *p_scbi; + + started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi); + APPL_TRACE_DEBUG3 ("bta_av_stream_chg started:%d started_msk:x%x chnl:x%x", started, + started_msk, p_scb->chnl); + if (BTA_AV_CHNL_AUDIO == p_scb->chnl) + p_streams = &bta_av_cb.audio_streams; + else + p_streams = &bta_av_cb.video_streams; + + if (started) + { + /* Let L2CAP know this channel is processed with high priority */ + L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_HIGH); + (*p_streams) |= started_msk; + } + else + { + (*p_streams) &= ~started_msk; + } + + if (!started) + { + i=0; + if (BTA_AV_CHNL_AUDIO == p_scb->chnl) + { + if (bta_av_cb.video_streams == 0) + no_streams = TRUE; + } + else + { + no_streams = TRUE; + if ( bta_av_cb.audio_streams ) + { + for (; i<BTA_AV_NUM_STRS; i++) + { + p_scbi = bta_av_cb.p_scb[i]; + /* scb is used and started */ + if ( p_scbi && (bta_av_cb.audio_streams & BTA_AV_HNDL_TO_MSK(i)) + && bdcmp(p_scbi->peer_addr, p_scb->peer_addr) == 0) + { + no_streams = FALSE; + break; + } + } + + } + } + + APPL_TRACE_DEBUG4 ("no_streams:%d i:%d, audio_streams:x%x, video_streams:x%x", no_streams, i, + bta_av_cb.audio_streams, bta_av_cb.video_streams); + if (no_streams) + { + /* Let L2CAP know this channel is processed with low priority */ + L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_NORMAL); + } + } +} + + +/******************************************************************************* +** +** Function bta_av_conn_chg +** +** Description connetion status changed. +** Open an AVRCP acceptor channel, if new conn. +** +** Returns void +** +*******************************************************************************/ +void bta_av_conn_chg(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_SCB *p_scb; + tBTA_AV_SCB *p_scbi; + UINT8 mask; + UINT8 conn_msk; + UINT8 old_msk; + int i; + int index = (p_data->hdr.layer_specific & BTA_AV_HNDL_MSK) - 1; + tBTA_AV_LCB *p_lcb; + tBTA_AV_LCB *p_lcb_rc; + tBTA_AV_RCB *p_rcb, *p_rcb2; + BOOLEAN chk_restore = FALSE; + + p_scb = p_cb->p_scb[index]; + + mask = BTA_AV_HNDL_TO_MSK(index); + p_lcb = bta_av_find_lcb(p_data->conn_chg.peer_addr, BTA_AV_LCB_FIND); + conn_msk = 1 << (index + 1); + if(p_data->conn_chg.is_up) + { + /* set the conned mask for this channel */ + if(p_scb) + { + if(p_lcb) + { + p_lcb->conn_msk |= conn_msk; + for (i=0; i<BTA_AV_NUM_RCB; i++) + { + if (bta_av_cb.rcb[i].lidx == p_lcb->lidx) + { + bta_av_cb.rcb[i].shdl = index + 1; + APPL_TRACE_DEBUG5("conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i, + bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status, + bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx); + break; + } + } + } + if (p_scb->chnl == BTA_AV_CHNL_AUDIO) + { + old_msk = p_cb->conn_audio; + p_cb->conn_audio |= mask; + } + else + { + old_msk = p_cb->conn_video; + p_cb->conn_video |= mask; + } + + if ((old_msk & mask) == 0) + { + /* increase the audio open count, if not set yet */ + bta_av_cb.audio_open_cnt++; + } + + + APPL_TRACE_DEBUG2("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx); + /* check if the AVRCP ACP channel is already connected */ + if(p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx) + { + p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS]; + APPL_TRACE_DEBUG1("rc_acp is connected && conn_chg on same addr p_lcb_rc->conn_msk:x%x", + p_lcb_rc->conn_msk); + /* check if the RC is connected to the scb addr */ + APPL_TRACE_DEBUG6 ("p_lcb_rc->addr: %02x:%02x:%02x:%02x:%02x:%02x", + p_lcb_rc->addr[0], p_lcb_rc->addr[1], p_lcb_rc->addr[2], p_lcb_rc->addr[3], + p_lcb_rc->addr[4], p_lcb_rc->addr[5]); + APPL_TRACE_DEBUG6 ("conn_chg.peer_addr: %02x:%02x:%02x:%02x:%02x:%02x", + p_data->conn_chg.peer_addr[0], p_data->conn_chg.peer_addr[1], + p_data->conn_chg.peer_addr[2], + p_data->conn_chg.peer_addr[3], p_data->conn_chg.peer_addr[4], + p_data->conn_chg.peer_addr[5]); + if (p_lcb_rc->conn_msk && bdcmp(p_lcb_rc->addr, p_data->conn_chg.peer_addr) == 0) + { + /* AVRCP is already connected. + * need to update the association betwen SCB and RCB */ + p_lcb_rc->conn_msk = 0; /* indicate RC ONLY is not connected */ + p_lcb_rc->lidx = 0; + p_scb->rc_handle = p_cb->rc_acp_handle; + p_rcb = &p_cb->rcb[p_cb->rc_acp_idx - 1]; + p_rcb->shdl = bta_av_get_shdl(p_scb); + APPL_TRACE_DEBUG3("update rc_acp shdl:%d/%d srch:%d", index + 1, p_rcb->shdl, + p_scb->rc_handle ); + + p_rcb2 = bta_av_get_rcb_by_shdl(p_rcb->shdl); + if (p_rcb2) + { + /* found the RCB that was created to associated with this SCB */ + p_cb->rc_acp_handle = p_rcb2->handle; + p_cb->rc_acp_idx = (p_rcb2 - p_cb->rcb) + 1; + APPL_TRACE_DEBUG2("new rc_acp_handle:%d, idx:%d", p_cb->rc_acp_handle, + p_cb->rc_acp_idx); + p_rcb2->lidx = (BTA_AV_NUM_LINKS + 1); + APPL_TRACE_DEBUG3("rc2 handle:%d lidx:%d/%d",p_rcb2->handle, p_rcb2->lidx, + p_cb->lcb[p_rcb2->lidx-1].lidx); + } + p_rcb->lidx = p_lcb->lidx; + APPL_TRACE_DEBUG3("rc handle:%d lidx:%d/%d",p_rcb->handle, p_rcb->lidx, + p_cb->lcb[p_rcb->lidx-1].lidx); + } + } + } + } + else + { + if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) + { + /* this channel is still marked as open. decrease the count */ + bta_av_cb.audio_open_cnt--; + } + + /* clear the conned mask for this channel */ + p_cb->conn_audio &= ~mask; + p_cb->conn_video &= ~mask; + if(p_scb) + { + /* the stream is closed. + * clear the peer address, so it would not mess up the AVRCP for the next round of operation */ + bdcpy(p_scb->peer_addr, bd_addr_null); + if(p_scb->chnl == BTA_AV_CHNL_AUDIO) + { + if(p_lcb) + { + p_lcb->conn_msk &= ~conn_msk; + } + /* audio channel is down. make sure the INT channel is down */ + /* just in case the RC timer is active + if(p_cb->features & BTA_AV_FEAT_RCCT) */ + { + bta_sys_stop_timer(&p_scb->timer); + } + /* one audio channel goes down. check if we need to restore high priority */ + chk_restore = TRUE; + } + } + + APPL_TRACE_DEBUG1("bta_av_conn_chg shdl:%d", index + 1); + for (i=0; i<BTA_AV_NUM_RCB; i++) + { + APPL_TRACE_DEBUG5("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i, + bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status, + bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx); + if(bta_av_cb.rcb[i].shdl == index + 1) + { + bta_av_del_rc(&bta_av_cb.rcb[i]); + break; + } + } + + if(p_cb->conn_audio == 0 && p_cb->conn_video == 0) + { + /* if both channels are not connected, + * close all RC channels */ + bta_av_close_all_rc(p_cb); + } + + /* if the AVRCP is no longer listening, create the listening channel */ + if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG) + bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + } + + APPL_TRACE_DEBUG6("bta_av_conn_chg audio:%x video:%x up:%d conn_msk:0x%x chk_restore:%d audio_open_cnt:%d", + p_cb->conn_audio, p_cb->conn_video, p_data->conn_chg.is_up, conn_msk, chk_restore, p_cb->audio_open_cnt); + + if (chk_restore) + { + if (p_cb->audio_open_cnt == 1) + { + /* one audio channel goes down and there's one audio channel remains open. + * restore the switch role in default link policy */ + bta_sys_set_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH); + /* allow role switch, if this is the last connection */ + bta_av_restore_switch(); + } + if (p_cb->audio_open_cnt) + { + /* adjust flush timeout settings to longer period */ + for (i=0; i<BTA_AV_NUM_STRS; i++) + { + p_scbi = bta_av_cb.p_scb[i]; + if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) + { + /* may need to update the flush timeout of this already started stream */ + if (p_scbi->co_started != bta_av_cb.audio_open_cnt) + { + p_scbi->co_started = bta_av_cb.audio_open_cnt; + L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] ); + } + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_disable +** +** Description disable AV. +** +** Returns void +** +*******************************************************************************/ +void bta_av_disable(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + BT_HDR hdr; + UINT16 xx; + + p_cb->disabling = TRUE; + + bta_av_close_all_rc(p_cb); + + utl_freebuf((void **) &p_cb->p_disc_db); + + /* disable audio/video - de-register all channels, + * expect BTA_AV_DEREG_COMP_EVT when deregister is complete */ + for(xx=0; xx<BTA_AV_NUM_STRS; xx++) + { + hdr.layer_specific = xx + 1; + bta_av_api_deregister((tBTA_AV_DATA *)&hdr); + } +} + +/******************************************************************************* +** +** Function bta_av_api_disconnect +** +** Description . +** +** Returns void +** +*******************************************************************************/ +void bta_av_api_disconnect(tBTA_AV_DATA *p_data) +{ + AVDT_DisconnectReq(p_data->api_discnt.bd_addr, bta_av_conn_cback); + bta_sys_stop_timer(&bta_av_cb.sig_tmr); +} + +/******************************************************************************* +** +** Function bta_av_sig_chg +** +** Description process AVDT signal channel up/down. +** +** Returns void +** +*******************************************************************************/ +void bta_av_sig_chg(tBTA_AV_DATA *p_data) +{ + UINT16 event = p_data->str_msg.hdr.layer_specific; + tBTA_AV_CB *p_cb = &bta_av_cb; + int xx; + UINT8 mask; + tBTA_AV_LCB *p_lcb = NULL; + + APPL_TRACE_DEBUG1("bta_av_sig_chg event: %d", event); + if(event == AVDT_CONNECT_IND_EVT) + { + p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND); + if(!p_lcb) + { + /* if the address does not have an LCB yet, alloc one */ + for(xx=0; xx<BTA_AV_NUM_LINKS; xx++) + { + mask = 1 << xx; + APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb); + if(!(mask & p_cb->conn_lcb)) + { + if (!p_cb->p_scb[xx]) + { + /* We do not have scb for this avdt connection. */ + /* Silently close the connection. */ + APPL_TRACE_ERROR0("av scb not available for avdt connection"); + AVDT_DisconnectReq (p_data->str_msg.bd_addr, NULL); + return; + } + + p_lcb = &p_cb->lcb[xx]; + p_lcb->lidx = xx + 1; + bdcpy(p_lcb->addr, p_data->str_msg.bd_addr); + p_lcb->conn_msk = 0; /* clear the connect mask */ + /* start listening when the signal channel is open */ + if (p_cb->features & BTA_AV_FEAT_RCTG) + { + bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx); + } + /* this entry is not used yet. */ + p_cb->conn_lcb |= mask; /* mark it as used */ + APPL_TRACE_DEBUG1("start sig timer %d", p_data->hdr.offset); + if (p_data->hdr.offset == AVDT_ACP) + { + APPL_TRACE_DEBUG1("Incoming L2CAP acquired, set state as incoming", NULL); + bdcpy(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr); + p_cb->p_scb[xx]->use_rc = TRUE; /* allowing RC for incoming connection */ + bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_ACP_CONNECT_EVT, p_data); + + /* The Pending Event should be sent as soon as the L2CAP signalling channel + * is set up, which is NOW. Earlier this was done only after + * BTA_AV_SIG_TIME_VAL milliseconds. + * The following function shall send the event and start the recurring timer + */ + bta_av_sig_timer(NULL); + + /* Possible collision : need to avoid outgoing processing while the timer is running */ + p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR; + + p_cb->acp_sig_tmr.param = (UINT32)xx; + p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK*)&bta_av_acp_sig_timer_cback; + bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL); + } + break; + } + } + } + } +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + else if (event == BTA_AR_AVDT_CONN_EVT) + { + bta_sys_stop_timer(&bta_av_cb.sig_tmr); + } +#endif + else + { + /* disconnected. */ + p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE); + if(p_lcb && p_lcb->conn_msk) + { + APPL_TRACE_DEBUG1("conn_msk: 0x%x", p_lcb->conn_msk); + /* clean up ssm */ + for(xx=0; xx < BTA_AV_NUM_STRS; xx++) + { + mask = 1 << (xx + 1); + if ((mask & p_lcb->conn_msk) && (p_cb->p_scb[xx]) && + (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0)) + { + bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL); + } + } + } + } + APPL_TRACE_DEBUG1("conn_lcb: 0x%x", p_cb->conn_lcb); +} + +/******************************************************************************* +** +** Function bta_av_sig_timer +** +** Description process the signal channel timer. This timer is started +** when the AVDTP signal channel is connected. If no profile +** is connected, the timer goes off every BTA_AV_SIG_TIME_VAL +** +** Returns void +** +*******************************************************************************/ +void bta_av_sig_timer(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + int xx; + UINT8 mask; + tBTA_AV_LCB *p_lcb = NULL; + tBTA_AV_PEND pend; + + APPL_TRACE_DEBUG0("bta_av_sig_timer"); + for(xx=0; xx<BTA_AV_NUM_LINKS; xx++) + { + mask = 1 << xx; + if(mask & p_cb->conn_lcb) + { + /* this entry is used. check if it is connected */ + p_lcb = &p_cb->lcb[xx]; + if(!p_lcb->conn_msk) + { + bta_sys_start_timer(&p_cb->sig_tmr, BTA_AV_SIG_TIMER_EVT, BTA_AV_SIG_TIME_VAL); + bdcpy(pend.bd_addr, p_lcb->addr); + (*p_cb->p_cback)(BTA_AV_PENDING_EVT, (tBTA_AV *) &pend); + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_acp_sig_timer_cback +** +** Description Process the timeout when SRC is accepting connection +** and SNK did not start signalling. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle) +{ + UINT8 inx = (UINT8)p_tle->param; + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_SCB *p_scb = p_cb->p_scb[inx]; + tBTA_AV_API_OPEN *p_buf; + + if (p_scb) + { + APPL_TRACE_DEBUG1("bta_av_acp_sig_timer_cback, coll_mask = 0x%02X", p_scb->coll_mask); + + if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) + { + p_scb->coll_mask &= ~BTA_AV_COLL_INC_TMR; + + if (bta_av_is_scb_opening(p_scb)) + { + if (p_scb->p_disc_db) + { + /* We are still doing SDP. Run the timer again. */ + p_scb->coll_mask |= BTA_AV_COLL_INC_TMR; + + p_cb->acp_sig_tmr.param = (UINT32)inx; + p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK *)&bta_av_acp_sig_timer_cback; + bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL); + } + else + { + /* SNK did not start signalling, resume signalling process. */ + bta_av_discover_req (p_scb, NULL); + } + } + else if (bta_av_is_scb_incoming(p_scb)) + { + /* Stay in incoming state if SNK does not start signalling */ + + /* API open was called right after SNK opened L2C connection. */ + if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED) + { + p_scb->coll_mask &= ~BTA_AV_COLL_API_CALLED; + + /* BTA_AV_API_OPEN_EVT */ + if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL) + { + memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN)); + bta_sys_sendmsg(p_buf); + } + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_check_peer_features +** +** Description checks +** +** Returns void +** +*******************************************************************************/ +tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid) +{ + tBTA_AV_FEAT peer_features = 0; + tBTA_AV_CB *p_cb = &bta_av_cb; + tSDP_DISC_REC *p_rec = NULL; + tSDP_DISC_ATTR *p_attr; + UINT16 peer_rc_version=0; + UINT16 categories = 0; + + APPL_TRACE_DEBUG1("bta_av_check_peer_features service_uuid:x%x", service_uuid); + /* loop through all records we found */ + while (TRUE) + { + /* get next record; if none found, we're done */ + if ((p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec)) == NULL) + { + break; + } + + if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL) + { + /* find peer features */ + if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL)) + { + peer_features |= BTA_AV_FEAT_RCCT; + } + if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) + { + peer_features |= BTA_AV_FEAT_RCTG; + } + } + + if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) + { + /* get profile version (if failure, version parameter is not updated) */ + SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version); + APPL_TRACE_DEBUG1("peer_rc_version 0x%x", peer_rc_version); + + if (peer_rc_version >= AVRC_REV_1_3) + peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA); + + if (peer_rc_version >= AVRC_REV_1_4) + { + peer_features |= (BTA_AV_FEAT_ADV_CTRL); + /* get supported categories */ + if ((p_attr = SDP_FindAttributeInRec(p_rec, + ATTR_ID_SUPPORTED_FEATURES)) != NULL) + { + categories = p_attr->attr_value.v.u16; + if (categories & AVRC_SUPF_CT_BROWSE) + peer_features |= (BTA_AV_FEAT_BROWSE); + } + } + } + } + APPL_TRACE_DEBUG1("peer_features:x%x", peer_features); + return peer_features; +} + +/******************************************************************************* +** +** Function bta_av_rc_disc_done +** +** Description Handle AVRCP service discovery results. If matching +** service found, open AVRCP connection. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_disc_done(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_SCB *p_scb = NULL; + tBTA_AV_LCB *p_lcb; + tBTA_AV_RC_OPEN rc_open; + tBTA_AV_RC_FEAT rc_feat; + UINT8 rc_handle; + tBTA_AV_FEAT peer_features; /* peer features mask */ + + APPL_TRACE_DEBUG1("bta_av_rc_disc_done disc:x%x", p_cb->disc); + if (!p_cb->disc) + { + return; + } + + if ((p_cb->disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) + { + /* this is the rc handle/index to tBTA_AV_RCB */ + rc_handle = p_cb->disc & (~BTA_AV_CHNL_MSK); + } + else + { + p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1]; + if (p_scb) + rc_handle = p_scb->rc_handle; + else + { + p_cb->disc = 0; + return; + } + } + + APPL_TRACE_DEBUG1("rc_handle %d", rc_handle); + peer_features = bta_av_check_peer_features (UUID_SERVCLASS_AV_REMOTE_CONTROL); + if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && ((peer_features&BTA_AV_FEAT_ADV_CTRL) == 0)) + { + /* if we support advance control and peer does not, check their support on TG role + * some implementation uses 1.3 on CT ans 1.4 on TG */ + peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET); + } + + p_cb->disc = 0; + utl_freebuf((void **) &p_cb->p_disc_db); + + APPL_TRACE_DEBUG2("peer_features 0x%x, features 0x%x", peer_features, p_cb->features); + + /* if we have no rc connection */ + if (rc_handle == BTA_AV_RC_HANDLE_NONE) + { + if (p_scb) + { + /* if peer remote control service matches ours and USE_RC is TRUE */ + if ((((p_cb->features & BTA_AV_FEAT_RCCT) && (peer_features & BTA_AV_FEAT_RCTG)) || + ((p_cb->features & BTA_AV_FEAT_RCTG) && (peer_features & BTA_AV_FEAT_RCCT))) ) + { + p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND); + if(p_lcb) + { + rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx); + p_cb->rcb[rc_handle].peer_features = peer_features; + } +#if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE) + else + { + APPL_TRACE_ERROR0("can not find LCB!!"); + } +#endif + } + else if(p_scb->use_rc) + { + /* can not find AVRC on peer device. report failure */ + p_scb->use_rc = FALSE; + bdcpy(rc_open.peer_addr, p_scb->peer_addr); + rc_open.peer_features = 0; + rc_open.status = BTA_AV_FAIL_SDP; + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open); + } + } + } + else + { + p_cb->rcb[rc_handle].peer_features = peer_features; + rc_feat.rc_handle = rc_handle; + rc_feat.peer_features = peer_features; + (*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV *) &rc_feat); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_closed +** +** Description Set AVRCP state to closed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_closed(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_RC_CLOSE rc_close; + tBTA_AV_RC_CONN_CHG *p_msg = (tBTA_AV_RC_CONN_CHG *)p_data; + tBTA_AV_RCB *p_rcb; + tBTA_AV_SCB *p_scb; + int i; + BOOLEAN conn = FALSE; + tBTA_AV_LCB *p_lcb; + + rc_close.rc_handle = BTA_AV_RC_HANDLE_NONE; + APPL_TRACE_DEBUG1("bta_av_rc_closed rc_handle:%d", p_msg->handle); + for(i=0; i<BTA_AV_NUM_RCB; i++) + { + p_rcb = &p_cb->rcb[i]; + APPL_TRACE_DEBUG3("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i, p_rcb->handle, p_rcb->status); + if(p_rcb->handle == p_msg->handle) + { + rc_close.rc_handle = i; + p_rcb->status &= ~BTA_AV_RC_CONN_MASK; + p_rcb->peer_features = 0; + APPL_TRACE_DEBUG2(" shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx); + if(p_rcb->shdl) + { + p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; + if(p_scb) + { + bdcpy(rc_close.peer_addr, p_scb->peer_addr); + if(p_scb->rc_handle == p_rcb->handle) + p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE; + APPL_TRACE_DEBUG2("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle); + } + p_rcb->shdl = 0; + } + else if(p_rcb->lidx == (BTA_AV_NUM_LINKS + 1) ) + { + /* if the RCB uses the extra LCB, use the addr for event and clean it */ + p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS]; + bdcpy(rc_close.peer_addr, p_msg->peer_addr); + APPL_TRACE_DEBUG6("rc_only closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + p_msg->peer_addr[0], p_msg->peer_addr[1], + p_msg->peer_addr[2], p_msg->peer_addr[3], + p_msg->peer_addr[4], p_msg->peer_addr[5]); + p_lcb->conn_msk = 0; + p_lcb->lidx = 0; + } + p_rcb->lidx = 0; + + if((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) + { + /* AVCT CCB is deallocated */ + p_rcb->handle = BTA_AV_RC_HANDLE_NONE; + p_rcb->status = 0; + } + else + { + /* AVCT CCB is still there. dealloc */ + bta_av_del_rc(p_rcb); + + /* if the AVRCP is no longer listening, create the listening channel */ + if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG) + bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + } + } + else if((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK)) + { + /* at least one channel is still connected */ + conn = TRUE; + } + } + + if(!conn) + { + /* no AVRC channels are connected, go back to INIT state */ + bta_av_sm_execute(p_cb, BTA_AV_AVRC_NONE_EVT, NULL); + } + + if (rc_close.rc_handle == BTA_AV_RC_HANDLE_NONE) + { + rc_close.rc_handle = p_msg->handle; + bdcpy(rc_close.peer_addr, p_msg->peer_addr); + } + (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV *) &rc_close); +} + +/******************************************************************************* +** +** Function bta_av_rc_disc +** +** Description start AVRC SDP discovery. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_disc(UINT8 disc) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tAVRC_SDP_DB_PARAMS db_params; + UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, + ATTR_ID_BT_PROFILE_DESC_LIST, + ATTR_ID_SUPPORTED_FEATURES}; + UINT8 hdi; + tBTA_AV_SCB *p_scb; + UINT8 *p_addr = NULL; + UINT8 rc_handle; + + APPL_TRACE_DEBUG2("bta_av_rc_disc 0x%x, %d", disc, bta_av_cb.disc); + if ((bta_av_cb.disc != 0) || (disc == 0)) + return; + + if ((disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) + { + /* this is the rc handle/index to tBTA_AV_RCB */ + rc_handle = disc & (~BTA_AV_CHNL_MSK); + if (p_cb->rcb[rc_handle].lidx) + { + p_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx-1].addr; + } + } + else + { + hdi = (disc & BTA_AV_HNDL_MSK) - 1; + p_scb = p_cb->p_scb[hdi]; + + if (p_scb) + { + APPL_TRACE_DEBUG1("rc_handle %d", p_scb->rc_handle); + p_addr = p_scb->peer_addr; + } + } + + if (p_addr) + { + /* allocate discovery database */ + if (p_cb->p_disc_db == NULL) + { + p_cb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE); + } + + if (p_cb->p_disc_db) + { + /* set up parameters */ + db_params.db_len = BTA_AV_DISC_BUF_SIZE; + db_params.num_attr = 3; + db_params.p_db = p_cb->p_disc_db; + db_params.p_attrs = attr_list; + + /* searching for UUID_SERVCLASS_AV_REMOTE_CONTROL gets both TG and CT */ + if (AVRC_FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, p_addr, &db_params, + bta_av_avrc_sdp_cback) == AVRC_SUCCESS) + { + p_cb->disc = disc; + APPL_TRACE_DEBUG1("disc %d", p_cb->disc); + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_dereg_comp +** +** Description deregister complete. free the stream control block. +** +** Returns void +** +*******************************************************************************/ +void bta_av_dereg_comp(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_SCB *p_scb; + tBTA_UTL_COD cod; + UINT8 mask; + BT_HDR *p_buf; + + /* find the stream control block */ + p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific); + + if(p_scb) + { + APPL_TRACE_DEBUG2("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl); + mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi); + if(p_scb->chnl == BTA_AV_CHNL_AUDIO) + { + p_cb->reg_audio &= ~mask; + if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) + { + /* this channel is still marked as open. decrease the count */ + bta_av_cb.audio_open_cnt--; + } + p_cb->conn_audio &= ~mask; + + if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM) + { + /* make sure no buffers are in q_info.a2d */ + while((p_buf = (BT_HDR*)GKI_dequeue (&p_scb->q_info.a2d)) != NULL) + GKI_freebuf(p_buf); + } + + /* remove the A2DP SDP record, if no more audio stream is left */ + if(!p_cb->reg_audio) + { +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV); +#endif + bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle); + bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE); + } + } + else + { + p_cb->reg_video &= ~mask; + /* make sure that this channel is not connected */ + p_cb->conn_video &= ~mask; + /* remove the VDP SDP record, (only one video stream at most) */ + bta_av_del_sdp_rec(&p_cb->sdp_vdp_handle); + bta_sys_remove_uuid(UUID_SERVCLASS_VIDEO_SOURCE); + } + + /* make sure that the timer is not active */ + bta_sys_stop_timer(&p_scb->timer); + utl_freebuf((void **)&p_cb->p_scb[p_scb->hdi]); + } + + APPL_TRACE_DEBUG3("audio 0x%x, video: 0x%x, disable:%d", + p_cb->reg_audio, p_cb->reg_video, p_cb->disabling); + /* if no stream control block is active */ + if((p_cb->reg_audio + p_cb->reg_video) == 0) + { +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + /* deregister from AVDT */ + bta_ar_dereg_avdt(BTA_ID_AV); + + /* deregister from AVCT */ + bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REM_CTRL_TARGET, BTA_ID_AV); + bta_ar_dereg_avct(BTA_ID_AV); +#endif + + if(p_cb->disabling) + { + p_cb->disabling = FALSE; + bta_av_cb.features = 0; + } + + /* Clear the Capturing service class bit */ + cod.service = BTM_COD_SERVICE_CAPTURING; + utl_set_device_class(&cod, BTA_UTL_CLR_COD_SERVICE_CLASS); + } +} +#endif /* BTA_AV_INCLUDED */ diff --git a/bta/av/bta_av_api.c b/bta/av/bta_av_api.c new file mode 100644 index 0000000..a58e4a6 --- /dev/null +++ b/bta/av/bta_av_api.c @@ -0,0 +1,581 @@ +/****************************************************************************** + * + * Copyright (C) 2011-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 of the API for the advanced audio/video (AV) + * subsystem of BTA, Broadcom's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#include "bta_api.h" +#include "bd.h" +#include "bta_sys.h" +#include "bta_av_api.h" +#include "bta_av_int.h" +#include "gki.h" +#include <string.h> + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_av_reg = +{ + bta_av_hdl_event, + BTA_AvDisable +}; + +/******************************************************************************* +** +** Function BTA_AvEnable +** +** Description Enable the advanced audio/video service. When the enable +** operation is complete the callback function will be +** called with a BTA_AV_ENABLE_EVT. This function must +** be called before other function in the AV API are +** called. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, tBTA_AV_CBACK *p_cback) +{ + tBTA_AV_API_ENABLE *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_AV, &bta_av_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_AV_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AV_API_ENABLE))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + p_buf->features = features; + p_buf->sec_mask = sec_mask; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvDisable +** +** Description Disable the advanced audio/video service. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_AV); + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AV_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvRegister +** +** Description Register the audio or video service to stack. When the +** operation is complete the callback function will be +** called with a BTA_AV_REGISTER_EVT. This function must +** be called before AVDT stream is open. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id) +{ + tBTA_AV_API_REG *p_buf; + + + if ((p_buf = (tBTA_AV_API_REG *) GKI_getbuf(sizeof(tBTA_AV_API_REG))) != NULL) + { + p_buf->hdr.layer_specific = chnl; + p_buf->hdr.event = BTA_AV_API_REGISTER_EVT; + if(p_service_name) + { + BCM_STRNCPY_S(p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name, BTA_SERVICE_NAME_LEN); + p_buf->p_service_name[BTA_SERVICE_NAME_LEN-1] = 0; + } + else + { + p_buf->p_service_name[0] = 0; + } + p_buf->app_id = app_id; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvDeregister +** +** Description Deregister the audio or video service +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDeregister(tBTA_AV_HNDL hndl) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->layer_specific = hndl; + p_buf->event = BTA_AV_API_DEREGISTER_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvOpen +** +** Description Opens an advanced audio/video connection to a peer device. +** When connection is open callback function is called +** with a BTA_AV_OPEN_EVT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, BOOLEAN use_rc, tBTA_SEC sec_mask) +{ + tBTA_AV_API_OPEN *p_buf; + + if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_OPEN_EVT; + p_buf->hdr.layer_specific = handle; + bdcpy(p_buf->bd_addr, bd_addr); + p_buf->use_rc = use_rc; + p_buf->sec_mask = sec_mask; + p_buf->switch_res = BTA_AV_RS_NONE; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvClose +** +** Description Close the current streams. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvClose(tBTA_AV_HNDL handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AV_API_CLOSE_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvDisconnect +** +** Description Close the connection to the address. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDisconnect(BD_ADDR bd_addr) +{ + tBTA_AV_API_DISCNT *p_buf; + + if ((p_buf = (tBTA_AV_API_DISCNT *) GKI_getbuf(sizeof(tBTA_AV_API_DISCNT))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_DISCONNECT_EVT; + bdcpy(p_buf->bd_addr, bd_addr); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvStart +** +** Description Start audio/video stream data transfer. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvStart(void) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AV_API_START_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvStop +** +** Description Stop audio/video stream data transfer. +** If suspend is TRUE, this function sends AVDT suspend signal +** to the connected peer(s). +** +** Returns void +** +*******************************************************************************/ +void BTA_AvStop(BOOLEAN suspend) +{ + tBTA_AV_API_STOP *p_buf; + + if ((p_buf = (tBTA_AV_API_STOP *) GKI_getbuf(sizeof(tBTA_AV_API_STOP))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_STOP_EVT; + p_buf->flush = TRUE; + p_buf->suspend = suspend; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvReconfig +** +** Description Reconfigure the audio/video stream. +** If suspend is TRUE, this function tries the suspend/reconfigure +** procedure first. +** If suspend is FALSE or when suspend/reconfigure fails, +** this function closes and re-opens the AVDT connection. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvReconfig(tBTA_AV_HNDL hndl, BOOLEAN suspend, UINT8 sep_info_idx, + UINT8 *p_codec_info, UINT8 num_protect, UINT8 *p_protect_info) +{ + tBTA_AV_API_RCFG *p_buf; + + if ((p_buf = (tBTA_AV_API_RCFG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_RCFG) + num_protect))) != NULL) + { + p_buf->hdr.layer_specific = hndl; + p_buf->hdr.event = BTA_AV_API_RECONFIG_EVT; + p_buf->num_protect = num_protect; + p_buf->suspend = suspend; + p_buf->sep_info_idx = sep_info_idx; + p_buf->p_protect_info = (UINT8 *)(p_buf + 1); + memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE); + memcpy(p_buf->p_protect_info, p_protect_info, num_protect); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvProtectReq +** +** Description Send a content protection request. This function can only +** be used if AV is enabled with feature BTA_AV_FEAT_PROTECT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvProtectReq(tBTA_AV_HNDL hndl, UINT8 *p_data, UINT16 len) +{ + tBTA_AV_API_PROTECT_REQ *p_buf; + + if ((p_buf = (tBTA_AV_API_PROTECT_REQ *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_PROTECT_REQ) + len))) != NULL) + { + p_buf->hdr.layer_specific = hndl; + p_buf->hdr.event = BTA_AV_API_PROTECT_REQ_EVT; + p_buf->len = len; + if (p_data == NULL) + { + p_buf->p_data = NULL; + } + else + { + p_buf->p_data = (UINT8 *) (p_buf + 1); + memcpy(p_buf->p_data, p_data, len); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvProtectRsp +** +** Description Send a content protection response. This function must +** be called if a BTA_AV_PROTECT_REQ_EVT is received. +** This function can only be used if AV is enabled with +** feature BTA_AV_FEAT_PROTECT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, UINT8 error_code, UINT8 *p_data, UINT16 len) +{ + tBTA_AV_API_PROTECT_RSP *p_buf; + + if ((p_buf = (tBTA_AV_API_PROTECT_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_PROTECT_RSP) + len))) != NULL) + { + p_buf->hdr.layer_specific = hndl; + p_buf->hdr.event = BTA_AV_API_PROTECT_RSP_EVT; + p_buf->len = len; + p_buf->error_code = error_code; + if (p_data == NULL) + { + p_buf->p_data = NULL; + } + else + { + p_buf->p_data = (UINT8 *) (p_buf + 1); + memcpy(p_buf->p_data, p_data, len); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvRemoteCmd +** +** Description Send a remote control command. This function can only +** be used if AV is enabled with feature BTA_AV_FEAT_RCCT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id, tBTA_AV_STATE key_state) +{ + tBTA_AV_API_REMOTE_CMD *p_buf; + + if ((p_buf = (tBTA_AV_API_REMOTE_CMD *) GKI_getbuf(sizeof(tBTA_AV_API_REMOTE_CMD))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->msg.op_id = rc_id; + p_buf->msg.state = key_state; + p_buf->msg.p_pass_data = NULL; + p_buf->msg.pass_len = 0; + p_buf->label = label; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvVendorCmd +** +** Description Send a vendor dependent remote control command. This +** function can only be used if AV is enabled with feature +** BTA_AV_FEAT_VENDOR. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvVendorCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE cmd_code, UINT8 *p_data, UINT16 len) +{ + tBTA_AV_API_VENDOR *p_buf; + + if ((p_buf = (tBTA_AV_API_VENDOR *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_VENDOR) + len))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_VENDOR_CMD_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->msg.hdr.ctype = cmd_code; + p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL; + p_buf->msg.hdr.subunit_id = 0; + p_buf->msg.company_id = p_bta_av_cfg->company_id; + p_buf->label = label; + p_buf->msg.vendor_len = len; + if (p_data == NULL) + { + p_buf->msg.p_vendor_data = NULL; + } + else + { + p_buf->msg.p_vendor_data = (UINT8 *) (p_buf + 1); + memcpy(p_buf->msg.p_vendor_data, p_data, len); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvVendorRsp +** +** Description Send a vendor dependent remote control response. +** This function must be called if a BTA_AV_VENDOR_CMD_EVT +** is received. This function can only be used if AV is +** enabled with feature BTA_AV_FEAT_VENDOR. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvVendorRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, UINT8 *p_data, UINT16 len, UINT32 company_id) +{ + tBTA_AV_API_VENDOR *p_buf; + + if ((p_buf = (tBTA_AV_API_VENDOR *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_VENDOR) + len))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_VENDOR_RSP_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->msg.hdr.ctype = rsp_code; + p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL; + p_buf->msg.hdr.subunit_id = 0; + if(company_id) + p_buf->msg.company_id = company_id; + else + p_buf->msg.company_id = p_bta_av_cfg->company_id; + p_buf->label = label; + p_buf->msg.vendor_len = len; + if (p_data == NULL) + { + p_buf->msg.p_vendor_data = NULL; + } + else + { + p_buf->msg.p_vendor_data = (UINT8 *) (p_buf + 1); + memcpy(p_buf->msg.p_vendor_data, p_data, len); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvOpenRc +** +** Description Open an AVRCP connection toward the device with the +** specified handle +** +** Returns void +** +*******************************************************************************/ +void BTA_AvOpenRc(tBTA_AV_HNDL handle) +{ + tBTA_AV_API_OPEN_RC *p_buf; + + if ((p_buf = (tBTA_AV_API_OPEN_RC *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN_RC))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_RC_OPEN_EVT; + p_buf->hdr.layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvCloseRc +** +** Description Close an AVRCP connection +** +** Returns void +** +*******************************************************************************/ +void BTA_AvCloseRc(UINT8 rc_handle) +{ + tBTA_AV_API_CLOSE_RC *p_buf; + + if ((p_buf = (tBTA_AV_API_CLOSE_RC *) GKI_getbuf(sizeof(tBTA_AV_API_CLOSE_RC))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_RC_CLOSE_EVT; + p_buf->hdr.layer_specific = rc_handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvMetaRsp +** +** Description Send a Metadata/Advanced Control response. The message contained +** in p_pkt can be composed with AVRC utility functions. +** This function can only be used if AV is enabled with feature +** BTA_AV_FEAT_METADATA. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvMetaRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, + BT_HDR *p_pkt) +{ + tBTA_AV_API_META_RSP *p_buf; + + if ((p_buf = (tBTA_AV_API_META_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_META_RSP)))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_META_RSP_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->rsp_code = rsp_code; + p_buf->p_pkt = p_pkt; + p_buf->is_rsp = TRUE; + p_buf->label = label; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvMetaCmd +** +** Description Send a Metadata/Advanced Control command. The message contained +** in p_pkt can be composed with AVRC utility functions. +** This function can only be used if AV is enabled with feature +** BTA_AV_FEAT_METADATA. +** This message is sent only when the peer supports the TG role. +*8 The only command makes sense right now is the absolute volume command. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvMetaCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CMD cmd_code, BT_HDR *p_pkt) +{ + tBTA_AV_API_META_RSP *p_buf; + + if ((p_buf = (tBTA_AV_API_META_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_META_RSP)))) != NULL) + { + p_buf->hdr.event = BTA_AV_API_META_RSP_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->p_pkt = p_pkt; + p_buf->rsp_code = cmd_code; + p_buf->is_rsp = FALSE; + p_buf->label = label; + + bta_sys_sendmsg(p_buf); + } +} + +#endif /* BTA_AV_INCLUDED */ diff --git a/bta/av/bta_av_cfg.c b/bta/av/bta_av_cfg.c new file mode 100644 index 0000000..793c772 --- /dev/null +++ b/bta/av/bta_av_cfg.c @@ -0,0 +1,231 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains compile-time configurable constants for advanced + * audio/video + * + ******************************************************************************/ + +#include "bt_target.h" +#include "gki.h" +#include "bta_api.h" +#include "bta_av_int.h" + + + +#ifndef BTA_AV_RC_PASS_RSP_CODE +#define BTA_AV_RC_PASS_RSP_CODE BTA_AV_RSP_NOT_IMPL +#endif + + +const UINT32 bta_av_meta_caps_co_ids[] = { + AVRC_CO_METADATA, + AVRC_CO_BROADCOM +}; + +/* AVRCP cupported categories */ +#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2) + + +/* Added to modify +** 1. flush timeout +** 2. Remove Group navigation support in SupportedFeatures +** 3. GetCapabilities supported event_ids list +** 4. GetCapabilities supported event_ids count +*/ +#ifdef ANDROID_APP_INCLUDED +/* Flushing partial avdtp packets can cause some headsets to disconnect the link + if receiving partial a2dp frames */ +const UINT16 bta_av_audio_flush_to[] = { + 0, /* 1 stream */ + 0, /* 2 streams */ + 0, /* 3 streams */ + 0, /* 4 streams */ + 0 /* 5 streams */ +}; /* AVDTP audio transport channel flush timeout */ + +/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI */ +#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1) + + +/* + * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed. + */ +const UINT8 bta_av_meta_caps_evt_ids[] = { + AVRC_EVT_PLAY_STATUS_CHANGE, + AVRC_EVT_TRACK_CHANGE, + AVRC_EVT_PLAY_POS_CHANGED, + AVRC_EVT_APP_SETTING_CHANGE, +}; +#ifndef BTA_AV_NUM_RC_EVT_IDS +#define BTA_AV_NUM_RC_EVT_IDS (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0])) +#endif /* BTA_AV_NUM_RC_EVT_IDS */ + + +#else /* !ANDROID_APP_INCLUDED */ + +/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */ +#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1) + +const UINT16 bta_av_audio_flush_to[] = { + 120, /* 1 stream */ + 100, /* 2 streams */ + 80, /* 3 streams */ + 60, /* 4 streams */ + 40 /* 5 streams */ +}; /* AVDTP audio transport channel flush timeout */ + + +/* + * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed. + */ +const UINT8 bta_av_meta_caps_evt_ids[] = { + AVRC_EVT_PLAY_STATUS_CHANGE, + AVRC_EVT_TRACK_CHANGE, + AVRC_EVT_TRACK_REACHED_END, + AVRC_EVT_TRACK_REACHED_START, + AVRC_EVT_PLAY_POS_CHANGED, + AVRC_EVT_BATTERY_STATUS_CHANGE, + AVRC_EVT_SYSTEM_STATUS_CHANGE, + AVRC_EVT_APP_SETTING_CHANGE, +}; + +#ifndef BTA_AV_NUM_RC_EVT_IDS +#define BTA_AV_NUM_RC_EVT_IDS 8 +#endif + +#endif /* ANDROID_APP_INCLUDED */ + +/* the MTU for the AVRCP browsing channel */ +#ifndef BTA_AV_MAX_RC_BR_MTU +#define BTA_AV_MAX_RC_BR_MTU 1008 +#endif + +const tBTA_AV_CFG bta_av_cfg = +{ + AVRC_CO_BROADCOM, /* AVRCP Company ID */ + 48, /* AVRCP MTU at L2CAP for control channel */ + BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */ + BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */ + BTA_AV_RC_SUPF_TG, /* AVRCP target categories */ + 672, /* AVDTP signaling channel MTU at L2CAP */ + BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */ + bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */ + 6, /* AVDTP audio channel max data queue size */ + BTA_AV_MAX_VDP_MTU, /* AVDTP video transport channel MTU at L2CAP */ + 600, /* AVDTP video transport channel flush timeout */ + TRUE, /* TRUE, to accept AVRC 1.3 group nevigation command */ + 2, /* company id count in p_meta_co_ids */ + BTA_AV_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */ + BTA_AV_RC_PASS_RSP_CODE,/* the default response code for pass through commands */ + bta_av_meta_caps_co_ids,/* the metadata Get Capabilities response for company id */ + bta_av_meta_caps_evt_ids,/* the the metadata Get Capabilities response for event id */ +}; + +tBTA_AV_CFG *p_bta_av_cfg = (tBTA_AV_CFG *) &bta_av_cfg; + +const UINT16 bta_av_rc_id[] = +{ + 0x021F, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT, + 4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP, + 8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU, + 12=FAV_MENU, 13=EXIT */ + + 0, /* not used */ + + 0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3, + 4=4, 5=5, 6=6, 7=7, + 8=8, 9=9, 10=DOT, 11=ENTER, + 12=CLEAR */ + + 0x0003, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL, + 4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP, + 8=PAGE_DOWN */ + +#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM) + /* btui_app provides an example of how to leave the decision of rejecting a command or not + * based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later) + * If the decision is per player for a particular rc_id, the related bit is clear (not set) */ + 0x0070, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, + 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, + 12=BACKWARD */ +#else +#if (defined BTA_AVRCP_FF_RW_SUPPORT) && (BTA_AVRCP_FF_RW_SUPPORT == TRUE) + 0x1b70, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, + 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, + 12=BACKWARD */ +#else + 0x1870, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, + 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, + 12=BACKWARD */ +#endif +#endif + + 0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */ + + 0, /* not used */ + + 0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3, + 4=F4, 5=F5 */ +}; + +#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM) +const UINT16 bta_av_rc_id_ac[] = +{ + 0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT, + 4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP, + 8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU, + 12=FAV_MENU, 13=EXIT */ + + 0, /* not used */ + + 0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3, + 4=4, 5=5, 6=6, 7=7, + 8=8, 9=9, 10=DOT, 11=ENTER, + 12=CLEAR */ + + 0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL, + 4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP, + 8=PAGE_DOWN */ + + /* btui_app provides an example of how to leave the decision of rejecting a command or not + * based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later) + * If the decision is per player for a particular rc_id, the related bit is set */ + 0x1800, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, + 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, + 12=BACKWARD */ + + 0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */ + + 0, /* not used */ + + 0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3, + 4=F4, 5=F5 */ +}; +UINT16 *p_bta_av_rc_id_ac = (UINT16 *) bta_av_rc_id_ac; +#else +UINT16 *p_bta_av_rc_id_ac = NULL; +#endif + +UINT16 *p_bta_av_rc_id = (UINT16 *) bta_av_rc_id; diff --git a/bta/av/bta_av_ci.c b/bta/av/bta_av_ci.c new file mode 100644 index 0000000..a1c2ac0 --- /dev/null +++ b/bta/av/bta_av_ci.c @@ -0,0 +1,98 @@ +/****************************************************************************** + * + * Copyright (C) 2005-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 advanced audio/video call-in + * functions. + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_av_int.h" +#include "bta_av_ci.h" + +#include <string.h> + +/******************************************************************************* +** +** Function bta_av_ci_src_data_ready +** +** Description This function sends an event to the AV indicating that +** the phone has audio stream data ready to send and AV +** should call bta_av_co_audio_src_data_path() or +** bta_av_co_video_src_data_path(). +** +** Returns void +** +*******************************************************************************/ +void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->layer_specific = chnl; + p_buf->event = BTA_AV_CI_SRC_DATA_READY_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_av_ci_setconfig +** +** Description This function must be called in response to function +** bta_av_co_audio_setconfig() or bta_av_co_video_setconfig. +** Parameter err_code is set to an AVDTP status value; +** AVDT_SUCCESS if the codec configuration is ok, +** otherwise error. +** +** Returns void +** +*******************************************************************************/ +void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, UINT8 category, + UINT8 num_seid, UINT8 *p_seid, BOOLEAN recfg_needed) +{ + tBTA_AV_CI_SETCONFIG *p_buf; + + if ((p_buf = (tBTA_AV_CI_SETCONFIG *) GKI_getbuf(sizeof(tBTA_AV_CI_SETCONFIG))) != NULL) + { + p_buf->hdr.layer_specific = hndl; + p_buf->hdr.event = (err_code == AVDT_SUCCESS) ? + BTA_AV_CI_SETCONFIG_OK_EVT : BTA_AV_CI_SETCONFIG_FAIL_EVT; + p_buf->err_code = err_code; + p_buf->category = category; + p_buf->recfg_needed = recfg_needed; + p_buf->num_seid = num_seid; + if(p_seid && num_seid) + { + p_buf->p_seid = (UINT8 *)(p_buf + 1); + memcpy(p_buf->p_seid, p_seid, num_seid); + } + else + { + p_buf->p_seid = NULL; + p_buf->num_seid = 0; + } + + bta_sys_sendmsg(p_buf); + } +} + diff --git a/bta/av/bta_av_int.h b/bta/av/bta_av_int.h new file mode 100644 index 0000000..05eb114 --- /dev/null +++ b/bta/av/bta_av_int.h @@ -0,0 +1,719 @@ +/****************************************************************************** + * + * 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 private interface file for the BTA advanced audio/video. + * + ******************************************************************************/ +#ifndef BTA_AV_INT_H +#define BTA_AV_INT_H + +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_av_api.h" +#include "avdt_api.h" +#include "bta_av_co.h" + +#define BTA_AV_DEBUG TRUE +/***************************************************************************** +** Constants +*****************************************************************************/ + +enum +{ + /* these events are handled by the AV main state machine */ + BTA_AV_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_AV), + BTA_AV_API_REMOTE_CMD_EVT, + BTA_AV_API_VENDOR_CMD_EVT, + BTA_AV_API_VENDOR_RSP_EVT, + BTA_AV_API_META_RSP_EVT, + BTA_AV_API_RC_CLOSE_EVT, + BTA_AV_AVRC_OPEN_EVT, + BTA_AV_AVRC_MSG_EVT, + BTA_AV_AVRC_NONE_EVT, + + /* these events are handled by the AV stream state machine */ + BTA_AV_API_OPEN_EVT, + BTA_AV_API_CLOSE_EVT, + BTA_AV_AP_START_EVT, /* the following 2 events must be in the same order as the *API_*EVT */ + BTA_AV_AP_STOP_EVT, + BTA_AV_API_RECONFIG_EVT, + BTA_AV_API_PROTECT_REQ_EVT, + BTA_AV_API_PROTECT_RSP_EVT, + BTA_AV_API_RC_OPEN_EVT, + BTA_AV_SRC_DATA_READY_EVT, + BTA_AV_CI_SETCONFIG_OK_EVT, + BTA_AV_CI_SETCONFIG_FAIL_EVT, + BTA_AV_SDP_DISC_OK_EVT, + BTA_AV_SDP_DISC_FAIL_EVT, + BTA_AV_STR_DISC_OK_EVT, + BTA_AV_STR_DISC_FAIL_EVT, + BTA_AV_STR_GETCAP_OK_EVT, + BTA_AV_STR_GETCAP_FAIL_EVT, + BTA_AV_STR_OPEN_OK_EVT, + BTA_AV_STR_OPEN_FAIL_EVT, + BTA_AV_STR_START_OK_EVT, + BTA_AV_STR_START_FAIL_EVT, + BTA_AV_STR_CLOSE_EVT, + BTA_AV_STR_CONFIG_IND_EVT, + BTA_AV_STR_SECURITY_IND_EVT, + BTA_AV_STR_SECURITY_CFM_EVT, + BTA_AV_STR_WRITE_CFM_EVT, + BTA_AV_STR_SUSPEND_CFM_EVT, + BTA_AV_STR_RECONFIG_CFM_EVT, + BTA_AV_AVRC_TIMER_EVT, + BTA_AV_AVDT_CONNECT_EVT, + BTA_AV_AVDT_DISCONNECT_EVT, + BTA_AV_ROLE_CHANGE_EVT, + BTA_AV_AVDT_DELAY_RPT_EVT, + BTA_AV_ACP_CONNECT_EVT, + + /* these events are handled outside of the state machine */ + BTA_AV_API_ENABLE_EVT, + BTA_AV_API_REGISTER_EVT, + BTA_AV_API_DEREGISTER_EVT, + BTA_AV_API_DISCONNECT_EVT, + BTA_AV_CI_SRC_DATA_READY_EVT, + BTA_AV_SIG_CHG_EVT, + BTA_AV_SIG_TIMER_EVT, + BTA_AV_SDP_AVRC_DISC_EVT, + BTA_AV_AVRC_CLOSE_EVT, + BTA_AV_CONN_CHG_EVT, + BTA_AV_DEREG_COMP_EVT, +#if (AVDT_REPORTING == TRUE) + BTA_AV_AVDT_RPT_CONN_EVT, +#endif + BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as the *AP_*EVT */ + BTA_AV_API_STOP_EVT +}; + +/* events for AV control block state machine */ +#define BTA_AV_FIRST_SM_EVT BTA_AV_API_DISABLE_EVT +#define BTA_AV_LAST_SM_EVT BTA_AV_AVRC_NONE_EVT + +/* events for AV stream control block state machine */ +#define BTA_AV_FIRST_SSM_EVT BTA_AV_API_OPEN_EVT + +/* events that do not go through state machine */ +#define BTA_AV_FIRST_NSM_EVT BTA_AV_API_ENABLE_EVT +#define BTA_AV_LAST_NSM_EVT BTA_AV_API_STOP_EVT + +/* API events passed to both SSMs (by bta_av_api_to_ssm) */ +#define BTA_AV_FIRST_A2S_API_EVT BTA_AV_API_START_EVT +#define BTA_AV_FIRST_A2S_SSM_EVT BTA_AV_AP_START_EVT + +#define BTA_AV_LAST_EVT BTA_AV_API_STOP_EVT + +/* maximum number of SEPS in stream discovery results */ +#define BTA_AV_NUM_SEPS 32 + +/* initialization value for AVRC handle */ +#define BTA_AV_RC_HANDLE_NONE 0xFF + +/* size of database for service discovery */ +#define BTA_AV_DISC_BUF_SIZE 1000 + +/* offset of media type in codec info byte array */ +#define BTA_AV_MEDIA_TYPE_IDX 1 + +/* maximum length of AVDTP security data */ +#define BTA_AV_SECURITY_MAX_LEN 400 + +/* check number of buffers queued at L2CAP when this amount of buffers are queued to L2CAP */ +#define BTA_AV_QUEUE_DATA_CHK_NUM 5 + +/* the number of ACL links with AVDT */ +#define BTA_AV_NUM_LINKS AVDT_NUM_LINKS + +#define BTA_AV_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); } +#define BTA_AV_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;} + +/* these bits are defined for bta_av_cb.multi_av */ +#define BTA_AV_MULTI_AV_SUPPORTED 0x01 +#define BTA_AV_MULTI_AV_IN_USE 0x02 + + +/***************************************************************************** +** Data types +*****************************************************************************/ + +/* function types for call-out functions */ +typedef BOOLEAN (*tBTA_AV_CO_INIT) (UINT8 *p_codec_type, UINT8 *p_codec_info, + UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index); + +typedef void (*tBTA_AV_CO_DISC_RES) (tBTA_AV_HNDL hndl, UINT8 num_seps, + UINT8 num_snk, BD_ADDR addr); + +typedef UINT8 (*tBTA_AV_CO_GETCFG) (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); +typedef void (*tBTA_AV_CO_SETCFG) (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); +typedef void (*tBTA_AV_CO_OPEN) (tBTA_AV_HNDL hndl, + tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu); +typedef void (*tBTA_AV_CO_CLOSE) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu); +typedef void (*tBTA_AV_CO_START) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); +typedef void (*tBTA_AV_CO_STOP) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); +typedef void * (*tBTA_AV_CO_DATAPATH) (tBTA_AV_CODEC codec_type, + UINT32 *p_len, UINT32 *p_timestamp); +typedef void (*tBTA_AV_CO_DELAY) (tBTA_AV_HNDL hndl, UINT16 delay); + +/* the call-out functions for one stream */ +typedef struct +{ + tBTA_AV_CO_INIT init; + tBTA_AV_CO_DISC_RES disc_res; + tBTA_AV_CO_GETCFG getcfg; + tBTA_AV_CO_SETCFG setcfg; + tBTA_AV_CO_OPEN open; + tBTA_AV_CO_CLOSE close; + tBTA_AV_CO_START start; + tBTA_AV_CO_STOP stop; + tBTA_AV_CO_DATAPATH data; + tBTA_AV_CO_DELAY delay; +} tBTA_AV_CO_FUNCTS; + +/* data type for BTA_AV_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_AV_CBACK *p_cback; + tBTA_AV_FEAT features; + tBTA_SEC sec_mask; +} tBTA_AV_API_ENABLE; + +/* data type for BTA_AV_API_REG_EVT */ +typedef struct +{ + BT_HDR hdr; + char p_service_name[BTA_SERVICE_NAME_LEN+1]; + UINT8 app_id; +} tBTA_AV_API_REG; + + +enum +{ + BTA_AV_RS_NONE, /* straight API call */ + BTA_AV_RS_OK, /* the role switch result - successful */ + BTA_AV_RS_FAIL, /* the role switch result - failed */ + BTA_AV_RS_DONE /* the role switch is done - continue */ +}; +typedef UINT8 tBTA_AV_RS_RES; +/* data type for BTA_AV_API_OPEN_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN use_rc; + tBTA_SEC sec_mask; + tBTA_AV_RS_RES switch_res; +} tBTA_AV_API_OPEN; + +/* data type for BTA_AV_API_STOP_EVT */ +typedef struct +{ + BT_HDR hdr; + BOOLEAN suspend; + BOOLEAN flush; +} tBTA_AV_API_STOP; + +/* data type for BTA_AV_API_DISCONNECT_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_AV_API_DISCNT; + +/* data type for BTA_AV_API_PROTECT_REQ_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 *p_data; + UINT16 len; +} tBTA_AV_API_PROTECT_REQ; + +/* data type for BTA_AV_API_PROTECT_RSP_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 *p_data; + UINT16 len; + UINT8 error_code; +} tBTA_AV_API_PROTECT_RSP; + +/* data type for BTA_AV_API_REMOTE_CMD_EVT */ +typedef struct +{ + BT_HDR hdr; + tAVRC_MSG_PASS msg; + UINT8 label; +} tBTA_AV_API_REMOTE_CMD; + +/* data type for BTA_AV_API_VENDOR_CMD_EVT and RSP */ +typedef struct +{ + BT_HDR hdr; + tAVRC_MSG_VENDOR msg; + UINT8 label; +} tBTA_AV_API_VENDOR; + +/* data type for BTA_AV_API_RC_OPEN_EVT */ +typedef struct +{ + BT_HDR hdr; +} tBTA_AV_API_OPEN_RC; + +/* data type for BTA_AV_API_RC_CLOSE_EVT */ +typedef struct +{ + BT_HDR hdr; +} tBTA_AV_API_CLOSE_RC; + +/* data type for BTA_AV_API_META_RSP_EVT */ +typedef struct +{ + BT_HDR hdr; + BOOLEAN is_rsp; + UINT8 label; + tBTA_AV_CODE rsp_code; + BT_HDR *p_pkt; +} tBTA_AV_API_META_RSP; + + +/* data type for BTA_AV_API_RECONFIG_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 codec_info[AVDT_CODEC_SIZE]; /* codec configuration */ + UINT8 *p_protect_info; + UINT8 num_protect; + BOOLEAN suspend; + UINT8 sep_info_idx; +} tBTA_AV_API_RCFG; + +/* data type for BTA_AV_CI_SETCONFIG_OK_EVT and BTA_AV_CI_SETCONFIG_FAIL_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_AV_HNDL hndl; + UINT8 err_code; + UINT8 category; + UINT8 num_seid; + UINT8 *p_seid; + BOOLEAN recfg_needed; +} tBTA_AV_CI_SETCONFIG; + +/* data type for all stream events from AVDTP */ +typedef struct { + BT_HDR hdr; + tAVDT_CFG cfg; /* configuration/capabilities parameters */ + tAVDT_CTRL msg; /* AVDTP callback message parameters */ + BD_ADDR bd_addr; /* bd address */ + UINT8 handle; + UINT8 avdt_event; + BOOLEAN initiator; /* TRUE, if local device initiates the SUSPEND */ +} tBTA_AV_STR_MSG; + +/* data type for BTA_AV_AVRC_MSG_EVT */ +typedef struct +{ + BT_HDR hdr; + tAVRC_MSG msg; + UINT8 handle; + UINT8 label; + UINT8 opcode; +} tBTA_AV_RC_MSG; + +/* data type for BTA_AV_AVRC_OPEN_EVT, BTA_AV_AVRC_CLOSE_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR peer_addr; + UINT8 handle; +} tBTA_AV_RC_CONN_CHG; + +/* data type for BTA_AV_CONN_CHG_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR peer_addr; + BOOLEAN is_up; +} tBTA_AV_CONN_CHG; + +/* data type for BTA_AV_ROLE_CHANGE_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 new_role; + UINT8 hci_status; +} tBTA_AV_ROLE_RES; + +/* data type for BTA_AV_SDP_DISC_OK_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 avdt_version; /* AVDTP protocol version */ +} tBTA_AV_SDP_RES; + +/* type for SEP control block */ +typedef struct +{ + UINT8 av_handle; /* AVDTP handle */ + tBTA_AV_CODEC codec_type; /* codec type */ +} tBTA_AV_SEP; + + +/* initiator/acceptor role for adaption */ +#define BTA_AV_ROLE_AD_INT 0x00 /* initiator */ +#define BTA_AV_ROLE_AD_ACP 0x01 /* acceptor */ + +/* initiator/acceptor signaling roles */ +#define BTA_AV_ROLE_START_ACP 0x00 +#define BTA_AV_ROLE_START_INT 0x10 /* do not change this value */ + +#define BTA_AV_ROLE_SUSPEND 0x20 /* suspending on start */ +#define BTA_AV_ROLE_SUSPEND_OPT 0x40 /* Suspend on Start option is set */ + +/* union of all event datatypes */ +typedef union +{ + BT_HDR hdr; + tBTA_AV_API_ENABLE api_enable; + tBTA_AV_API_REG api_reg; + tBTA_AV_API_OPEN api_open; + tBTA_AV_API_STOP api_stop; + tBTA_AV_API_DISCNT api_discnt; + tBTA_AV_API_PROTECT_REQ api_protect_req; + tBTA_AV_API_PROTECT_RSP api_protect_rsp; + tBTA_AV_API_REMOTE_CMD api_remote_cmd; + tBTA_AV_API_VENDOR api_vendor; + tBTA_AV_API_RCFG api_reconfig; + tBTA_AV_CI_SETCONFIG ci_setconfig; + tBTA_AV_STR_MSG str_msg; + tBTA_AV_RC_MSG rc_msg; + tBTA_AV_RC_CONN_CHG rc_conn_chg; + tBTA_AV_CONN_CHG conn_chg; + tBTA_AV_ROLE_RES role_res; + tBTA_AV_SDP_RES sdp_res; + tBTA_AV_API_META_RSP api_meta_rsp; +} tBTA_AV_DATA; + +typedef void (tBTA_AV_VDP_DATA_ACT)(void *p_scb); + +typedef struct +{ + tBTA_AV_VDP_DATA_ACT *p_act; + UINT8 *p_frame; + UINT16 buf_size; + UINT32 len; + UINT32 offset; + UINT32 timestamp; +} tBTA_AV_VF_INFO; + +typedef union +{ + BUFFER_Q a2d; /* used for audio channels only */ + tBTA_AV_VF_INFO vdp; /* used for video channels only */ + tBTA_AV_API_OPEN open; /* used only before open and role switch + is needed on another AV channel */ +} tBTA_AV_Q_INFO; + +#define BTA_AV_Q_TAG_OPEN 0x01 /* after API_OPEN, before STR_OPENED */ +#define BTA_AV_Q_TAG_START 0x02 /* before start sending media packets */ +#define BTA_AV_Q_TAG_STREAM 0x03 /* during streaming */ + +#define BTA_AV_WAIT_ACP_CAPS_ON 0x01 /* retriving the peer capabilities */ +#define BTA_AV_WAIT_ACP_CAPS_STARTED 0x02 /* started while retriving peer capabilities */ +#define BTA_AV_WAIT_ROLE_SW_RES_OPEN 0x04 /* waiting for role switch result after API_OPEN, before STR_OPENED */ +#define BTA_AV_WAIT_ROLE_SW_RES_START 0x08 /* waiting for role switch result before streaming */ +#define BTA_AV_WAIT_ROLE_SW_STARTED 0x10 /* started while waiting for role switch result */ +#define BTA_AV_WAIT_ROLE_SW_RETRY 0x20 /* set when retry on timeout */ +#define BTA_AV_WAIT_CHECK_RC 0x40 /* set when the timer is used by role switch */ +#define BTA_AV_WAIT_ROLE_SW_FAILED 0x80 /* role switch failed */ + +#define BTA_AV_WAIT_ROLE_SW_BITS (BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START|BTA_AV_WAIT_ROLE_SW_STARTED|BTA_AV_WAIT_ROLE_SW_RETRY) + +/* Bitmap for collision, coll_mask */ +#define BTA_AV_COLL_INC_TMR 0x01 /* Timer is running for incoming L2C connection */ +#define BTA_AV_COLL_API_CALLED 0x02 /* API open was called while incoming timer is running */ + +/* type for AV stream control block */ +typedef struct +{ + const tBTA_AV_ACT *p_act_tbl; /* the action table for stream state machine */ + const tBTA_AV_CO_FUNCTS *p_cos; /* the associated callout functions */ + tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */ + tBTA_AV_SEP seps[BTA_AV_MAX_SEPS]; + tAVDT_CFG *p_cap; /* buffer used for get capabilities */ + tBTA_AV_Q_INFO q_info; + tAVDT_SEP_INFO sep_info[BTA_AV_NUM_SEPS]; /* stream discovery results */ + tAVDT_CFG cfg; /* local SEP configuration */ + TIMER_LIST_ENT timer; /* delay timer for AVRC CT */ + BD_ADDR peer_addr; /* peer BD address */ + UINT16 l2c_cid; /* L2CAP channel ID */ + UINT16 stream_mtu; /* MTU of stream */ + UINT16 avdt_version; /* the avdt version of peer device */ + tBTA_SEC sec_mask; /* security mask */ + tBTA_AV_CODEC codec_type; /* codec type */ + UINT8 media_type; /* Media type */ + BOOLEAN cong; /* TRUE if AVDTP congested */ + tBTA_AV_STATUS open_status; /* open failure status */ + tBTA_AV_CHNL chnl; /* the channel: audio/video */ + tBTA_AV_HNDL hndl; /* the handle: ((hdi + 1)|chnl) */ + UINT16 cur_psc_mask; /* Protocol service capabilities mask for current connection */ + UINT8 avdt_handle; /* AVDTP handle */ + UINT8 hdi; /* the index to SCB[] */ + UINT8 num_seps; /* number of seps returned by stream discovery */ + UINT8 num_disc_snks; /* number of discovered snks */ + UINT8 sep_info_idx; /* current index into sep_info */ + UINT8 sep_idx; /* current index into local seps[] */ + UINT8 rcfg_idx; /* reconfig requested index into sep_info */ + UINT8 state; /* state machine state */ + UINT8 avdt_label; /* AVDTP label */ + UINT8 app_id; /* application id */ + UINT8 num_recfg; /* number of reconfigure sent */ + UINT8 role; + UINT8 l2c_bufs; /* the number of buffers queued to L2CAP */ + UINT8 rc_handle; /* connected AVRCP handle */ + BOOLEAN use_rc; /* TRUE if AVRCP is allowed */ + BOOLEAN started; /* TRUE if stream started */ + UINT8 co_started; /* non-zero, if stream started from call-out perspective */ + BOOLEAN recfg_sup; /* TRUE if the first attempt to reconfigure the stream was successfull, else False if command fails */ + BOOLEAN suspend_sup; /* TRUE if Suspend stream is supported, else FALSE if suspend command fails */ + BOOLEAN deregistring; /* TRUE if deregistering */ + BOOLEAN sco_suspend; /* TRUE if SUSPEND is issued automatically for SCO */ + UINT8 coll_mask; /* Mask to check incoming and outgoing collision */ + tBTA_AV_API_OPEN open_api; /* Saved OPEN api message */ + UINT8 wait; /* set 0x1, when getting Caps as ACP, set 0x2, when started */ + UINT8 q_tag; /* identify the associated q_info union member */ +} tBTA_AV_SCB; + +#define BTA_AV_RC_ROLE_MASK 0x10 +#define BTA_AV_RC_ROLE_INT 0x00 +#define BTA_AV_RC_ROLE_ACP 0x10 + +#define BTA_AV_RC_CONN_MASK 0x20 + +/* type for AV RCP control block */ +/* index to this control block is the rc handle */ +typedef struct +{ + UINT8 status; + UINT8 handle; + UINT8 shdl; /* stream handle (hdi + 1) */ + UINT8 lidx; /* (index+1) to LCB */ + tBTA_AV_FEAT peer_features; /* peer features mask */ +} tBTA_AV_RCB; +#define BTA_AV_NUM_RCB (BTA_AV_NUM_STRS + 2) + +enum +{ + BTA_AV_LCB_FREE, + BTA_AV_LCB_FIND +}; + +/* type for AV ACL Link control block */ +typedef struct +{ + BD_ADDR addr; /* peer BD address */ + UINT8 conn_msk; /* handle mask of connected stream handle */ + UINT8 lidx; /* index + 1 */ +} tBTA_AV_LCB; + +/* type for stream state machine action functions */ +typedef void (*tBTA_AV_SACT)(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); + + +/* type for AV control block */ +typedef struct +{ + tBTA_AV_SCB *p_scb[BTA_AV_NUM_STRS]; /* stream control block */ + tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */ + tBTA_AV_CBACK *p_cback; /* application callback function */ + tBTA_AV_RCB rcb[BTA_AV_NUM_RCB]; /* RCB control block */ + tBTA_AV_LCB lcb[BTA_AV_NUM_LINKS+1]; /* link control block */ + TIMER_LIST_ENT sig_tmr; /* link timer */ + TIMER_LIST_ENT acp_sig_tmr; /* timer to monitor signalling when accepting */ + UINT32 sdp_a2d_handle; /* SDP record handle for audio src */ + UINT32 sdp_vdp_handle; /* SDP record handle for video src */ + tBTA_AV_FEAT features; /* features mask */ + tBTA_SEC sec_mask; /* security mask */ + tBTA_AV_HNDL handle; /* the handle for SDP activity */ + BOOLEAN disabling; /* TRUE if api disabled called */ + UINT8 disc; /* (hdi+1) or (rc_handle|BTA_AV_CHNL_MSK) if p_disc_db is in use */ + UINT8 state; /* state machine state */ + UINT8 conn_rc; /* handle mask of connected RCP channels */ + UINT8 conn_audio; /* handle mask of connected audio channels */ + UINT8 conn_video; /* handle mask of connected video channels */ + UINT8 conn_lcb; /* index mask of used LCBs */ + UINT8 audio_open_cnt; /* number of connected audio channels */ + UINT8 reg_audio; /* handle mask of registered audio channels */ + UINT8 reg_video; /* handle mask of registered video channels */ + UINT8 rc_acp_handle; + UINT8 rc_acp_idx; /* (index + 1) to RCB */ + UINT8 rs_idx; /* (index + 1) to SCB for the one waiting for RS on open */ + BOOLEAN sco_occupied; /* TRUE if SCO is being used or call is in progress */ + UINT8 audio_streams; /* handle mask of streaming audio channels */ + UINT8 video_streams; /* handle mask of streaming video channels */ +} tBTA_AV_CB; + + + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* control block declaration */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_AV_CB bta_av_cb; +#else +extern tBTA_AV_CB *bta_av_cb_ptr; +#define bta_av_cb (*bta_av_cb_ptr) +#endif + +/* config struct */ +extern tBTA_AV_CFG *p_bta_av_cfg; + +/* rc id config struct */ +extern UINT16 *p_bta_av_rc_id; +extern UINT16 *p_bta_av_rc_id_ac; + +extern const tBTA_AV_SACT bta_av_a2d_action[]; +extern const tBTA_AV_CO_FUNCTS bta_av_a2d_cos; +extern const tBTA_AV_SACT bta_av_vdp_action[]; +extern tAVDT_CTRL_CBACK * const bta_av_dt_cback[]; + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +/* utility functions */ +extern tBTA_AV_SCB *bta_av_hndl_to_scb(UINT16 handle); +extern BOOLEAN bta_av_chk_start(tBTA_AV_SCB *p_scb); +extern void bta_av_restore_switch (void); +extern UINT16 bta_av_chk_mtu(tBTA_AV_SCB *p_scb, UINT16 mtu); +extern void bta_av_conn_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +extern UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx); +extern void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data, int index); +extern void bta_av_stream_chg(tBTA_AV_SCB *p_scb, BOOLEAN started); +extern BOOLEAN bta_av_is_scb_opening (tBTA_AV_SCB *p_scb); +extern BOOLEAN bta_av_is_scb_incoming (tBTA_AV_SCB *p_scb); +extern void bta_av_set_scb_sst_init (tBTA_AV_SCB *p_scb); +extern BOOLEAN bta_av_is_scb_init (tBTA_AV_SCB *p_scb); +extern void bta_av_set_scb_sst_incoming (tBTA_AV_SCB *p_scb); +extern tBTA_AV_LCB * bta_av_find_lcb(BD_ADDR addr, UINT8 op); + + +/* main functions */ +extern void bta_av_api_deregister(tBTA_AV_DATA *p_data); +extern void bta_av_dup_audio_buf(tBTA_AV_SCB *p_scb, BT_HDR *p_buf); +extern void bta_av_sm_execute(tBTA_AV_CB *p_cb, UINT16 event, tBTA_AV_DATA *p_data); +extern void bta_av_ssm_execute(tBTA_AV_SCB *p_scb, UINT16 event, tBTA_AV_DATA *p_data); +extern BOOLEAN bta_av_hdl_event(BT_HDR *p_msg); +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +extern char *bta_av_evt_code(UINT16 evt_code); +#endif +extern BOOLEAN bta_av_switch_if_needed(tBTA_AV_SCB *p_scb); +extern BOOLEAN bta_av_link_role_ok(tBTA_AV_SCB *p_scb, UINT8 bits); +extern BOOLEAN bta_av_is_rcfg_sst(tBTA_AV_SCB *p_scb); + +/* nsm action functions */ +extern void bta_av_api_disconnect(tBTA_AV_DATA *p_data); +extern void bta_av_sig_chg(tBTA_AV_DATA *p_data); +extern void bta_av_sig_timer(tBTA_AV_DATA *p_data); +extern void bta_av_rc_disc_done(tBTA_AV_DATA *p_data); +extern void bta_av_rc_closed(tBTA_AV_DATA *p_data); +extern void bta_av_rc_disc(UINT8 disc); +extern void bta_av_conn_chg(tBTA_AV_DATA *p_data); +extern void bta_av_dereg_comp(tBTA_AV_DATA *p_data); + +/* sm action functions */ +extern void bta_av_disable (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_opened (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_remote_cmd (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_vendor_cmd (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_vendor_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_meta_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); + +extern tBTA_AV_RCB * bta_av_get_rcb_by_shdl(UINT8 shdl); +extern void bta_av_del_rc(tBTA_AV_RCB *p_rcb); + +/* ssm action functions */ +extern void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_cleanup (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_free_sdb (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_disconnect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_discover_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_conn_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_do_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_reconfig (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_start_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_clr_cong (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_str_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_connect (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_discntd (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_open_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_chk_2nd_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_save_caps (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rej_conn (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rej_conn (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_set_use_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_switch_role (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); + +/* ssm action functions - vdp specific */ +extern void bta_av_do_disc_vdp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_vdp_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_reg_vdp (tAVDT_CS *p_cs, char *p_service_name, void *p_data); + +#endif /* BTA_AV_INT_H */ diff --git a/bta/av/bta_av_main.c b/bta/av/bta_av_main.c new file mode 100644 index 0000000..085362d --- /dev/null +++ b/bta/av/bta_av_main.c @@ -0,0 +1,1323 @@ +/****************************************************************************** + * + * 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 main implementation file for the BTA advanced audio/video. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#include <string.h> +#include "bta_av_int.h" +#include "utl.h" +#include "bd.h" +#include "l2c_api.h" +#include "l2cdefs.h" +#include "bta_av_co.h" +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#include "bta_ar_api.h" +#endif + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +/* AVDTP protocol timeout values */ +#ifndef BTA_AV_RET_TOUT +#define BTA_AV_RET_TOUT 4 +#endif + +#ifndef BTA_AV_SIG_TOUT +#define BTA_AV_SIG_TOUT 4 +#endif + +#ifndef BTA_AV_IDLE_TOUT +#define BTA_AV_IDLE_TOUT 10 +#endif + +/* the delay time in milliseconds to retry role switch */ +#ifndef BTA_AV_RS_TIME_VAL +#define BTA_AV_RS_TIME_VAL 1000 +#endif + +/* state machine states */ +enum +{ + BTA_AV_INIT_ST, + BTA_AV_OPEN_ST +}; + +/* state machine action enumeration list */ +enum +{ + BTA_AV_DISABLE, + BTA_AV_RC_OPENED, + BTA_AV_RC_REMOTE_CMD, + BTA_AV_RC_VENDOR_CMD, + BTA_AV_RC_VENDOR_RSP, + BTA_AV_RC_FREE_RSP, + BTA_AV_RC_FREE_MSG, + BTA_AV_RC_META_RSP, + BTA_AV_RC_MSG, + BTA_AV_RC_CLOSE, + BTA_AV_NUM_ACTIONS +}; + +#define BTA_AV_IGNORE BTA_AV_NUM_ACTIONS + +/* type for action functions */ +typedef void (*tBTA_AV_ACTION)(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); + +/* action functions */ +const tBTA_AV_ACTION bta_av_action[] = +{ + bta_av_disable, + bta_av_rc_opened, + bta_av_rc_remote_cmd, + bta_av_rc_vendor_cmd, + bta_av_rc_vendor_rsp, + bta_av_rc_free_rsp, + bta_av_rc_free_msg, + bta_av_rc_meta_rsp, + bta_av_rc_msg, + bta_av_rc_close, + NULL +}; + +/* state table information */ +#define BTA_AV_ACTION_COL 0 /* position of actions */ +#define BTA_AV_NEXT_STATE 1 /* position of next state */ +#define BTA_AV_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for init state */ +static const UINT8 bta_av_st_init[][BTA_AV_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST }, +/* API_REMOTE_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, +/* API_VENDOR_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, +/* API_VENDOR_RSP_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, +/* API_META_RSP_EVT */ {BTA_AV_RC_FREE_RSP, BTA_AV_INIT_ST }, +/* API_RC_CLOSE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, +/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST }, +/* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_MSG, BTA_AV_INIT_ST }, +/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, +}; + +/* state table for open state */ +static const UINT8 bta_av_st_open[][BTA_AV_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST }, +/* API_REMOTE_CMD_EVT */ {BTA_AV_RC_REMOTE_CMD, BTA_AV_OPEN_ST }, +/* API_VENDOR_CMD_EVT */ {BTA_AV_RC_VENDOR_CMD, BTA_AV_OPEN_ST }, +/* API_VENDOR_RSP_EVT */ {BTA_AV_RC_VENDOR_RSP, BTA_AV_OPEN_ST }, +/* API_META_RSP_EVT */ {BTA_AV_RC_META_RSP, BTA_AV_OPEN_ST }, +/* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_OPEN_ST }, +/* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST }, +/* AVRC_MSG_EVT */ {BTA_AV_RC_MSG, BTA_AV_OPEN_ST }, +/* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_AV_ST_TBL)[BTA_AV_NUM_COLS]; + +/* state table */ +static const tBTA_AV_ST_TBL bta_av_st_tbl[] = +{ + bta_av_st_init, + bta_av_st_open +}; + +typedef void (*tBTA_AV_NSM_ACT)(tBTA_AV_DATA *p_data); +static void bta_av_api_enable(tBTA_AV_DATA *p_data); +static void bta_av_api_register(tBTA_AV_DATA *p_data); +static void bta_av_ci_data(tBTA_AV_DATA *p_data); +#if (AVDT_REPORTING == TRUE) +static void bta_av_rpc_conn(tBTA_AV_DATA *p_data); +#endif +static void bta_av_api_to_ssm(tBTA_AV_DATA *p_data); + +static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 + app_id, BD_ADDR peer_addr); +static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr); + + +/* action functions */ +const tBTA_AV_NSM_ACT bta_av_nsm_act[] = +{ + bta_av_api_enable, /* BTA_AV_API_ENABLE_EVT */ + bta_av_api_register, /* BTA_AV_API_REGISTER_EVT */ + bta_av_api_deregister, /* BTA_AV_API_DEREGISTER_EVT */ + bta_av_api_disconnect, /* BTA_AV_API_DISCONNECT_EVT */ + bta_av_ci_data, /* BTA_AV_CI_SRC_DATA_READY_EVT */ + bta_av_sig_chg, /* BTA_AV_SIG_CHG_EVT */ + bta_av_sig_timer, /* BTA_AV_SIG_TIMER_EVT */ + bta_av_rc_disc_done, /* BTA_AV_SDP_AVRC_DISC_EVT */ + bta_av_rc_closed, /* BTA_AV_AVRC_CLOSE_EVT */ + bta_av_conn_chg, /* BTA_AV_CONN_CHG_EVT */ + bta_av_dereg_comp, /* BTA_AV_DEREG_COMP_EVT */ +#if (AVDT_REPORTING == TRUE) + bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */ +#endif + bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */ + bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */ +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* AV control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_AV_CB bta_av_cb; +#endif + +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +static char *bta_av_st_code(UINT8 state); +#endif + +/******************************************************************************* +** +** Function bta_av_timer_cback +** +** Description forward the event to stream state machine +** +** Returns void +** +*******************************************************************************/ +static void bta_av_timer_cback(void *p_tle) +{ + BT_HDR *p_buf; + TIMER_LIST_ENT *p = (TIMER_LIST_ENT *)p_tle; + int xx; + tBTA_AV_SCB *p_scb = NULL; + + /* find the SCB that has the timer */ + for(xx=0; xx<BTA_AV_NUM_STRS; xx++) + { + if(bta_av_cb.p_scb[xx] && &(bta_av_cb.p_scb[xx]->timer)== p) + { + p_scb = bta_av_cb.p_scb[xx]; + break; + } + } + + if (p_scb && (p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + /* send the event through the audio state machine. + * only when the audio SM is open, the main SM opens the RC connection as INT */ + p_buf->event = p->event; + p_buf->layer_specific = p_scb->hndl; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_av_api_enable +** +** Description Handle an API enable event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_av_api_enable(tBTA_AV_DATA *p_data) +{ + int i; + tBTA_AV_ENABLE enable; + + /* initialize control block */ + memset(&bta_av_cb, 0, sizeof(tBTA_AV_CB)); + + for(i=0; i<BTA_AV_NUM_RCB; i++) + bta_av_cb.rcb[i].handle = BTA_AV_RC_HANDLE_NONE; + + bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE; + + /* store parameters */ + bta_av_cb.p_cback = p_data->api_enable.p_cback; + bta_av_cb.features = p_data->api_enable.features; + bta_av_cb.sec_mask = p_data->api_enable.sec_mask; + + enable.features = bta_av_cb.features; + + /* Register for SCO change event */ + if (!(bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD)) + { + bta_sys_sco_register(bta_av_sco_chg_cback); + } + + /* call callback with enable event */ + (*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, (tBTA_AV *)&enable); +} + +/******************************************************************************* +** +** Function bta_av_addr_to_scb +** +** Description find the stream control block by the peer addr +** +** Returns void +** +*******************************************************************************/ +static tBTA_AV_SCB * bta_av_addr_to_scb(BD_ADDR bd_addr) +{ + tBTA_AV_SCB * p_scb = NULL; + int xx; + + for(xx=0; xx<BTA_AV_NUM_STRS; xx++) + { + if(bta_av_cb.p_scb[xx]) + { + if(!bdcmp(bd_addr, bta_av_cb.p_scb[xx]->peer_addr)) + { + p_scb = bta_av_cb.p_scb[xx]; + break; + } + } + } + return p_scb; +} + +/******************************************************************************* +** +** Function bta_av_hndl_to_scb +** +** Description find the stream control block by the handle +** +** Returns void +** +*******************************************************************************/ +tBTA_AV_SCB * bta_av_hndl_to_scb(UINT16 handle) +{ + tBTA_AV_HNDL hndl = (tBTA_AV_HNDL)handle; + tBTA_AV_SCB * p_scb = NULL; + UINT8 idx = (hndl & BTA_AV_HNDL_MSK); + + if(idx && (idx <= BTA_AV_NUM_STRS) ) + { + p_scb = bta_av_cb.p_scb[idx-1]; + } + return p_scb; +} + +/******************************************************************************* +** +** Function bta_av_alloc_scb +** +** Description allocate stream control block, +** register the service to stack +** create SDP record +** +** Returns void +** +*******************************************************************************/ +static tBTA_AV_SCB * bta_av_alloc_scb(tBTA_AV_CHNL chnl) +{ + tBTA_AV_SCB *p_ret = NULL; + int xx; + tBTA_AV_STATUS sts = BTA_AV_SUCCESS; + + if(chnl == BTA_AV_CHNL_VIDEO) + { + if(p_bta_av_cfg->p_act_tbl == NULL || p_bta_av_cfg->p_reg == NULL) + { + APPL_TRACE_ERROR0("Video streaming not supported"); + sts = BTA_AV_FAIL; + } + else + { + /* allow only one Video channel */ + if(bta_av_cb.reg_video) + { + APPL_TRACE_ERROR0("Already registered"); + sts = BTA_AV_FAIL; + } + } + } + else if(chnl != BTA_AV_CHNL_AUDIO) + { + APPL_TRACE_ERROR1("bad channel: %d", chnl); + sts = BTA_AV_FAIL; + } + + if(sts == BTA_AV_SUCCESS) + { + for(xx=0; xx<BTA_AV_NUM_STRS; xx++) + { + if(bta_av_cb.p_scb[xx] == NULL) + { + /* found an empty spot */ + p_ret = (tBTA_AV_SCB *)GKI_getbuf(sizeof(tBTA_AV_SCB)); + if(p_ret) + { + memset(p_ret, 0, sizeof(tBTA_AV_SCB)); + p_ret->rc_handle = BTA_AV_RC_HANDLE_NONE; + p_ret->chnl = chnl; + p_ret->hndl = (tBTA_AV_HNDL)((xx + 1) | chnl); + p_ret->hdi = xx; + bta_av_cb.p_scb[xx] = p_ret; + } + break; + } + } + } + return p_ret; +} + +/******************************************************************************* +*******************************************************************************/ +void bta_av_conn_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + tBTA_AV_STR_MSG *p_msg; + UINT16 evt = 0; + tBTA_AV_SCB *p_scb = NULL; + +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + if (event == BTA_AR_AVDT_CONN_EVT || + event == AVDT_CONNECT_IND_EVT || event == AVDT_DISCONNECT_IND_EVT) +#else + if (event == AVDT_CONNECT_IND_EVT || event == AVDT_DISCONNECT_IND_EVT) +#endif + { + evt = BTA_AV_SIG_CHG_EVT; + if(AVDT_DISCONNECT_IND_EVT == event) + p_scb = bta_av_addr_to_scb(bd_addr); +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + else if (AVDT_CONNECT_IND_EVT == event) + { + APPL_TRACE_DEBUG1("CONN_IND is ACP:%d", p_data->hdr.err_param); + } +#endif + + if (/*((p_scb && (p_scb->role & BTA_AV_ROLE_AD_ACP)) || + + //(AVDT_CONNECT_IND_EVT == event && AVDT_ACP == p_data->hdr.err_param)) + + (AVDT_CONNECT_IND_EVT == event))&& */ + (p_msg = (tBTA_AV_STR_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_STR_MSG)))) != NULL) + { + p_msg->hdr.event = evt; + p_msg->hdr.layer_specific = event; + p_msg->hdr.offset = p_data->hdr.err_param; + bdcpy(p_msg->bd_addr, bd_addr); +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + if(p_scb) + { + APPL_TRACE_DEBUG2("scb hndl x%x, role x%x", p_scb->hndl, p_scb->role); + } +#endif + APPL_TRACE_DEBUG6("conn_cback bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + bd_addr[0], bd_addr[1], + bd_addr[2], bd_addr[3], + bd_addr[4], bd_addr[5]); + bta_sys_sendmsg(p_msg); + } + } + +} + +#if AVDT_REPORTING == TRUE +/******************************************************************************* +** +** Function bta_av_a2dp_report_cback +** +** Description A2DP report callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_a2dp_report_cback(UINT8 handle, AVDT_REPORT_TYPE type, + tAVDT_REPORT_DATA *p_data) +{ + /* Do not need to handle report data for now. + * This empty function is here for conformance reasons. */ +} +#endif + +/******************************************************************************* +** +** Function bta_av_api_register +** +** Description allocate stream control block, +** register the service to stack +** create SDP record +** +** Returns void +** +*******************************************************************************/ +static void bta_av_api_register(tBTA_AV_DATA *p_data) +{ + tBTA_AV_REGISTER registr; + tBTA_AV_SCB *p_scb; /* stream control block */ + tAVDT_REG reg; + tAVDT_CS cs; + char *p_service_name; + tBTA_AV_CODEC codec_type; + tBTA_UTL_COD cod; + UINT8 index = 0; + + memset(&cs,0,sizeof(tAVDT_CS)); + + registr.status = BTA_AV_FAIL_RESOURCES; + registr.app_id = p_data->api_reg.app_id; + registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific; + do + { + p_scb = bta_av_alloc_scb(registr.chnl); + if(p_scb == NULL) + { + APPL_TRACE_ERROR0("failed to alloc SCB"); + break; + } + + registr.hndl = p_scb->hndl; + p_scb->app_id = registr.app_id; + + /* initialize the stream control block */ + p_scb->timer.p_cback = (TIMER_CBACK*)&bta_av_timer_cback; + registr.status = BTA_AV_SUCCESS; + + if((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0) + { + /* the first channel registered. register to AVDTP */ + reg.ctrl_mtu = p_bta_av_cfg->sig_mtu; + reg.ret_tout = BTA_AV_RET_TOUT; + reg.sig_tout = BTA_AV_SIG_TOUT; + reg.idle_tout = BTA_AV_IDLE_TOUT; + reg.sec_mask = bta_av_cb.sec_mask; +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + bta_ar_reg_avdt(®, bta_av_conn_cback, BTA_ID_AV); +#endif + bta_sys_role_chg_register(&bta_av_sys_rs_cback); + + /* create remote control TG service if required */ + if (bta_av_cb.features & (BTA_AV_FEAT_RCTG)) + { + /* register with no authorization; let AVDTP use authorization instead */ +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE) + bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, + bta_av_cb.sec_mask, BTA_ID_AV); +#else + bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, + (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV); +#endif + + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL, + p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV); +#endif + } + + /* Set the Capturing service class bit */ + cod.service = BTM_COD_SERVICE_CAPTURING; + utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); + } /* if 1st channel */ + + /* get stream configuration and create stream */ + /* memset(&cs.cfg,0,sizeof(tAVDT_CFG)); */ + cs.cfg.num_codec = 1; + cs.tsep = AVDT_TSEP_SRC; + + /* + * memset of cs takes care setting call back pointers to null. + cs.p_data_cback = NULL; + cs.p_report_cback = NULL; + */ + cs.nsc_mask = AVDT_NSC_RECONFIG | + ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY); + APPL_TRACE_DEBUG1("nsc_mask: 0x%x", cs.nsc_mask); + + if (p_data->api_reg.p_service_name[0] == 0) + { + p_service_name = NULL; + } + else + { + p_service_name = p_data->api_reg.p_service_name; + } + + p_scb->suspend_sup = TRUE; + p_scb->recfg_sup = TRUE; + + cs.p_ctrl_cback = bta_av_dt_cback[p_scb->hdi]; + if(registr.chnl == BTA_AV_CHNL_AUDIO) + { + /* set up the audio stream control block */ + p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action; + p_scb->p_cos = &bta_av_a2d_cos; + p_scb->media_type= AVDT_MEDIA_AUDIO; + cs.cfg.psc_mask = AVDT_PSC_TRANS; + cs.media_type = AVDT_MEDIA_AUDIO; + cs.mtu = p_bta_av_cfg->audio_mtu; + cs.flush_to = L2CAP_DEFAULT_FLUSH_TO; +#if AVDT_REPORTING == TRUE + if(bta_av_cb.features & BTA_AV_FEAT_REPORT) + { + cs.cfg.psc_mask |= AVDT_PSC_REPORT; + cs.p_report_cback = bta_av_a2dp_report_cback; +#if AVDT_MULTIPLEXING == TRUE + cs.cfg.mux_tsid_report = 2; +#endif + } +#endif + if(bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT) + cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT; + + /* keep the configuration in the stream control block */ + memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG)); + while(index < BTA_AV_MAX_SEPS && + (*bta_av_a2d_cos.init)(&codec_type, cs.cfg.codec_info, + &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE) + { + if(AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS) + { + p_scb->seps[index].codec_type = codec_type; + APPL_TRACE_DEBUG3("audio[%d] av_handle: %d codec_type: %d", + index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type); + index++; + } + else + break; + } + + if(!bta_av_cb.reg_audio) + { + /* create the SDP records on the 1st audio channel */ + bta_av_cb.sdp_a2d_handle = SDP_CreateRecord(); + A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL, + A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle); + bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE); + + /* start listening when A2DP is registered */ + if (bta_av_cb.features & BTA_AV_FEAT_RCTG) + bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + + /* if the AV and AVK are both supported, it cannot support the CT role */ + if (bta_av_cb.features & (BTA_AV_FEAT_RCCT)) + { + /* if TG is not supported, we need to register to AVCT now */ + if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0) + { +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE) + bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, + bta_av_cb.sec_mask, BTA_ID_AV); +#else + bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, + (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV); +#endif +#endif + } +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + /* create an SDP record as AVRC CT. */ + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, + p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV); +#endif + } + } + bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi); + APPL_TRACE_DEBUG1("reg_audio: 0x%x",bta_av_cb.reg_audio); + } + else + { + bta_av_cb.reg_video = BTA_AV_HNDL_TO_MSK(p_scb->hdi); + bta_av_cb.sdp_vdp_handle = SDP_CreateRecord(); + /* register the video channel */ + /* no need to verify the function pointer here. it's verified prior */ + (*p_bta_av_cfg->p_reg)(&cs, p_service_name, p_scb); + } + } while (0); + + /* call callback with register event */ + (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV *)®istr); +} + +/******************************************************************************* +** +** Function bta_av_api_deregister +** +** Description de-register a channel +** +** +** Returns void +** +*******************************************************************************/ +void bta_av_api_deregister(tBTA_AV_DATA *p_data) +{ + tBTA_AV_SCB *p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific); + + if(p_scb) + { + p_scb->deregistring = TRUE; + bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, p_data); + } + else + { + bta_av_dereg_comp(p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_ci_data +** +** Description forward the BTA_AV_CI_SRC_DATA_READY_EVT to stream state machine +** +** +** Returns void +** +*******************************************************************************/ +static void bta_av_ci_data(tBTA_AV_DATA *p_data) +{ + tBTA_AV_SCB *p_scb; + int i; + UINT8 chnl = (UINT8)p_data->hdr.layer_specific; + + for( i=0; i < BTA_AV_NUM_STRS; i++ ) + { + p_scb = bta_av_cb.p_scb[i]; + + if(p_scb && p_scb->chnl == chnl) + { + bta_av_ssm_execute(p_scb, BTA_AV_SRC_DATA_READY_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rpc_conn +** +** Description report report channel open +** +** Returns void +** +*******************************************************************************/ +#if (AVDT_REPORTING == TRUE) + +static void bta_av_rpc_conn(tBTA_AV_DATA *p_data) +{ +} +#endif + +/******************************************************************************* +** +** Function bta_av_api_to_ssm +** +** Description forward the API request to stream state machine +** +** +** Returns void +** +*******************************************************************************/ +static void bta_av_api_to_ssm(tBTA_AV_DATA *p_data) +{ + int xx; + UINT16 event = p_data->hdr.event - BTA_AV_FIRST_A2S_API_EVT + BTA_AV_FIRST_A2S_SSM_EVT; + + for(xx=0; xx<BTA_AV_NUM_STRS; xx++) + { + bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_chk_start +** +** Description if this is audio channel, check if more than one audio +** channel is connected & already started. +** +** Returns TRUE, if need api_start +** +*******************************************************************************/ +BOOLEAN bta_av_chk_start(tBTA_AV_SCB *p_scb) +{ + BOOLEAN start = FALSE; + tBTA_AV_SCB *p_scbi; + int i; + + if(p_scb->chnl == BTA_AV_CHNL_AUDIO) + { + if ((bta_av_cb.audio_open_cnt >= 2) && + ((0 == (p_scb->role & BTA_AV_ROLE_AD_ACP)) || /* Outgoing connection or */ + (bta_av_cb.features & BTA_AV_FEAT_ACP_START))) /* auto-starting option */ + { + /* more than one audio channel is connected */ + /* if this is the 2nd stream as ACP, give INT a chance to issue the START command */ + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + p_scbi = bta_av_cb.p_scb[i]; + if(p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) + { + start = TRUE; + /* may need to update the flush timeout of this already started stream */ + if(p_scbi->co_started != bta_av_cb.audio_open_cnt) + { + p_scbi->co_started = bta_av_cb.audio_open_cnt; + L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] ); + } + } + } + } + } + return start; +} + +/******************************************************************************* +** +** Function bta_av_restore_switch +** +** Description assume that the caller of this function already makes +** sure that there's only one ACL connection left +** +** Returns void +** +*******************************************************************************/ +void bta_av_restore_switch (void) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + int i; + UINT8 mask; + + APPL_TRACE_DEBUG1("reg_audio: 0x%x",bta_av_cb.reg_audio); + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + mask = BTA_AV_HNDL_TO_MSK(i); + if (p_cb->conn_audio == mask) + { + if (p_cb->p_scb[i]) + { + bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_cb->p_scb[i]->peer_addr); + } + break; + } + } +} + +/******************************************************************************* +** +** Function bta_av_sys_rs_cback +** +** Description Receives the role change event from dm +** +** Returns (BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda) +** +*******************************************************************************/ +static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + int i; + tBTA_AV_SCB *p_scb; + tBTA_AV_ROLE_RES *p_buf; + UINT8 cur_role; + UINT8 peer_idx = 0; + + APPL_TRACE_DEBUG1("bta_av_sys_rs_cback: %d", bta_av_cb.rs_idx); + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + /* loop through all the SCBs to find matching peer addresses and report the role change event */ + /* note that more than one SCB (a2dp & vdp) maybe waiting for this event */ + p_scb = bta_av_cb.p_scb[i]; + if (p_scb && (bdcmp (peer_addr, p_scb->peer_addr) == 0) && + (p_buf = (tBTA_AV_ROLE_RES *) GKI_getbuf(sizeof(tBTA_AV_ROLE_RES))) != NULL) + { + APPL_TRACE_DEBUG3("new_role:%d, hci_status:x%x hndl: x%x", id, app_id, p_scb->hndl); + /* + if ((id != BTM_ROLE_MASTER) && (app_id != HCI_SUCCESS)) + { + bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_MASTER_SLAVE_SWITCH|HCI_ENABLE_SNIFF_MODE), p_scb->peer_addr); + } + */ + p_buf->hdr.event = BTA_AV_ROLE_CHANGE_EVT; + p_buf->hdr.layer_specific = p_scb->hndl; + p_buf->new_role = id; + p_buf->hci_status = app_id; + bta_sys_sendmsg(p_buf); + + peer_idx = p_scb->hdi + 1; /* Handle index for the peer_addr */ + } + } + + /* restore role switch policy, if role switch failed */ + if ((HCI_SUCCESS != app_id) && + (BTM_GetRole (peer_addr, &cur_role) == BTM_SUCCESS) && + (cur_role == BTM_ROLE_SLAVE) ) + { + bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, peer_addr); + } + + /* if BTA_AvOpen() was called for other device, which caused the role switch of the peer_addr, */ + /* we need to continue opening process for the BTA_AvOpen(). */ + if ((bta_av_cb.rs_idx != 0) && (bta_av_cb.rs_idx != peer_idx)) + { + p_scb = bta_av_cb.p_scb[bta_av_cb.rs_idx - 1]; + if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN) + { + APPL_TRACE_DEBUG3 ("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d", + bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag); + + if(HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id) + p_scb->q_info.open.switch_res = BTA_AV_RS_OK; + else + p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL; + + /* Continue av open process */ + bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *)&(p_scb->q_info.open)); + } + + bta_av_cb.rs_idx = 0; + } +} + +/******************************************************************************* +** +** Function bta_av_sco_chg_cback +** +** Description receive & process the SCO connection up/down event from sys. +** call setup also triggers this callback, to suspend av before sco +** activity happens, or to resume av once call ends. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 + app_id, BD_ADDR peer_addr) +{ + tBTA_AV_SCB *p_scb; + int i; + tBTA_AV_API_STOP stop; + + APPL_TRACE_DEBUG2("bta_av_sco_chg_cback:%d status:%d", id, status); + if(id) + { + bta_av_cb.sco_occupied = TRUE; + + /* either BTA_SYS_SCO_OPEN or BTA_SYS_SCO_CLOSE with remaining active SCO */ + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + p_scb = bta_av_cb.p_scb[i]; + + if( p_scb && p_scb->co_started && (p_scb->sco_suspend == FALSE)) + { + APPL_TRACE_DEBUG1("suspending scb:%d", i); + /* scb is used and started, not suspended automatically */ + p_scb->sco_suspend = TRUE; + stop.flush = FALSE; + stop.suspend = TRUE; + bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA *)&stop); + } + } + } + else + { + bta_av_cb.sco_occupied = FALSE; + + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + p_scb = bta_av_cb.p_scb[i]; + + if( p_scb && p_scb->sco_suspend ) /* scb is used and suspended for SCO */ + { + APPL_TRACE_DEBUG1("starting scb:%d", i); + bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL); + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_switch_if_needed +** +** Description This function checks if there is another existing AV +** channel that is local as slave role. +** If so, role switch and remove it from link policy. +** +** Returns TRUE, if role switch is done +** +*******************************************************************************/ +BOOLEAN bta_av_switch_if_needed(tBTA_AV_SCB *p_scb) +{ + UINT8 role; + BOOLEAN needed = FALSE; + tBTA_AV_SCB *p_scbi; + int i; + UINT8 mask; + + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + mask = BTA_AV_HNDL_TO_MSK(i); + p_scbi = bta_av_cb.p_scb[i]; + if( p_scbi && (p_scb->hdi != i) && /* not the original channel */ + ((bta_av_cb.conn_audio & mask) ||/* connected audio */ + (bta_av_cb.conn_video & mask)) ) /* connected video */ + { + BTM_GetRole(p_scbi->peer_addr, &role); + /* this channel is open - clear the role switch link policy for this link */ + if(BTM_ROLE_MASTER != role) + { + if (bta_av_cb.features & BTA_AV_FEAT_MASTER) + bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scbi->peer_addr); + if (BTM_CMD_STARTED != BTM_SwitchRole(p_scbi->peer_addr, BTM_ROLE_MASTER, NULL)) + { + /* can not switch role on SCBI + * start the timer on SCB - because this function is ONLY called when SCB gets API_OPEN */ + bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RS_TIME_VAL); + } + needed = TRUE; + /* mark the original channel as waiting for RS result */ + bta_av_cb.rs_idx = p_scb->hdi + 1; + break; + } + } + } + return needed; +} + +/******************************************************************************* +** +** Function bta_av_link_role_ok +** +** Description This function checks if the SCB has existing ACL connection +** If so, check if the link role fits the requirements. +** +** Returns TRUE, if role is ok +** +*******************************************************************************/ +BOOLEAN bta_av_link_role_ok(tBTA_AV_SCB *p_scb, UINT8 bits) +{ + UINT8 role; + BOOLEAN is_ok = TRUE; + BOOLEAN need_timer = FALSE; + + if (BTM_GetRole(p_scb->peer_addr, &role) == BTM_SUCCESS) + { + APPL_TRACE_ERROR5("bta_av_link_role_ok hndl:x%x role:%d, conn_audio:x%x, bits:%d, features:x%x", p_scb->hndl, role, bta_av_cb.conn_audio, bits, bta_av_cb.features); + if (BTM_ROLE_MASTER != role && (A2D_BitsSet(bta_av_cb.conn_audio) > bits || (bta_av_cb.features & BTA_AV_FEAT_MASTER))) + { + if (bta_av_cb.features & BTA_AV_FEAT_MASTER) + bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scb->peer_addr); + + if (BTM_CMD_STARTED != BTM_SwitchRole(p_scb->peer_addr, BTM_ROLE_MASTER, NULL)) + { + /* can not switch role on SCB - start the timer on SCB */ + need_timer = TRUE; + } + is_ok = FALSE; + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START; + + } + } + + return is_ok; +} + +/******************************************************************************* +** +** Function bta_av_chk_mtu +** +** Description if this is audio channel, check if more than one audio +** channel is connected. +** +** Returns The smallest mtu of the connected audio channels +** +*******************************************************************************/ +UINT16 bta_av_chk_mtu(tBTA_AV_SCB *p_scb, UINT16 mtu) +{ + UINT16 ret_mtu = BTA_AV_MAX_A2DP_MTU; + tBTA_AV_SCB *p_scbi; + int i; + UINT8 mask; + + /* TODO_MV mess with the mtu according to the number of EDR/non-EDR headsets */ + if(p_scb->chnl == BTA_AV_CHNL_AUDIO) + { + if(bta_av_cb.audio_open_cnt >= 2) + { + /* more than one audio channel is connected */ + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + p_scbi = bta_av_cb.p_scb[i]; + if((p_scb != p_scbi) && p_scbi && (p_scbi->chnl == BTA_AV_CHNL_AUDIO) ) + { + mask = BTA_AV_HNDL_TO_MSK(i); + APPL_TRACE_DEBUG3("[%d] mtu: %d, mask:0x%x", + i, p_scbi->stream_mtu, mask); + if(bta_av_cb.conn_audio & mask) + { + if(ret_mtu > p_scbi->stream_mtu) + ret_mtu = p_scbi->stream_mtu; + } + } + } + } + APPL_TRACE_DEBUG3("bta_av_chk_mtu audio count:%d, conn_audio:0x%x, ret:%d", + bta_av_cb.audio_open_cnt, bta_av_cb.conn_audio, ret_mtu); + } + return ret_mtu; +} + +/******************************************************************************* +** +** Function bta_av_dup_audio_buf +** +** Description dup the audio data to the q_info.a2d of other audio channels +** +** Returns void +** +*******************************************************************************/ +void bta_av_dup_audio_buf(tBTA_AV_SCB *p_scb, BT_HDR *p_buf) +{ + tBTA_AV_SCB *p_scbi; + BUFFER_Q *pq; + int i; + UINT16 size, copy_size; + BT_HDR *p_new; + + if(!p_buf) + return; + + if(bta_av_cb.audio_open_cnt >= 2) + { + size = GKI_get_buf_size(p_buf); + copy_size = BT_HDR_SIZE + p_buf->len + p_buf->offset; + /* more than one audio channel is connected */ + for(i=0; i<BTA_AV_NUM_STRS; i++) + { + p_scbi = bta_av_cb.p_scb[i]; + if( (p_scb->hdi != i) && /* not the original channel */ + (bta_av_cb.conn_audio & BTA_AV_HNDL_TO_MSK(i)) && /* connected audio */ + p_scbi && p_scbi->co_started ) /* scb is used and started */ + { + /* enqueue the data only when the stream is started */ + p_new = (BT_HDR *)GKI_getbuf(size); + if(p_new) + { + memcpy(p_new, p_buf, copy_size); + pq = &p_scbi->q_info.a2d; + GKI_enqueue(pq, p_new); + if(pq->count > p_bta_av_cfg->audio_mqs) + { + bta_av_co_audio_drop(p_scbi->hndl); + GKI_freebuf(GKI_dequeue(pq)); + } + } + } + } + } + +} + +/******************************************************************************* +** +** Function bta_av_sm_execute +** +** Description State machine event handling function for AV +** +** +** Returns void +** +*******************************************************************************/ +void bta_av_sm_execute(tBTA_AV_CB *p_cb, UINT16 event, tBTA_AV_DATA *p_data) +{ + tBTA_AV_ST_TBL state_table; + UINT8 action; + +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + APPL_TRACE_EVENT4("AV event=0x%x(%s) state=%d(%s)", + event, bta_av_evt_code(event), p_cb->state, bta_av_st_code(p_cb->state)); +#else + APPL_TRACE_EVENT2("AV event=0x%x state=%d", event, p_cb->state); +#endif + + /* look up the state table for the current state */ + state_table = bta_av_st_tbl[p_cb->state]; + + event &= 0x00FF; + + /* set next state */ + p_cb->state = state_table[event][BTA_AV_NEXT_STATE]; + APPL_TRACE_EVENT1("next state=%d", p_cb->state); + + /* execute action functions */ + if ((action = state_table[event][BTA_AV_ACTION_COL]) != BTA_AV_IGNORE) + { + (*bta_av_action[action])(p_cb, p_data); + } +} + + +/******************************************************************************* +** +** Function bta_av_hdl_event +** +** Description Advanced audio/video main event handling function. +** +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN bta_av_hdl_event(BT_HDR *p_msg) +{ + UINT16 event = p_msg->event; + UINT16 first_event = BTA_AV_FIRST_NSM_EVT; + + if (event > BTA_AV_LAST_EVT) + { + return TRUE; /* to free p_msg */ + } + + if(event >= first_event) + { +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + APPL_TRACE_EVENT2("AV nsm event=0x%x(%s)", event, bta_av_evt_code(event)); +#else + APPL_TRACE_EVENT1("AV nsm event=0x%x", event); +#endif + /* non state machine events */ + (*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT]) ((tBTA_AV_DATA *) p_msg); + } + else if (event >= BTA_AV_FIRST_SM_EVT && event <= BTA_AV_LAST_SM_EVT) + { +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + APPL_TRACE_EVENT2("AV sm event=0x%x(%s)", event, bta_av_evt_code(event)); +#else + APPL_TRACE_EVENT1("AV sm event=0x%x", event); +#endif + /* state machine events */ + bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA *) p_msg); + } + else + { + APPL_TRACE_EVENT1("handle=0x%x", p_msg->layer_specific); + /* stream state machine events */ + bta_av_ssm_execute( bta_av_hndl_to_scb(p_msg->layer_specific), + p_msg->event, (tBTA_AV_DATA *) p_msg); + } + return TRUE; +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +/******************************************************************************* +** +** Function bta_av_st_code +** +** Description +** +** Returns char * +** +*******************************************************************************/ +static char *bta_av_st_code(UINT8 state) +{ + switch(state) + { + case BTA_AV_INIT_ST: return "INIT"; + case BTA_AV_OPEN_ST: return "OPEN"; + default: return "unknown"; + } +} +/******************************************************************************* +** +** Function bta_av_evt_code +** +** Description +** +** Returns char * +** +*******************************************************************************/ +char *bta_av_evt_code(UINT16 evt_code) +{ + switch(evt_code) + { + case BTA_AV_API_DISABLE_EVT: return "API_DISABLE"; + case BTA_AV_API_REMOTE_CMD_EVT: return "API_REMOTE_CMD"; + case BTA_AV_API_VENDOR_CMD_EVT: return "API_VENDOR_CMD"; + case BTA_AV_API_VENDOR_RSP_EVT: return "API_VENDOR_RSP"; + case BTA_AV_API_META_RSP_EVT: return "API_META_RSP_EVT"; + case BTA_AV_API_RC_CLOSE_EVT: return "API_RC_CLOSE"; + case BTA_AV_AVRC_OPEN_EVT: return "AVRC_OPEN"; + case BTA_AV_AVRC_MSG_EVT: return "AVRC_MSG"; + case BTA_AV_AVRC_NONE_EVT: return "AVRC_NONE"; + + case BTA_AV_API_OPEN_EVT: return "API_OPEN"; + case BTA_AV_API_CLOSE_EVT: return "API_CLOSE"; + case BTA_AV_AP_START_EVT: return "AP_START"; + case BTA_AV_AP_STOP_EVT: return "AP_STOP"; + case BTA_AV_API_RECONFIG_EVT: return "API_RECONFIG"; + case BTA_AV_API_PROTECT_REQ_EVT: return "API_PROTECT_REQ"; + case BTA_AV_API_PROTECT_RSP_EVT: return "API_PROTECT_RSP"; + case BTA_AV_API_RC_OPEN_EVT: return "API_RC_OPEN"; + case BTA_AV_SRC_DATA_READY_EVT: return "SRC_DATA_READY"; + case BTA_AV_CI_SETCONFIG_OK_EVT: return "CI_SETCONFIG_OK"; + case BTA_AV_CI_SETCONFIG_FAIL_EVT: return "CI_SETCONFIG_FAIL"; + case BTA_AV_SDP_DISC_OK_EVT: return "SDP_DISC_OK"; + case BTA_AV_SDP_DISC_FAIL_EVT: return "SDP_DISC_FAIL"; + case BTA_AV_STR_DISC_OK_EVT: return "STR_DISC_OK"; + case BTA_AV_STR_DISC_FAIL_EVT: return "STR_DISC_FAIL"; + case BTA_AV_STR_GETCAP_OK_EVT: return "STR_GETCAP_OK"; + case BTA_AV_STR_GETCAP_FAIL_EVT: return "STR_GETCAP_FAIL"; + case BTA_AV_STR_OPEN_OK_EVT: return "STR_OPEN_OK"; + case BTA_AV_STR_OPEN_FAIL_EVT: return "STR_OPEN_FAIL"; + case BTA_AV_STR_START_OK_EVT: return "STR_START_OK"; + case BTA_AV_STR_START_FAIL_EVT: return "STR_START_FAIL"; + case BTA_AV_STR_CLOSE_EVT: return "STR_CLOSE"; + case BTA_AV_STR_CONFIG_IND_EVT: return "STR_CONFIG_IND"; + case BTA_AV_STR_SECURITY_IND_EVT: return "STR_SECURITY_IND"; + case BTA_AV_STR_SECURITY_CFM_EVT: return "STR_SECURITY_CFM"; + case BTA_AV_STR_WRITE_CFM_EVT: return "STR_WRITE_CFM"; + case BTA_AV_STR_SUSPEND_CFM_EVT: return "STR_SUSPEND_CFM"; + case BTA_AV_STR_RECONFIG_CFM_EVT: return "STR_RECONFIG_CFM"; + case BTA_AV_AVRC_TIMER_EVT: return "AVRC_TIMER"; + case BTA_AV_AVDT_CONNECT_EVT: return "AVDT_CONNECT"; + case BTA_AV_AVDT_DISCONNECT_EVT: return "AVDT_DISCONNECT"; + case BTA_AV_ROLE_CHANGE_EVT: return "ROLE_CHANGE"; + case BTA_AV_AVDT_DELAY_RPT_EVT: return "AVDT_DELAY_RPT"; + case BTA_AV_ACP_CONNECT_EVT: return "ACP_CONNECT"; + + case BTA_AV_API_ENABLE_EVT: return "API_ENABLE"; + case BTA_AV_API_REGISTER_EVT: return "API_REG"; + case BTA_AV_API_DEREGISTER_EVT: return "API_DEREG"; + case BTA_AV_API_DISCONNECT_EVT: return "API_DISCNT"; + case BTA_AV_CI_SRC_DATA_READY_EVT: return "CI_DATA_READY"; + case BTA_AV_SIG_CHG_EVT: return "SIG_CHG"; + case BTA_AV_SIG_TIMER_EVT: return "SIG_TMR"; + case BTA_AV_SDP_AVRC_DISC_EVT: return "SDP_AVRC_DISC"; + case BTA_AV_AVRC_CLOSE_EVT: return "AVRC_CLOSE"; + case BTA_AV_CONN_CHG_EVT: return "CONN_CHG"; + case BTA_AV_DEREG_COMP_EVT: return "DEREG_COMP"; +#if (AVDT_REPORTING == TRUE) + case BTA_AV_AVDT_RPT_CONN_EVT: return "RPT_CONN"; +#endif + case BTA_AV_API_START_EVT: return "API_START"; + case BTA_AV_API_STOP_EVT: return "API_STOP"; + default: return "unknown"; + } +} +#endif + +#endif /* BTA_AV_INCLUDED */ diff --git a/bta/av/bta_av_sbc.c b/bta/av/bta_av_sbc.c new file mode 100644 index 0000000..1517270 --- /dev/null +++ b/bta/av/bta_av_sbc.c @@ -0,0 +1,590 @@ +/****************************************************************************** + * + * 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 module contains utility functions for dealing with SBC data frames + * and codec capabilities. + * + ******************************************************************************/ + +#include "a2d_api.h" +#include "a2d_sbc.h" +#include "bta_av_sbc.h" + +typedef int (tBTA_AV_SBC_ACT)(void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +typedef struct +{ + INT32 cur_pos; /* current position */ + UINT32 src_sps; /* samples per second (source audio data) */ + UINT32 dst_sps; /* samples per second (converted audio data) */ + tBTA_AV_SBC_ACT *p_act; /* the action function to do the conversion */ + UINT16 bits; /* number of bits per pcm sample */ + UINT16 n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */ + INT16 worker1; + INT16 worker2; + UINT8 div; +} tBTA_AV_SBC_UPS_CB; + +tBTA_AV_SBC_UPS_CB bta_av_sbc_ups_cb; + +/******************************************************************************* +** +** Function bta_av_sbc_init_up_sample +** +** Description initialize the up sample +** +** src_sps: samples per second (source audio data) +** dst_sps: samples per second (converted audio data) +** bits: number of bits per pcm sample +** n_channels: number of channels (i.e. mono(1), stereo(2)...) +** +** Returns none +** +*******************************************************************************/ +void bta_av_sbc_init_up_sample (UINT32 src_sps, UINT32 dst_sps, UINT16 bits, UINT16 n_channels) +{ + bta_av_sbc_ups_cb.cur_pos = -1; + bta_av_sbc_ups_cb.src_sps = src_sps; + bta_av_sbc_ups_cb.dst_sps = dst_sps; + bta_av_sbc_ups_cb.bits = bits; + bta_av_sbc_ups_cb.n_channels= n_channels; + + if(n_channels == 1) + { + /* mono */ + if(bits == 8) + { + bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_8m; + bta_av_sbc_ups_cb.div = 1; + } + else + { + bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_16m; + bta_av_sbc_ups_cb.div = 2; + } + } + else + { + /* stereo */ + if(bits == 8) + { + bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_8s; + bta_av_sbc_ups_cb.div = 2; + } + else + { + bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_16s; + bta_av_sbc_ups_cb.div = 4; + } + } +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (number of bytes) +** dst_samples: The size of p_dst (number of bytes) +** +** Note: An AE reported an issue with this function. +** When called with bta_av_sbc_up_sample(src, uint8_array_dst..) +** the byte before uint8_array_dst may get overwritten. +** Using uint16_array_dst avoids the problem. +** This issue is related to endian-ness and is hard to resolve +** in a generic manner. +** **************** Please use uint16 array as dst. +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + UINT32 src; + UINT32 dst; + + if(bta_av_sbc_ups_cb.p_act) + { + src = src_samples/bta_av_sbc_ups_cb.div; + dst = dst_samples/bta_av_sbc_ups_cb.div; + return (*bta_av_sbc_ups_cb.p_act)(p_src, p_dst, src, dst, p_ret); + } + else + { + *p_ret = 0; + return 0; + } +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_16s (16bits-stereo) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 4 bytes) +** dst_samples: The size of p_dst (in uint of 4 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + INT16 *p_src_tmp = (INT16 *)p_src; + INT16 *p_dst_tmp = (INT16 *)p_dst; + INT16 *p_worker1 = &bta_av_sbc_ups_cb.worker1; + INT16 *p_worker2 = &bta_av_sbc_ups_cb.worker2; + UINT32 src_sps = bta_av_sbc_ups_cb.src_sps; + UINT32 dst_sps = bta_av_sbc_ups_cb.dst_sps; + + while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) + { + *p_dst_tmp++ = *p_worker1; + *p_dst_tmp++ = *p_worker2; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + } + + bta_av_sbc_ups_cb.cur_pos = dst_sps; + + while (src_samples-- && dst_samples) + { + *p_worker1 = *p_src_tmp++; + *p_worker2 = *p_src_tmp++; + + do + { + *p_dst_tmp++ = *p_worker1; + *p_dst_tmp++ = *p_worker2; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + + bta_av_sbc_ups_cb.cur_pos += dst_sps; + } + + if (bta_av_sbc_ups_cb.cur_pos == (INT32)dst_sps) + bta_av_sbc_ups_cb.cur_pos = 0; + + *p_ret = ((char *)p_src_tmp - (char *)p_src); + return ((char *)p_dst_tmp - (char *)p_dst); +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_16m (16bits-mono) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 2 bytes) +** dst_samples: The size of p_dst (in uint of 2 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + INT16 *p_src_tmp = (INT16 *)p_src; + INT16 *p_dst_tmp = (INT16 *)p_dst; + INT16 *p_worker = &bta_av_sbc_ups_cb.worker1; + UINT32 src_sps = bta_av_sbc_ups_cb.src_sps; + UINT32 dst_sps = bta_av_sbc_ups_cb.dst_sps; + + while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) + { + *p_dst_tmp++ = *p_worker; + *p_dst_tmp++ = *p_worker; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + dst_samples--; + } + + + bta_av_sbc_ups_cb.cur_pos = dst_sps; + + while (src_samples-- && dst_samples) + { + *p_worker = *p_src_tmp++; + + do + { + *p_dst_tmp++ = *p_worker; + *p_dst_tmp++ = *p_worker; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + dst_samples--; + + } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + + bta_av_sbc_ups_cb.cur_pos += dst_sps; + } + + if (bta_av_sbc_ups_cb.cur_pos == (INT32)dst_sps) + bta_av_sbc_ups_cb.cur_pos = 0; + + *p_ret = ((char *)p_src_tmp - (char *)p_src); + return ((char *)p_dst_tmp - (char *)p_dst); +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_8s (8bits-stereo) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 2 bytes) +** dst_samples: The size of p_dst (in uint of 2 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + UINT8 *p_src_tmp = (UINT8 *)p_src; + INT16 *p_dst_tmp = (INT16 *)p_dst; + INT16 *p_worker1 = &bta_av_sbc_ups_cb.worker1; + INT16 *p_worker2 = &bta_av_sbc_ups_cb.worker2; + UINT32 src_sps = bta_av_sbc_ups_cb.src_sps; + UINT32 dst_sps = bta_av_sbc_ups_cb.dst_sps; + + while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) + { + *p_dst_tmp++ = *p_worker1; + *p_dst_tmp++ = *p_worker2; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + dst_samples--; + } + + bta_av_sbc_ups_cb.cur_pos = dst_sps; + + while (src_samples -- && dst_samples) + { + *p_worker1 = *(UINT8 *)p_src_tmp++; + *p_worker1 -= 0x80; + *p_worker1 <<= 8; + *p_worker2 = *(UINT8 *)p_src_tmp++; + *p_worker2 -= 0x80; + *p_worker2 <<= 8; + + do + { + *p_dst_tmp++ = *p_worker1; + *p_dst_tmp++ = *p_worker2; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + dst_samples--; + } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + + bta_av_sbc_ups_cb.cur_pos += dst_sps; + } + + if (bta_av_sbc_ups_cb.cur_pos == (INT32)dst_sps) + bta_av_sbc_ups_cb.cur_pos = 0; + + *p_ret = ((char *)p_src_tmp - (char *)p_src); + return ((char *)p_dst_tmp - (char *)p_dst); +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_8m (8bits-mono) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (number of bytes) +** dst_samples: The size of p_dst (number of bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample_8m (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + UINT8 *p_src_tmp = (UINT8 *)p_src; + INT16 *p_dst_tmp = (INT16 *)p_dst; + INT16 *p_worker = &bta_av_sbc_ups_cb.worker1; + UINT32 src_sps = bta_av_sbc_ups_cb.src_sps; + UINT32 dst_sps = bta_av_sbc_ups_cb.dst_sps; + + while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) + { + *p_dst_tmp++ = *p_worker; + *p_dst_tmp++ = *p_worker; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples -= 4; + } + + + bta_av_sbc_ups_cb.cur_pos = dst_sps; + + while (src_samples-- && dst_samples) + { + *p_worker = *(UINT8 *)p_src_tmp++; + *p_worker -= 0x80; + *p_worker <<= 8; + + do + { + *p_dst_tmp++ = *p_worker; + *p_dst_tmp++ = *p_worker; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples -= 4; + + } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + + bta_av_sbc_ups_cb.cur_pos += dst_sps; + } + + if (bta_av_sbc_ups_cb.cur_pos == (INT32)dst_sps) + bta_av_sbc_ups_cb.cur_pos = 0; + + *p_ret = ((char *)p_src_tmp - (char *)p_src); + return ((char *)p_dst_tmp - (char *)p_dst); +} + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_for_cap +** +** Description Determine the preferred SBC codec configuration for the +** given codec capabilities. The function is passed the +** preferred codec configuration and the peer codec +** capabilities for the stream. The function attempts to +** match the preferred capabilities with the configuration +** as best it can. The resulting codec configuration is +** returned in the same memory used for the capabilities. +** +** Returns 0 if ok, nonzero if error. +** Codec configuration in p_cap. +** +*******************************************************************************/ +UINT8 bta_av_sbc_cfg_for_cap(UINT8 *p_peer, tA2D_SBC_CIE *p_cap, tA2D_SBC_CIE *p_pref) +{ + UINT8 status = A2D_SUCCESS; + tA2D_SBC_CIE peer_cie; + + /* parse peer capabilities */ + if ((status = A2D_ParsSbcInfo(&peer_cie, p_peer, TRUE)) != 0) + { + return status; + } + + /* Check if the peer supports our channel mode */ + if (peer_cie.ch_mode & p_pref->ch_mode) + { + peer_cie.ch_mode = p_pref->ch_mode; + } + else + { + APPL_TRACE_ERROR1("bta_av_sbc_cfg_for_cap: ch_mode(0x%02X) not supported", p_pref->ch_mode); + return A2D_FAIL; + } + + /* Check if the peer supports our sampling freq */ + if (peer_cie.samp_freq & p_pref->samp_freq) + { + peer_cie.samp_freq = p_pref->samp_freq; + } + else + { + APPL_TRACE_ERROR1("bta_av_sbc_cfg_for_cap: samp_freq(0x%02X) not supported", p_pref->samp_freq); + return A2D_FAIL; + } + + /* Check if the peer supports our block len */ + if (peer_cie.block_len & p_pref->block_len) + { + peer_cie.block_len = p_pref->block_len; + } + else + { + APPL_TRACE_ERROR1("bta_av_sbc_cfg_for_cap: block_len(0x%02X) not supported", p_pref->block_len); + return A2D_FAIL; + } + + /* Check if the peer supports our num subbands */ + if (peer_cie.num_subbands & p_pref->num_subbands) + { + peer_cie.num_subbands = p_pref->num_subbands; + } + else + { + APPL_TRACE_ERROR1("bta_av_sbc_cfg_for_cap: num_subbands(0x%02X) not supported", p_pref->num_subbands); + return A2D_FAIL; + } + + /* Check if the peer supports our alloc method */ + if (peer_cie.alloc_mthd & p_pref->alloc_mthd) + { + peer_cie.alloc_mthd = p_pref->alloc_mthd; + } + else + { + APPL_TRACE_ERROR1("bta_av_sbc_cfg_for_cap: alloc_mthd(0x%02X) not supported", p_pref->alloc_mthd); + return A2D_FAIL; + } + + /* max bitpool */ + if (p_pref->max_bitpool != 0 && p_pref->max_bitpool < peer_cie.max_bitpool) + { + peer_cie.max_bitpool = p_pref->max_bitpool; + } + + /* min bitpool */ + if (p_pref->min_bitpool != 0 && p_pref->min_bitpool > peer_cie.min_bitpool) + { + peer_cie.min_bitpool = p_pref->min_bitpool; + } + + if (status == A2D_SUCCESS) + { + /* build configuration */ + A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, &peer_cie, p_peer); + } + return status; +} + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_in_cap +** +** Description This function checks whether an SBC codec configuration +** is allowable for the given codec capabilities. +** +** Returns 0 if ok, nonzero if error. +** +*******************************************************************************/ +UINT8 bta_av_sbc_cfg_in_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap) +{ + UINT8 status = 0; + tA2D_SBC_CIE cfg_cie; + + /* parse configuration */ + if ((status = A2D_ParsSbcInfo(&cfg_cie, p_cfg, FALSE)) != 0) + { + return status; + } + + /* verify that each parameter is in range */ + + /* sampling frequency */ + if ((cfg_cie.samp_freq & p_cap->samp_freq) == 0) + { + status = A2D_NS_SAMP_FREQ; + } + /* channel mode */ + else if ((cfg_cie.ch_mode & p_cap->ch_mode) == 0) + { + status = A2D_NS_CH_MODE; + } + /* block length */ + else if ((cfg_cie.block_len & p_cap->block_len) == 0) + { + status = A2D_BAD_BLOCK_LEN; + } + /* subbands */ + else if ((cfg_cie.num_subbands & p_cap->num_subbands) == 0) + { + status = A2D_NS_SUBBANDS; + } + /* allocation method */ + else if ((cfg_cie.alloc_mthd & p_cap->alloc_mthd) == 0) + { + status = A2D_NS_ALLOC_MTHD; + } + /* max bitpool */ + else if (cfg_cie.max_bitpool > p_cap->max_bitpool) + { + status = A2D_NS_MAX_BITPOOL; + } + /* min bitpool */ + else if (cfg_cie.min_bitpool < p_cap->min_bitpool) + { + status = A2D_NS_MIN_BITPOOL; + } + + return status; +} + +/******************************************************************************* +** +** Function bta_av_sbc_bld_hdr +** +** Description This function builds the packet header for MPF1. +** +** Returns void +** +*******************************************************************************/ +void bta_av_sbc_bld_hdr(BT_HDR *p_buf, UINT16 fr_per_pkt) +{ + UINT8 *p; + + p_buf->offset -= BTA_AV_SBC_HDR_SIZE; + p = (UINT8 *) (p_buf + 1) + p_buf->offset; + p_buf->len += BTA_AV_SBC_HDR_SIZE; + A2D_BldSbcMplHdr(p, FALSE, FALSE, FALSE, (UINT8) fr_per_pkt); +} + diff --git a/bta/av/bta_av_ssm.c b/bta/av/bta_av_ssm.c new file mode 100644 index 0000000..a35a4b0 --- /dev/null +++ b/bta/av/bta_av_ssm.c @@ -0,0 +1,599 @@ +/****************************************************************************** + * + * 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 stream state machine for the BTA advanced audio/video. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#include <string.h> +#include "bta_av_co.h" +#include "bta_av_int.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +/* state machine states */ +enum +{ + BTA_AV_INIT_SST, + BTA_AV_INCOMING_SST, + BTA_AV_OPENING_SST, + BTA_AV_OPEN_SST, + BTA_AV_RCFG_SST, + BTA_AV_CLOSING_SST +}; + + +/* state machine action enumeration list */ +enum +{ + BTA_AV_DO_DISC, + BTA_AV_CLEANUP, + BTA_AV_FREE_SDB, + BTA_AV_CONFIG_IND, + BTA_AV_DISCONNECT_REQ, + BTA_AV_SECURITY_REQ, + BTA_AV_SECURITY_RSP, + BTA_AV_SETCONFIG_RSP, + BTA_AV_ST_RC_TIMER, + BTA_AV_STR_OPENED, + BTA_AV_SECURITY_IND, + BTA_AV_SECURITY_CFM, + BTA_AV_DO_CLOSE, + BTA_AV_CONNECT_REQ, + BTA_AV_SDP_FAILED, + BTA_AV_DISC_RESULTS, + BTA_AV_DISC_RES_AS_ACP, + BTA_AV_OPEN_FAILED, + BTA_AV_GETCAP_RESULTS, + BTA_AV_SETCONFIG_REJ, + BTA_AV_DISCOVER_REQ, + BTA_AV_CONN_FAILED, + BTA_AV_DO_START, + BTA_AV_STR_STOPPED, + BTA_AV_RECONFIG, + BTA_AV_DATA_PATH, + BTA_AV_START_OK, + BTA_AV_START_FAILED, + BTA_AV_STR_CLOSED, + BTA_AV_CLR_CONG, + BTA_AV_SUSPEND_CFM, + BTA_AV_RCFG_STR_OK, + BTA_AV_RCFG_FAILED, + BTA_AV_RCFG_CONNECT, + BTA_AV_RCFG_DISCNTD, + BTA_AV_SUSPEND_CONT, + BTA_AV_RCFG_CFM, + BTA_AV_RCFG_OPEN, + BTA_AV_SECURITY_REJ, + BTA_AV_OPEN_RC, + BTA_AV_CHK_2ND_START, + BTA_AV_SAVE_CAPS, + BTA_AV_SET_USE_RC, + BTA_AV_CCO_CLOSE, + BTA_AV_SWITCH_ROLE, + BTA_AV_ROLE_RES, + BTA_AV_DELAY_CO, + BTA_AV_OPEN_AT_INC, + BTA_AV_NUM_SACTIONS +}; + +#define BTA_AV_SIGNORE BTA_AV_NUM_SACTIONS + + +/* state table information */ +/* #define BTA_AV_SACTION_COL 0 position of actions */ +#define BTA_AV_SACTIONS 2 /* number of actions */ +#define BTA_AV_SNEXT_STATE 2 /* position of next state */ +#define BTA_AV_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for init state */ +static const UINT8 bta_av_sst_init[][BTA_AV_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* AP_OPEN_EVT */ {BTA_AV_DO_DISC, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* AP_CLOSE_EVT */ {BTA_AV_CLEANUP, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* AVDT_DISCONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST } +}; + +/* state table for incoming state */ +static const UINT8 bta_av_sst_incoming[][BTA_AV_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* AP_OPEN_EVT */ {BTA_AV_OPEN_AT_INC, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* AP_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ, BTA_AV_CLOSING_SST }, +/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_ST_RC_TIMER, BTA_AV_INCOMING_SST }, +/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_CLEANUP, BTA_AV_INIT_SST }, +/* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP,BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_OPEN_OK_EVT */ {BTA_AV_STR_OPENED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST }, +/* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* AVDT_DISCONNECT_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST }, +/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST } +}; + +/* state table for opening state */ +static const UINT8 bta_av_sst_opening[][BTA_AV_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* SDP_DISC_OK_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* SDP_DISC_FAIL_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_DISC_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_GETCAP_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_OPEN_OK_EVT */ {BTA_AV_ST_RC_TIMER, BTA_AV_STR_OPENED, BTA_AV_OPEN_SST }, +/* STR_OPEN_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, +/* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* AVRC_TIMER_EVT */ {BTA_AV_SWITCH_ROLE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* AVDT_CONNECT_EVT */ {BTA_AV_DISCOVER_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* AVDT_DISCONNECT_EVT */ {BTA_AV_CONN_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, +/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST } +}; + +/* state table for open state */ +static const UINT8 bta_av_sst_open[][BTA_AV_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AP_START_EVT */ {BTA_AV_DO_START, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* AP_STOP_EVT */ {BTA_AV_STR_STOPPED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* API_RECONFIG_EVT */ {BTA_AV_RECONFIG, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* API_RC_OPEN_EVT */ {BTA_AV_SET_USE_RC, BTA_AV_OPEN_RC, BTA_AV_OPEN_SST }, +/* SRC_DATA_READY_EVT */ {BTA_AV_DATA_PATH, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_START_OK_EVT */ {BTA_AV_START_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_START_FAIL_EVT */ {BTA_AV_START_FAILED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_CLOSE_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_WRITE_CFM_EVT */ {BTA_AV_CLR_CONG, BTA_AV_DATA_PATH, BTA_AV_OPEN_SST }, +/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* AVRC_TIMER_EVT */ {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START, BTA_AV_OPEN_SST }, +/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST } +}; + +/* state table for reconfig state */ +static const UINT8 bta_av_sst_rcfg[][BTA_AV_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_DISC_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_GETCAP_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_OPEN_OK_EVT */ {BTA_AV_RCFG_STR_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, +/* STR_OPEN_FAIL_EVT */ {BTA_AV_RCFG_FAILED, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_CLOSE_EVT */ {BTA_AV_RCFG_CONNECT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CONT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* STR_RECONFIG_CFM_EVT */ {BTA_AV_RCFG_CFM, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* AVDT_CONNECT_EVT */ {BTA_AV_RCFG_OPEN, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* AVDT_DISCONNECT_EVT */ {BTA_AV_RCFG_DISCNTD, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, +/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST } +}; + +/* state table for closing state */ +static const UINT8 bta_av_sst_closing[][BTA_AV_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next state */ +/* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* SDP_DISC_OK_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* SDP_DISC_FAIL_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_OPEN_OK_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_OPEN_FAIL_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_REJ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, +/* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, +/* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST } +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_AV_SST_TBL)[BTA_AV_NUM_COLS]; + +/* state table */ +static const tBTA_AV_SST_TBL bta_av_sst_tbl[] = +{ + bta_av_sst_init, + bta_av_sst_incoming, + bta_av_sst_opening, + bta_av_sst_open, + bta_av_sst_rcfg, + bta_av_sst_closing +}; + + + +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +static char *bta_av_sst_code(UINT8 state); +#endif + +/******************************************************************************* +** +** Function bta_av_is_rcfg_sst +** +** Description Check if stream state machine is in reconfig state. +** +** +** Returns TRUE if stream state machine is in reconfig state. +** +*******************************************************************************/ +BOOLEAN bta_av_is_rcfg_sst (tBTA_AV_SCB *p_scb) +{ + BOOLEAN is_rcfg_sst = FALSE; + + if (p_scb != NULL) + { + if (p_scb->state == BTA_AV_RCFG_SST) + is_rcfg_sst = TRUE; + } + + return is_rcfg_sst; +} + +/******************************************************************************* +** +** Function bta_av_ssm_execute +** +** Description Stream state machine event handling function for AV +** +** +** Returns void +** +*******************************************************************************/ +void bta_av_ssm_execute(tBTA_AV_SCB *p_scb, UINT16 event, tBTA_AV_DATA *p_data) +{ + tBTA_AV_SST_TBL state_table; + UINT8 action; + int i, xx; + + if(p_scb == NULL) + { + /* this stream is not registered */ + APPL_TRACE_EVENT0("AV channel not registered"); + return; + } + + /* In case incoming connection is for VDP, we need to swap scb. */ + /* When ACP_CONNECT_EVT was received, we put first available scb to */ + /* to Incoming state. Later, when STR_CONFIG_IND_EVT is coming, we */ + /* know if it is A2DP or VDP. */ + if ((p_scb->state == BTA_AV_INIT_SST) && (event == BTA_AV_STR_CONFIG_IND_EVT)) + { + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) + { + if (bta_av_cb.p_scb[xx]) + { + if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST) + { + bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST; + bta_av_cb.p_scb[xx]->coll_mask = 0; + p_scb->state = BTA_AV_INCOMING_SST; + break; + } + } + } + } + +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + APPL_TRACE_EVENT5("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)", + p_scb->hndl, event, bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state)); +#else + APPL_TRACE_EVENT2("AV Sevent=0x%x state=%d", event, p_scb->state); +#endif + + /* look up the state table for the current state */ + state_table = bta_av_sst_tbl[p_scb->state]; + + event -= BTA_AV_FIRST_SSM_EVT; + + /* set next state */ + p_scb->state = state_table[event][BTA_AV_SNEXT_STATE]; + + /* execute action functions */ + for(i=0; i< BTA_AV_SACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_AV_SIGNORE) + { + (*p_scb->p_act_tbl[action])(p_scb, p_data); + } + else + break; + } + +} + +/******************************************************************************* +** +** Function bta_av_is_scb_opening +** +** Description Returns TRUE is scb is in opening state. +** +** +** Returns TRUE if scb is in opening state. +** +*******************************************************************************/ +BOOLEAN bta_av_is_scb_opening (tBTA_AV_SCB *p_scb) +{ + BOOLEAN is_opening = FALSE; + + if (p_scb) + { + if (p_scb->state == BTA_AV_OPENING_SST) + is_opening = TRUE; + } + + return is_opening; +} + +/******************************************************************************* +** +** Function bta_av_is_scb_incoming +** +** Description Returns TRUE is scb is in incoming state. +** +** +** Returns TRUE if scb is in incoming state. +** +*******************************************************************************/ +BOOLEAN bta_av_is_scb_incoming (tBTA_AV_SCB *p_scb) +{ + BOOLEAN is_incoming = FALSE; + + if (p_scb) + { + if (p_scb->state == BTA_AV_INCOMING_SST) + is_incoming = TRUE; + } + + return is_incoming; +} + +/******************************************************************************* +** +** Function bta_av_set_scb_sst_init +** +** Description Set SST state to INIT. +** Use this function to change SST outside of state machine. +** +** Returns None +** +*******************************************************************************/ +void bta_av_set_scb_sst_init (tBTA_AV_SCB *p_scb) +{ + if (p_scb) + { + p_scb->state = BTA_AV_INIT_SST; + } +} + +/******************************************************************************* +** +** Function bta_av_is_scb_init +** +** Description Returns TRUE is scb is in init state. +** +** +** Returns TRUE if scb is in incoming state. +** +*******************************************************************************/ +BOOLEAN bta_av_is_scb_init (tBTA_AV_SCB *p_scb) +{ + BOOLEAN is_init = FALSE; + + if (p_scb) + { + if (p_scb->state == BTA_AV_INIT_SST) + is_init = TRUE; + } + + return is_init; +} + +/******************************************************************************* +** +** Function bta_av_set_scb_sst_incoming +** +** Description Set SST state to incoming. +** Use this function to change SST outside of state machine. +** +** Returns None +** +*******************************************************************************/ +void bta_av_set_scb_sst_incoming (tBTA_AV_SCB *p_scb) +{ + if (p_scb) + { + p_scb->state = BTA_AV_INCOMING_SST; + } +} + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +/******************************************************************************* +** +** Function bta_av_sst_code +** +** Description +** +** Returns char * +** +*******************************************************************************/ +static char *bta_av_sst_code(UINT8 state) +{ + switch(state) + { + case BTA_AV_INIT_SST: return "INIT"; + case BTA_AV_INCOMING_SST: return "INCOMING"; + case BTA_AV_OPENING_SST: return "OPENING"; + case BTA_AV_OPEN_SST: return "OPEN"; + case BTA_AV_RCFG_SST: return "RCFG"; + case BTA_AV_CLOSING_SST: return "CLOSING"; + default: return "unknown"; + } +} + +#endif +#endif /* BTA_AV_INCLUDED */ diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c new file mode 100644 index 0000000..29b4ec2 --- /dev/null +++ b/bta/dm/bta_dm_act.c @@ -0,0 +1,4886 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the action functions for device manager state + * machine. + * + ******************************************************************************/ + +#include "bt_types.h" +#include "gki.h" +#include "bd.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +#include "bta_dm_co.h" +#include "btm_api.h" +#include "btm_int.h" +#include "btu.h" +#include "sdp_api.h" +#include "l2c_api.h" +#include "wbt_api.h" +#include "utl.h" +#include <string.h> + +static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir); +static void bta_dm_inq_cmpl_cb (void * p_result); +static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name); +static void bta_dm_remname_cback (tBTM_REMOTE_DEV_NAME *p_remote_name); +static void bta_dm_find_services ( BD_ADDR bd_addr); +static void bta_dm_discover_next_device(void); +static void bta_dm_sdp_callback (UINT16 sdp_status); +static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, UINT8 *service_name, UINT8 service_id, BOOLEAN is_originator); +static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name); +static UINT8 bta_dm_link_key_request_cback (BD_ADDR bd_addr, LINK_KEY key); +static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, LINK_KEY key, UINT8 key_type); +static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,BD_NAME bd_name, int result); +static void bta_dm_local_name_cback(BD_ADDR bd_addr); +static BOOLEAN bta_dm_check_av(UINT16 event); +#if (BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) +static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data); +#else +static void bta_dm_acl_change_cback (BD_ADDR p_bda, DEV_CLASS p_dc, BD_NAME p_bdn, BD_FEATURES features, BOOLEAN is_new); +#endif +static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); + +/* Extended Inquiry Response */ +static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data); + +#if (BTM_EIR_SERVER_INCLUDED == TRUE) +static void bta_dm_set_eir (char *local_name); +#endif /* BTM_EIR_SERVER_INCLUDED */ + +#if (BTM_EIR_CLIENT_INCLUDED == TRUE) +static void bta_dm_eir_search_services( tBTM_INQ_RESULTS *p_result, + tBTA_SERVICE_MASK *p_services_to_search, + tBTA_SERVICE_MASK *p_services_found); +#endif /* BTM_EIR_CLIENT_INCLUDED */ + +static void bta_dm_rssi_cback (tBTM_RSSI_RESULTS *p_result); +static void bta_dm_signal_strength_timer_cback (TIMER_LIST_ENT *p_tle); +static void bta_dm_link_quality_cback (tBTM_LINK_QUALITY_RESULTS *p_result); +static void bta_dm_search_timer_cback (TIMER_LIST_ENT *p_tle); +static void bta_dm_disable_timer_cback (TIMER_LIST_ENT *p_tle); +static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle); +static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +static void bta_dm_adjust_roles(BOOLEAN delay_role_switch); +static char *bta_dm_get_remname(void); +static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result); + +static BOOLEAN bta_dm_read_remote_device_name (BD_ADDR bd_addr); +static void bta_dm_discover_device(BD_ADDR remote_bd_addr); + +static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ); + +static BOOLEAN bta_dm_dev_blacklisted_for_switch (BD_ADDR remote_bd_addr); +static void bta_dm_delay_role_switch_cback (TIMER_LIST_ENT *p_tle); + + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + #if ((defined SMP_INCLUDED) && (SMP_INCLUDED == TRUE)) +static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data); + #endif +static void bta_dm_ble_id_key_cback (UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key); + #if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) +static void btm_dm_start_gatt_discovery ( BD_ADDR bd_addr); +static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr); +static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data); + #endif +#endif + +extern void sdpu_uuid16_to_uuid128(UINT16 uuid16, UINT8* p_uuid128); + +const UINT16 bta_service_id_to_uuid_lkup_tbl [BTA_MAX_SERVICE_ID] = +{ + UUID_SERVCLASS_PNP_INFORMATION, /* Reserved */ + UUID_SERVCLASS_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */ + UUID_SERVCLASS_DIALUP_NETWORKING, /* BTA_DUN_SERVICE_ID */ + UUID_SERVCLASS_AUDIO_SOURCE, /* BTA_A2DP_SOURCE_SERVICE_ID */ + UUID_SERVCLASS_LAN_ACCESS_USING_PPP, /* BTA_LAP_SERVICE_ID */ + UUID_SERVCLASS_HEADSET, /* BTA_HSP_HS_SERVICE_ID */ + UUID_SERVCLASS_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */ + UUID_SERVCLASS_OBEX_OBJECT_PUSH, /* BTA_OPP_SERVICE_ID */ + UUID_SERVCLASS_OBEX_FILE_TRANSFER, /* BTA_FTP_SERVICE_ID */ + UUID_SERVCLASS_CORDLESS_TELEPHONY, /* BTA_CTP_SERVICE_ID */ + UUID_SERVCLASS_INTERCOM, /* BTA_ICP_SERVICE_ID */ + UUID_SERVCLASS_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */ + UUID_SERVCLASS_DIRECT_PRINTING, /* BTA_BPP_SERVICE_ID */ + UUID_SERVCLASS_IMAGING_RESPONDER, /* BTA_BIP_SERVICE_ID */ + UUID_SERVCLASS_PANU, /* BTA_PANU_SERVICE_ID */ + UUID_SERVCLASS_NAP, /* BTA_NAP_SERVICE_ID */ + UUID_SERVCLASS_GN, /* BTA_GN_SERVICE_ID */ + UUID_SERVCLASS_SAP, /* BTA_SAP_SERVICE_ID */ + UUID_SERVCLASS_AUDIO_SINK, /* BTA_A2DP_SERVICE_ID */ + UUID_SERVCLASS_AV_REMOTE_CONTROL, /* BTA_AVRCP_SERVICE_ID */ + UUID_SERVCLASS_HUMAN_INTERFACE, /* BTA_HID_SERVICE_ID */ + UUID_SERVCLASS_VIDEO_SINK, /* BTA_VDP_SERVICE_ID */ + UUID_SERVCLASS_PBAP_PSE, /* BTA_PBAP_SERVICE_ID */ + UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, /* BTA_HSP_SERVICE_ID */ + UUID_SERVCLASS_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */ + UUID_SERVCLASS_MESSAGE_ACCESS, /* BTA_MAP_SERVICE_ID */ + UUID_SERVCLASS_MESSAGE_NOTIFICATION, /* BTA_MN_SERVICE_ID */ + UUID_SERVCLASS_HDP_PROFILE, /* BTA_HDP_SERVICE_ID */ + UUID_SERVCLASS_PBAP_PCE /* BTA_PCE_SERVICE_ID */ +#if BLE_INCLUDED && BTA_GATT_INCLUDED + ,UUID_PROTOCOL_ATT /* BTA_GATT_SERVICE_ID */ +#endif +}; + +/* + * NOTE : The number of element in bta_service_id_to_btm_srv_id_lkup_tbl should be matching with + * the value BTA_MAX_SERVICE_ID in bta_api.h + * + * i.e., If you add new Service ID for BTA, the correct security ID of the new service + * from Security service definitions (btm_api.h) should be added to this lookup table. + */ +const UINT32 bta_service_id_to_btm_srv_id_lkup_tbl [BTA_MAX_SERVICE_ID] = +{ + 0, /* Reserved */ + BTM_SEC_SERVICE_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */ + BTM_SEC_SERVICE_DUN, /* BTA_DUN_SERVICE_ID */ + BTM_SEC_SERVICE_AVDTP, /* BTA_AUDIO_SOURCE_SERVICE_ID */ + BTM_SEC_SERVICE_LAN_ACCESS, /* BTA_LAP_SERVICE_ID */ + BTM_SEC_SERVICE_HEADSET_AG, /* BTA_HSP_SERVICE_ID */ + BTM_SEC_SERVICE_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */ + BTM_SEC_SERVICE_OBEX, /* BTA_OPP_SERVICE_ID */ + BTM_SEC_SERVICE_OBEX_FTP, /* BTA_FTP_SERVICE_ID */ + BTM_SEC_SERVICE_CORDLESS, /* BTA_CTP_SERVICE_ID */ + BTM_SEC_SERVICE_INTERCOM, /* BTA_ICP_SERVICE_ID */ + BTM_SEC_SERVICE_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */ + BTM_SEC_SERVICE_BPP_JOB, /* BTA_BPP_SERVICE_ID */ + BTM_SEC_SERVICE_BIP, /* BTA_BIP_SERVICE_ID */ + BTM_SEC_SERVICE_BNEP_PANU, /* BTA_PANU_SERVICE_ID */ + BTM_SEC_SERVICE_BNEP_NAP, /* BTA_NAP_SERVICE_ID */ + BTM_SEC_SERVICE_BNEP_GN, /* BTA_GN_SERVICE_ID */ + BTM_SEC_SERVICE_SAP, /* BTA_SAP_SERVICE_ID */ + BTM_SEC_SERVICE_AVDTP, /* BTA_A2DP_SERVICE_ID */ + BTM_SEC_SERVICE_AVCTP, /* BTA_AVRCP_SERVICE_ID */ + BTM_SEC_SERVICE_HID_SEC_CTRL, /* BTA_HID_SERVICE_ID */ + BTM_SEC_SERVICE_AVDTP, /* BTA_VDP_SERVICE_ID */ + BTM_SEC_SERVICE_PBAP, /* BTA_PBAP_SERVICE_ID */ + BTM_SEC_SERVICE_HEADSET, /* BTA_HSP_HS_SERVICE_ID */ + BTM_SEC_SERVICE_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */ + BTM_SEC_SERVICE_MAP, /* BTA_MAP_SERVICE_ID */ + BTM_SEC_SERVICE_MAP, /* BTA_MN_SERVICE_ID */ + BTM_SEC_SERVICE_HDP_SNK, /* BTA_HDP_SERVICE_ID */ + BTM_SEC_SERVICE_PBAP /* BTA_PCE_SERVICE_ID */ +#if BLE_INCLUDED && BTA_GATT_INCLUDED + ,BTM_SEC_SERVICE_ATT /* BTA_GATT_SERVICE_ID */ +#endif +}; + +/* bta security callback */ +const tBTM_APPL_INFO bta_security = +{ + &bta_dm_authorize_cback, + &bta_dm_pin_cback, + &bta_dm_new_link_key_cback, + &bta_dm_link_key_request_cback, + &bta_dm_authentication_complete_cback, + NULL, + &bta_dm_bond_cancel_complete_cback, +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + &bta_dm_sp_cback +#else + NULL +#endif +#if BLE_INCLUDED == TRUE +#if SMP_INCLUDED == TRUE + ,&bta_dm_ble_smp_cback +#endif + ,&bta_dm_ble_id_key_cback +#endif + +}; + +/* TBD... To be moved to some conf file..? */ +#define BTA_DM_MAX_ROLE_SWITCH_BLACKLIST_COUNT 5 +const tBTA_DM_LMP_VER_INFO bta_role_switch_blacklist[BTA_DM_MAX_ROLE_SWITCH_BLACKLIST_COUNT] = +{ + {0x000F,0x2000,0x04}, + {0x00,0x00,0x00}, + {0x00,0x00,0x00}, + {0x00,0x00,0x00}, + {0x00,0x00,0x00} +}; + +#define MAX_DISC_RAW_DATA_BUF (4096) +UINT8 g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF]; + +/******************************************************************************* +** +** Function bta_dm_app_ready_timer_cback +** +** Description allow sending EIR to controller +** +** +** Returns void +** +*******************************************************************************/ +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) +static void bta_dm_app_ready_timer_cback (TIMER_LIST_ENT *p_tle) +{ + bta_dm_set_eir (NULL); +} +#else +#define bta_dm_app_ready_timer_cback (x) +#endif + +/******************************************************************************* +** +** Function bta_dm_enable +** +** Description Initialises the BT device manager +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_enable(tBTA_DM_MSG *p_data) +{ + tBTA_SYS_HW_MSG *sys_enable_event; + tBTA_DM_SEC sec_event; + + + /* if already in use, return an error */ + if( bta_dm_cb.is_bta_dm_active == TRUE ) + { + APPL_TRACE_WARNING0("bta_dm_enable - device already started by another application"); + memset(&sec_event.enable, 0, sizeof ( tBTA_DM_ENABLE )); + sec_event.enable.status = BTA_FAILURE; + if( p_data->enable.p_sec_cback != NULL ) + p_data->enable.p_sec_cback (BTA_DM_ENABLE_EVT, &sec_event); + return; + } + + + /* first, register our callback to SYS HW manager */ + bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback ); + + /* make sure security callback is saved - if no callback, do not erase the previous one, + it could be an error recovery mechanism */ + if( p_data->enable.p_sec_cback != NULL ) + bta_dm_cb.p_sec_cback = p_data->enable.p_sec_cback; + /* notify BTA DM is now active */ + bta_dm_cb.is_bta_dm_active = TRUE; + + /* send a message to BTA SYS */ + if ((sys_enable_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + sys_enable_event->hdr.event = BTA_SYS_API_ENABLE_EVT; + sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH; + + bta_sys_sendmsg(sys_enable_event); + + } + + + +} + + + +/******************************************************************************* +** +** Function bta_dm_sys_hw_cback +** +** Description callback register to SYS to get HW status updates +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ) +{ + DEV_CLASS dev_class; + tBTA_DM_SEC_CBACK *temp_cback; +#if BLE_INCLUDED == TRUE + UINT8 key_mask = 0; + BT_OCTET16 er; + tBTA_BLE_LOCAL_ID_KEYS id_key; + tBT_UUID app_uuid = {LEN_UUID_128,{0}}; +#endif + APPL_TRACE_DEBUG1(" bta_dm_sys_hw_cback with event: %i" , status ); + + /* On H/W error evt, report to the registered DM application callback */ + if (status == BTA_SYS_HW_ERROR_EVT) { + if( bta_dm_cb.p_sec_cback != NULL ) + bta_dm_cb.p_sec_cback(BTA_DM_HW_ERROR_EVT, NULL); + return; + } + if( status == BTA_SYS_HW_OFF_EVT ) + { + if( bta_dm_cb.p_sec_cback != NULL ) + bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL); + + /* reinitialize the control block */ + memset(&bta_dm_cb, 0, sizeof(bta_dm_cb)); + + /* unregister from SYS */ + bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH ); + /* notify BTA DM is now unactive */ + bta_dm_cb.is_bta_dm_active = FALSE; + } + else + if( status == BTA_SYS_HW_ON_EVT ) + { + /* FIXME: We should not unregister as the SYS shall invoke this callback on a H/W error. + * We need to revisit when this platform has more than one BLuetooth H/W chip */ + //bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH); + + /* save security callback */ + temp_cback = bta_dm_cb.p_sec_cback; + /* make sure the control block is properly initialized */ + memset(&bta_dm_cb, 0, sizeof(bta_dm_cb)); + /* and retrieve the callback */ + bta_dm_cb.p_sec_cback=temp_cback; + bta_dm_cb.is_bta_dm_active = TRUE; + + /* hw is ready, go on with BTA DM initialization */ + memset(&bta_dm_search_cb, 0x00, sizeof(bta_dm_search_cb)); + memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs)); + memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB)); + + memcpy(dev_class, bta_dm_cfg.dev_class, sizeof(dev_class)); + BTM_SetDeviceClass (dev_class); + +#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) + /* load BLE local information: ID keys, ER if available */ + bta_dm_co_ble_load_local_keys(&key_mask, er, &id_key); + + if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ER) + { + BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ER, (tBTM_BLE_LOCAL_KEYS *)&er); + } + if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ID) + { + BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ID, (tBTM_BLE_LOCAL_KEYS *)&id_key); + } +#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + memset (&app_uuid.uu.uuid128, 0x87, LEN_UUID_128); + BTA_GATTC_AppRegister(&app_uuid, bta_dm_gattc_callback); +#endif +#endif + + BTM_SecRegister((tBTM_APPL_INFO*)&bta_security); + BTM_SetDefaultLinkSuperTout(bta_dm_cfg.link_timeout); + BTM_WritePageTimeout(bta_dm_cfg.page_timeout); + bta_dm_cb.cur_policy = bta_dm_cfg.policy_settings; + BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy); +#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) + BTM_RegBusyLevelNotif (bta_dm_bl_change_cback, NULL, BTM_BL_UPDATE_MASK|BTM_BL_ROLE_CHG_MASK); +#else + BTM_AclRegisterForChanges(bta_dm_acl_change_cback); +#endif + /* Earlier, we used to invoke BTM_ReadLocalAddr which was just copying the bd_addr + from the control block and invoking the callback which was sending the DM_ENABLE_EVT. + But then we have a few HCI commands being invoked above which were still in progress + when the ENABLE_EVT was sent. So modified this to fetch the local name which forces + the DM_ENABLE_EVT to be sent only after all the init steps are complete */ + BTM_ReadLocalDeviceNameFromController((tBTM_CMPL_CB *)bta_dm_local_name_cback); + + bta_sys_rm_register((tBTA_SYS_CONN_CBACK*)bta_dm_rm_cback); + + /* initialize bluetooth low power manager */ + bta_dm_init_pm(); + + bta_sys_policy_register((tBTA_SYS_CONN_CBACK*)bta_dm_policy_cback); + + + // BLUEDROID REMOVE ?? +#if 0 +#if 1 + /* Create broadcom primary DI record */ + if(WBT_ExtCreateRecord()) + { +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE ) + /* while app_ready_timer is running, BTA DM doesn't send EIR to controller */ + bta_dm_cb.app_ready_timer.p_cback = (TIMER_CBACK*)&bta_dm_app_ready_timer_cback; + bta_sys_start_timer(&bta_dm_cb.app_ready_timer, 0, 100); + + bta_sys_add_uuid(UUID_SERVCLASS_PNP_INFORMATION); +#endif + bta_dm_di_cb.di_handle[bta_dm_di_cb.di_num] = 0; /* primary DI record */ + bta_dm_di_cb.di_num ++; + } +#else /* Eventually implement pin code */ + if (WBT_ExtCreateRecord()) + WBT_ExtAddPinCode(); +#endif +#endif + } + else + APPL_TRACE_DEBUG0(" --- ignored event"); + +} + + +/******************************************************************************* +** +** Function bta_dm_disable +** +** Description Disables the BT device manager +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disable (tBTA_DM_MSG *p_data) +{ + /* Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after last channel is closed) */ + L2CA_SetIdleTimeoutByBdAddr((UINT8 *)BT_BD_ANY, 0); + + /* disable all active subsystems */ + bta_sys_disable(BTA_SYS_HW_BLUETOOTH); + + BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0); + BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0); + + bta_dm_disable_pm(); + + bta_dm_cb.disabling = TRUE; + + bta_dm_search_cancel(NULL); + + if(BTM_GetNumAclLinks()==0) + { +#if (defined(BTA_DISABLE_DELAY) && BTA_DISABLE_DELAY > 0) + /* If BTA_DISABLE_DELAY is defined and greater than zero, then delay the shutdown by + * BTA_DISABLE_DELAY milliseconds + */ + APPL_TRACE_WARNING2("%s BTA_DISABLE_DELAY set to %d ms", + __FUNCTION__, BTA_DISABLE_DELAY); + bta_sys_stop_timer(&bta_dm_cb.disable_timer); + bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_conn_down_timer_cback; + bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, BTA_DISABLE_DELAY); +#else + bta_dm_disable_conn_down_timer_cback(NULL); +#endif + } + else + { + bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_timer_cback; + bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 5000); + } + +} + +/******************************************************************************* +** +** Function bta_dm_disable_timer_cback +** +** Description Called if the disable timer expires +** Used to close ACL connections which are still active +** +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_disable_timer_cback (TIMER_LIST_ENT *p_tle) +{ + + UINT8 i; + + APPL_TRACE_EVENT0(" bta_dm_disable_timer_cback "); + + if(BTM_GetNumAclLinks()) + { + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + btm_remove_acl(bta_dm_cb.device_list.peer_device[i].peer_bdaddr); + + } + + } + else + { + bta_dm_cb.disabling = FALSE; + + bta_sys_remove_uuid(UUID_SERVCLASS_PNP_INFORMATION); + bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL); + } +} + + + + +/******************************************************************************* +** +** Function bta_dm_set_dev_name +** +** Description Sets local device name +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_set_dev_name (tBTA_DM_MSG *p_data) +{ + + BTM_SetLocalDeviceName((char*)p_data->set_name.name); +#if (BTM_EIR_SERVER_INCLUDED == TRUE) + bta_dm_set_eir ((char*)p_data->set_name.name); +#endif +} + +/******************************************************************************* +** +** Function bta_dm_set_visibility +** +** Description Sets discoverability, connectability and pairability +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_set_visibility (tBTA_DM_MSG *p_data) +{ + + + /* set modes for Discoverability and connectability if not ignore */ + if (p_data->set_visibility.disc_mode != BTA_DM_IGNORE) + BTM_SetDiscoverability((UINT8)p_data->set_visibility.disc_mode, + bta_dm_cb.inquiry_scan_window, + bta_dm_cb.inquiry_scan_interval); + + if (p_data->set_visibility.conn_mode != BTA_DM_IGNORE) + BTM_SetConnectability((UINT8)p_data->set_visibility.conn_mode, + bta_dm_cb.page_scan_window, + bta_dm_cb.page_scan_interval); + + /* Send False or True if not ignore */ + if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE ) + { + + if (p_data->set_visibility.pair_mode == BTA_DM_NON_PAIRABLE) + bta_dm_cb.disable_pair_mode = TRUE; + else + bta_dm_cb.disable_pair_mode = FALSE; + + } + + /* Send False or True if not ignore */ + if (p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE) + { + + if (p_data->set_visibility.conn_paired_only == BTA_DM_CONN_ALL) + bta_dm_cb.conn_paired_only = FALSE; + else + bta_dm_cb.conn_paired_only = TRUE; + + } + + /* Change mode if either mode is not ignore */ + if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE || p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE) + BTM_SetPairableMode((BOOLEAN)(!(bta_dm_cb.disable_pair_mode)),bta_dm_cb.conn_paired_only); + +} + + +/******************************************************************************* +** +** Function bta_dm_set_afhchannels +** +** Description This function sets the AFH first and +** last disable channel, so channels within +** that range are disabled. +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_set_afhchannels (tBTA_DM_MSG *p_data) +{ + BTM_SetAfhChannels(p_data->set_afhchannels.first,p_data->set_afhchannels.last); + +} + + +/******************************************************************************* +** +** Function bta_dm_vendor_spec_command +** +** Description Send a vendor specific command to the controller +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_vendor_spec_command (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS status; + + status = BTM_VendorSpecificCommand(p_data->vendor_command.opcode,p_data->vendor_command.param_len,p_data->vendor_command.p_param_buf, p_data->vendor_command.p_cback); + +} + + +/******************************************************************************* +** +** Function bta_dm_tx_inqpower +** +** Description write inquiry tx power. +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_tx_inqpower(tBTA_DM_MSG *p_data) +{ + if (BTM_WriteInquiryTxPower (p_data->tx_inq_pwr.tx_power) == BTM_ILLEGAL_VALUE) + { + APPL_TRACE_ERROR1("Invalid Inquiry Tx Power: %d", p_data->tx_inq_pwr.tx_power); + } + return; +} + +/******************************************************************************* +** +** Function bta_dm_remove_device +** +** Description Removes device, Disconnects ACL link if required. +**** +*******************************************************************************/ +void bta_dm_remove_device (tBTA_DM_MSG *p_data) +{ + tBTA_DM_API_REMOVE_DEVICE *p_dev = &p_data->remove_dev; + int i; + tBTA_DM_SEC sec_event; + + if (BTM_IsAclConnectionUp(p_dev->bd_addr)) + { + /* Take the link down first, and mark the device for removal when disconnected */ + btm_remove_acl( p_dev->bd_addr) ; + + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + if(!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_dev->bd_addr)) + break; + } + + if(i < bta_dm_cb.device_list.count) + { + bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING; + } + } + else /* Ok to remove the device in application layer */ + { + BTM_SecDeleteDevice(p_dev->bd_addr); + if( bta_dm_cb.p_sec_cback ) + { + bdcpy(sec_event.link_down.bd_addr, p_dev->bd_addr); + /* No connection, set status to success (acl disc code not valid) */ + sec_event.link_down.status = HCI_SUCCESS; + bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &sec_event); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_add_device +** +** Description This function adds a Link Key to an security database entry. +** It is normally called during host startup to restore all required information +** stored in the NVRAM. +**** +*******************************************************************************/ +void bta_dm_add_device (tBTA_DM_MSG *p_data) +{ + tBTA_DM_API_ADD_DEVICE *p_dev = &p_data->add_dev; + UINT8 *p_dc = NULL; + UINT8 *p_lc = NULL; + UINT32 trusted_services_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; + UINT8 index = 0; + UINT8 btm_mask_index = 0; + + memset (trusted_services_mask, 0, sizeof(trusted_services_mask)); + + /* If not all zeros, the device class has been specified */ + if (p_dev->dc_known) + p_dc = (UINT8 *)p_dev->dc; + + if (p_dev->link_key_known) + p_lc = (UINT8 *)p_dev->link_key; + + if (p_dev->is_trusted) + { + /* covert BTA service mask to BTM mask */ + while (p_dev->tm && (index < BTA_MAX_SERVICE_ID)) + { + if (p_dev->tm & (UINT32)(1<<index)) + { + + btm_mask_index = bta_service_id_to_btm_srv_id_lkup_tbl[index] / BTM_SEC_ARRAY_BITS; + trusted_services_mask[btm_mask_index] |= (UINT32)(1 << (bta_service_id_to_btm_srv_id_lkup_tbl[index] - (UINT32)(btm_mask_index * 32))); + + p_dev->tm &= (UINT32)(~(1<<index)); + + } + index++; + } + } + + if (!BTM_SecAddDevice (p_dev->bd_addr, p_dc, p_dev->bd_name, p_dev->features, + trusted_services_mask, p_lc, p_dev->key_type, p_dev->io_cap)) + { + APPL_TRACE_ERROR2 ("BTA_DM: Error adding device %08x%04x", + (p_dev->bd_addr[0]<<24)+(p_dev->bd_addr[1]<<16)+(p_dev->bd_addr[2]<<8)+p_dev->bd_addr[3], + (p_dev->bd_addr[4]<<8)+p_dev->bd_addr[5]); + } +} + +/******************************************************************************* +** +** Function bta_dm_bond +** +** Description Bonds with peer device +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_bond (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS status; + tBTA_DM_SEC sec_event; + char *p_name; + + status = BTM_SecBond ( p_data->bond.bd_addr, 0, NULL, 0 ); + + if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)) + { + + p_name = BTM_SecReadDevName(p_data->bond.bd_addr); + if (!p_name) + p_name = ""; + + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr); + memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN-1)); + sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 0; + +/* taken care of by memset [above] + sec_event.auth_cmpl.key_present = FALSE; + sec_event.auth_cmpl.success = FALSE; +*/ + sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND; + if (status == BTM_SUCCESS) + sec_event.auth_cmpl.success = TRUE; + + bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + } + +} + +/******************************************************************************* +** +** Function bta_dm_bond_cancel +** +** Description Cancels bonding with a peer device +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_bond_cancel (tBTA_DM_MSG *p_data) +{ + tBTM_STATUS status; + tBTA_DM_SEC sec_event; + + APPL_TRACE_EVENT0(" bta_dm_bond_cancel "); + status = BTM_SecBondCancel ( p_data->bond_cancel.bd_addr ); + + if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED && status != BTM_SUCCESS)) + { + sec_event.bond_cancel_cmpl.result = BTA_FAILURE; + + bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event); + } + +} + +/******************************************************************************* +** +** Function bta_dm_pin_reply +** +** Description Send the pin_reply to a request from BTM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_pin_reply (tBTA_DM_MSG *p_data) +{ + UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; + UINT32 * current_trusted_mask; + + current_trusted_mask = BTM_ReadTrustedMask(p_data->pin_reply.bd_addr); + + if(current_trusted_mask) + { + memcpy(trusted_mask, current_trusted_mask, sizeof(trusted_mask)); + } + else + { + memset(trusted_mask, 0, sizeof(trusted_mask)); + } + + if(p_data->pin_reply.accept) + { + + BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_SUCCESS, p_data->pin_reply.pin_len, p_data->pin_reply.p_pin, trusted_mask ); + } + else + { + BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_NOT_AUTHORIZED, 0, NULL, trusted_mask ); + } + +} + +/******************************************************************************* +** +** Function bta_dm_link_policy +** +** Description remove/set link policy mask. +** wake the link, is sniff/park is removed +** +** Returns void +** +*******************************************************************************/ +void bta_dm_link_policy (tBTA_DM_MSG *p_data) +{ + tBTA_DM_PEER_DEVICE *p_dev; + + p_dev = bta_dm_find_peer_device(p_data->link_policy.bd_addr); + if(!p_dev) + return; + + APPL_TRACE_DEBUG2(" bta_dm_link_policy set:%d, policy:0x%x", + p_data->link_policy.set, p_data->link_policy.policy_mask); + if(p_data->link_policy.set) + { + /* restore the default link policy */ + p_dev->link_policy |= p_data->link_policy.policy_mask; + BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy)); + } + else + { + /* clear the policy from the default link policy */ + p_dev->link_policy &= (~p_data->link_policy.policy_mask); + BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy)); + + if(p_data->link_policy.policy_mask & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)) + { + /* if clearing sniff/park, wake the link */ + bta_dm_pm_active(p_dev->peer_bdaddr); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_policy_cback +** +** Description process the link policy changes +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + tBTA_DM_PEER_DEVICE *p_dev = NULL; + UINT16 policy = app_id; + UINT32 mask = (UINT32)(1 << id); + + if(peer_addr) + p_dev = bta_dm_find_peer_device(peer_addr); + + APPL_TRACE_DEBUG2(" bta_dm_policy_cback cmd:%d, policy:0x%x", + status, policy); + switch(status) + { + case BTA_SYS_PLCY_SET: + if(!p_dev) + return; + /* restore the default link policy */ + p_dev->link_policy |= policy; + BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy)); + break; + + case BTA_SYS_PLCY_CLR: + if(!p_dev) + return; + /* clear the policy from the default link policy */ + p_dev->link_policy &= (~policy); + BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy)); + + if(policy & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)) + { + /* if clearing sniff/park, wake the link */ + bta_dm_pm_active(p_dev->peer_bdaddr); + } + break; + + case BTA_SYS_PLCY_DEF_SET: + /* want to restore/set the role switch policy */ + bta_dm_cb.role_policy_mask &= ~mask; + if(0 == bta_dm_cb.role_policy_mask) + { + /* if nobody wants to insist on the role */ + bta_dm_cb.cur_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy); + } + break; + + case BTA_SYS_PLCY_DEF_CLR: + /* want to remove the role switch policy */ + bta_dm_cb.role_policy_mask |= mask; + bta_dm_cb.cur_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH; + BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy); + break; + } +} + + +/******************************************************************************* +** +** Function bta_dm_auth_reply +** +** Description Send the authorization reply to a request from BTM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_auth_reply (tBTA_DM_MSG *p_data) +{ + + UINT32 trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; + UINT8 btm_mask_index = 0; + UINT32 * current_trusted_mask; + + current_trusted_mask = BTM_ReadTrustedMask(p_data->auth_reply.bd_addr); + + if(current_trusted_mask) + { + memcpy(trusted_mask, current_trusted_mask, sizeof(trusted_mask)); + } + else + { + memset(trusted_mask, 0, sizeof(trusted_mask)); + } + + if(p_data->auth_reply.response != BTA_DM_NOT_AUTH) + { + if(p_data->auth_reply.response == BTA_DM_AUTH_PERM) + { + if(p_data->auth_reply.service < BTA_MAX_SERVICE_ID) + { + /* convert BTA service id to BTM mask */ + btm_mask_index = bta_service_id_to_btm_srv_id_lkup_tbl[p_data->auth_reply.service] / 32; + trusted_mask[btm_mask_index] |= (UINT32)(1 << (bta_service_id_to_btm_srv_id_lkup_tbl[p_data->auth_reply.service] - (UINT32)(btm_mask_index * 32))); + + } + } + BTM_DeviceAuthorized (p_data->auth_reply.bd_addr, BTM_SUCCESS,trusted_mask); + } + else + { + BTM_DeviceAuthorized (p_data->auth_reply.bd_addr, BTM_NOT_AUTHORIZED,trusted_mask); + } + +} + +/******************************************************************************* +** +** Function bta_dm_confirm +** +** Description Send the user confirm request reply in response to a +** request from BTM +** +** Returns void +** +*******************************************************************************/ +void bta_dm_confirm(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS res = BTM_NOT_AUTHORIZED; + + if(p_data->confirm.accept == TRUE) + res = BTM_SUCCESS; + BTM_ConfirmReqReply(res, p_data->confirm.bd_addr); +} + +/******************************************************************************* +** +** Function bta_dm_passkey_cancel +** +** Description Send the passkey cancel from SP initiator by sending a negative +** passkey request replyreply. +** Returns void +** +*******************************************************************************/ +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) +void bta_dm_passkey_cancel(tBTA_DM_MSG *p_data) +{ + BTM_PasskeyReqReply(BTM_NOT_AUTHORIZED, p_data->passkey_cancel.bd_addr, 0); +} +#endif + +/******************************************************************************* +** +** Function bta_dm_loc_oob +** +** Description Retrieve the OOB data from the local LM +** +** Returns void +** +*******************************************************************************/ +#if (BTM_OOB_INCLUDED == TRUE) +void bta_dm_loc_oob(tBTA_DM_MSG *p_data) +{ + BTM_ReadLocalOobData(); +} + +/******************************************************************************* +** +** Function bta_dm_ci_io_req_act +** +** Description respond to the IO capabilities request from BTM +** +** Returns void +** +*******************************************************************************/ +void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data) +{ + tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO; + if(p_data->ci_io_req.auth_req) + auth_req = BTM_AUTH_AP_YES; + BTM_IoCapRsp(p_data->ci_io_req.bd_addr, p_data->ci_io_req.io_cap, + p_data->ci_io_req.oob_data, auth_req); +} + +/******************************************************************************* +** +** Function bta_dm_ci_rmt_oob_act +** +** Description respond to the OOB data request for the remote device from BTM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data) +{ + tBTM_STATUS res = BTM_NOT_AUTHORIZED; + + if(p_data->ci_rmt_oob.accept == TRUE) + res = BTM_SUCCESS; + BTM_RemoteOobDataReply(res, p_data->ci_rmt_oob.bd_addr, + p_data->ci_rmt_oob.c, p_data->ci_rmt_oob.r ); +} +#endif /* BTM_OOB_INCLUDED */ + +/******************************************************************************* +** +** Function bta_dm_search_start +** +** Description Starts an inquiry +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_start (tBTA_DM_MSG *p_data) +{ + tBTM_INQUIRY_CMPL result; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + UINT16 len = (UINT16)(sizeof(tBT_UUID) * p_data->search.num_uuid); +#endif + + APPL_TRACE_DEBUG1("bta_dm_search_start avoid_scatter=%d", bta_dm_cfg.avoid_scatter); + if (bta_dm_cfg.avoid_scatter && + (p_data->search.rs_res == BTA_DM_RS_NONE) && bta_dm_check_av(BTA_DM_API_SEARCH_EVT)) + { + memcpy(&bta_dm_cb.search_msg, &p_data->search, sizeof(tBTA_DM_API_SEARCH)); + return; + } + + BTM_ClearInqDb(NULL); + /* save search params */ + bta_dm_search_cb.p_search_cback = p_data->search.p_cback; + bta_dm_search_cb.services = p_data->search.services; + +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid); + + if ((bta_dm_search_cb.num_uuid = p_data->search.num_uuid) != 0 && + p_data->search.p_uuid != NULL) + { + if ((bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len)) == NULL) + { + APPL_TRACE_ERROR0("bta_dm_search_start no resources"); + + result.status = BTA_FAILURE; + result.num_resp = 0; + bta_dm_inq_cmpl_cb ((void *)&result); + return; + } +// bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len); + memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->search.p_uuid, len); + } + + if (p_data->search.inq_params.mode & BTM_LIMITED_INQUIRY) + p_data->search.inq_params.mode |= BTM_BLE_LIMITED_INQUIRY; + else + p_data->search.inq_params.mode |= BTM_BLE_GENERAL_INQUIRY; +#endif + result.status = BTM_StartInquiry( (tBTM_INQ_PARMS*)&p_data->search.inq_params, + bta_dm_inq_results_cb, + (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb); + + APPL_TRACE_EVENT1("bta_dm_search_start status=%d", result.status); + if (result.status != BTM_CMD_STARTED) + { + result.num_resp = 0; + bta_dm_inq_cmpl_cb ((void *)&result); + } + +} + +/******************************************************************************* +** +** Function bta_dm_search_cancel +** +** Description Cancels an ongoing search for devices +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cancel (tBTA_DM_MSG *p_data) +{ + + tBTA_DM_MSG * p_msg; + + if(BTM_IsInquiryActive()) + { + BTM_CancelInquiry(); + bta_dm_search_cancel_notify(NULL); + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + + } + } + /* If no Service Search going on then issue cancel remote name in case it is active */ + else if (!bta_dm_search_cb.name_discover_done) + { + BTM_CancelRemoteDeviceName(); + } +#if ((BLE_INCLUDED == TRUE) && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + if (bta_dm_search_cb.gatt_disc_active) + { + bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr); + } +#endif +} + +/******************************************************************************* +** +** Function bta_dm_discover +** +** Description Discovers services on a remote device +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_discover (tBTA_DM_MSG *p_data) +{ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + UINT16 len = (UINT16)(sizeof(tBT_UUID) * p_data->discover.num_uuid); +#endif + APPL_TRACE_EVENT2("bta_dm_discover services_to_search=0x%04X, sdp_search=%d", + p_data->discover.services, p_data->discover.sdp_search); + + /* save the search condition */ + bta_dm_search_cb.services = p_data->discover.services; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid); + if ((bta_dm_search_cb.num_uuid = p_data->discover.num_uuid) != 0 && + p_data->discover.p_uuid != NULL) + { + if ((bta_dm_search_cb.p_srvc_uuid = (tBT_UUID *)GKI_getbuf(len)) == NULL) + { + p_data->discover.p_cback(BTA_DM_DISC_CMPL_EVT, NULL); + return; + } + memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->discover.p_uuid, len); + } + bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid; +#endif + + bta_dm_search_cb.p_search_cback = p_data->discover.p_cback; + bta_dm_search_cb.sdp_search = p_data->discover.sdp_search; + bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; + bta_dm_search_cb.service_index = 0; + bta_dm_search_cb.services_found = 0; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_search_cb.sdp_search = p_data->discover.sdp_search; + bta_dm_search_cb.p_btm_inq_info = BTM_InqDbRead (p_data->discover.bd_addr); + + bta_dm_search_cb.name_discover_done = FALSE; + memcpy(&bta_dm_search_cb.uuid, &p_data->discover.uuid, sizeof(tSDP_UUID)); + bta_dm_discover_device(p_data->discover.bd_addr); +} + +/******************************************************************************* +** +** Function bta_dm_di_disc_cmpl +** +** Description Sends event to application when DI discovery complete +** +** Returns void +** +*******************************************************************************/ +void bta_dm_di_disc_cmpl(tBTA_DM_MSG *p_data) +{ + tBTA_DM_DI_DISC_CMPL di_disc; + + memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL)); + bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr); + + if((p_data->hdr.offset == SDP_SUCCESS) + || (p_data->hdr.offset == SDP_DB_FULL)) + { + di_disc.num_record = SDP_GetNumDiRecords(bta_dm_di_cb.p_di_db); + } + else + di_disc.result = BTA_FAILURE; + + bta_dm_di_cb.p_di_db = NULL; + bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT, (tBTA_DM_SEARCH *) &di_disc); +} + +/******************************************************************************* +** +** Function bta_dm_di_disc_callback +** +** Description This function queries a remote device for DI information. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_di_disc_callback(UINT16 result) +{ + tBTA_DM_MSG * p_msg; + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT; + p_msg->hdr.offset = result; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_di_disc +** +** Description This function queries a remote device for DI information. +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_di_disc (tBTA_DM_MSG *p_data) +{ + UINT16 result = BTA_FAILURE; + tBTA_DM_MSG *p_msg; + + bta_dm_search_cb.p_search_cback = p_data->di_disc.p_cback; + bdcpy(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.bd_addr); + bta_dm_di_cb.p_di_db = p_data->di_disc.p_sdp_db; + + if((bta_dm_search_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_DM_SDP_DB_SIZE)) != NULL) + { + if ( SDP_DiDiscover(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.p_sdp_db, + p_data->di_disc.len, bta_dm_di_disc_callback) == SDP_SUCCESS) + { + result = BTA_SUCCESS; + } + } + else + { + APPL_TRACE_ERROR0("No buffer to start DI discovery"); + } + + if ( result == BTA_FAILURE && + (p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT; + p_data->hdr.offset = result; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_read_remote_device_name +** +** Description Initiate to get remote device name +** +** Returns TRUE if started to get remote name +** +*******************************************************************************/ +static BOOLEAN bta_dm_read_remote_device_name (BD_ADDR bd_addr) +{ + tBTM_STATUS btm_status; + + APPL_TRACE_DEBUG0("bta_dm_read_remote_device_name"); + + bdcpy(bta_dm_search_cb.peer_bdaddr, bd_addr); + bta_dm_search_cb.peer_name[0] = 0; + + btm_status = BTM_ReadRemoteDeviceName (bta_dm_search_cb.peer_bdaddr, + (tBTM_CMPL_CB *) bta_dm_remname_cback); + + if ( btm_status == BTM_CMD_STARTED ) + { + APPL_TRACE_DEBUG0("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is started"); + + return (TRUE); + } + else if ( btm_status == BTM_BUSY ) + { + APPL_TRACE_DEBUG0("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is busy"); + + /* Remote name discovery is on going now so BTM cannot notify through "bta_dm_remname_cback" */ + /* adding callback to get notified that current reading remore name done */ + BTM_SecAddRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + + return (TRUE); + } + else + { + APPL_TRACE_WARNING1("bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName returns 0x%02X", btm_status); + + return (FALSE); + } +} + +/******************************************************************************* +** +** Function bta_dm_inq_cmpl +** +** Description Process the inquiry complete event from BTM +** +** Returns void +** +*******************************************************************************/ +void bta_dm_inq_cmpl (tBTA_DM_MSG *p_data) +{ + tBTA_DM_MSG * p_msg; + tBTA_DM_SEARCH data; + + APPL_TRACE_DEBUG0("bta_dm_inq_cmpl"); + + data.inq_cmpl.num_resps = p_data->inq_cmpl.num; + bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data); + + if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst()) != NULL) + { + /* start name and service discovery from the first device on inquiry result */ + bta_dm_search_cb.name_discover_done = FALSE; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); + } + else + { + /* no devices, search complete */ + bta_dm_search_cb.services = 0; + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + } + } + +/******************************************************************************* +** +** Function bta_dm_rmt_name +** +** Description Process the remote name result from BTM +** +** Returns void +** +*******************************************************************************/ +void bta_dm_rmt_name (tBTA_DM_MSG *p_data) +{ + APPL_TRACE_DEBUG0("bta_dm_rmt_name"); + + if( p_data->rem_name.result.disc_res.bd_name[0] && bta_dm_search_cb.p_btm_inq_info) + { + bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name = TRUE; + } + + bta_dm_discover_device(bta_dm_search_cb.peer_bdaddr); +} + +/******************************************************************************* +** +** Function bta_dm_disc_rmt_name +** +** Description Process the remote name result from BTM when application +** wants to find the name for a bdaddr +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disc_rmt_name (tBTA_DM_MSG *p_data) +{ + tBTM_INQ_INFO *p_btm_inq_info; + + APPL_TRACE_DEBUG0("bta_dm_disc_rmt_name"); + + p_btm_inq_info = BTM_InqDbRead (p_data->rem_name.result.disc_res.bd_addr); + if( p_btm_inq_info ) + { + if( p_data->rem_name.result.disc_res.bd_name[0] ) + { + p_btm_inq_info->appl_knows_rem_name = TRUE; + } + } + + bta_dm_discover_device(p_data->rem_name.result.disc_res.bd_addr); +} + +/******************************************************************************* +** +** Function bta_dm_sdp_result +** +** Description Process the discovery result from sdp +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sdp_result (tBTA_DM_MSG *p_data) +{ + + tSDP_DISC_REC *p_sdp_rec = NULL; + tBTA_DM_MSG *p_msg; + BOOLEAN service_found = FALSE; + BOOLEAN scn_found = FALSE; + UINT16 service = 0xFFFF; + tSDP_PROTOCOL_ELEM pe; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + tBT_UUID *p_uuid = bta_dm_search_cb.p_srvc_uuid; + tBTA_DM_SEARCH result; + tBT_UUID service_uuid; +#endif + + UINT32 num_uuids = 0; + UINT8 uuid_list[32][MAX_UUID_SIZE]; // assuming a max of 32 services + + if((p_data->sdp_event.sdp_result == SDP_SUCCESS) + || (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) + || (p_data->sdp_event.sdp_result == SDP_DB_FULL)) + { + APPL_TRACE_DEBUG1("sdp_result::0x%x", p_data->sdp_event.sdp_result); + do + { + + service_found = FALSE; + p_sdp_rec = NULL; + if( bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID+1) ) + { + p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db, &bta_dm_search_cb.uuid, p_sdp_rec); + + if (p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) + { + bta_dm_search_cb.peer_scn = (UINT8) pe.params[0]; + scn_found = TRUE; + } + } + else + { + service = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index-1]; + p_sdp_rec = SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, service, p_sdp_rec); + } +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + /* finished with BR/EDR services, now we check the result for GATT based service UUID */ + if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID) + { + if (bta_dm_search_cb.uuid_to_search != 0 && p_uuid != NULL) + { + p_uuid += (bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search); + /* only support 16 bits UUID for now */ + service = p_uuid->uu.uuid16; + + } + /* all GATT based services */ + do + { + /* find a service record, report it */ + p_sdp_rec = SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, + 0, p_sdp_rec); + if (p_sdp_rec) + { + if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) + { + /* send result back to app now, one by one */ + bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + result.disc_ble_res.service.len = service_uuid.len; + result.disc_ble_res.service.uu.uuid16 = service_uuid.uu.uuid16; + + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result); + } + } + + if (bta_dm_search_cb.uuid_to_search > 0) + break; + + } while (p_sdp_rec); + } + else +#endif + { + /* SDP_DB_FULL means some records with the + required attributes were received */ + if(((p_data->sdp_event.sdp_result == SDP_DB_FULL) && + bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) || + (p_sdp_rec != NULL)) + { + /* If Plug and Play service record, check to see if Broadcom stack */ + if (service == UUID_SERVCLASS_PNP_INFORMATION) + { + if (p_sdp_rec) + { + if (SDP_FindAttributeInRec (p_sdp_rec, ATTR_ID_EXT_BRCM_VERSION)) + { + service_found = TRUE; + } + } + } + else + { + service_found = TRUE; + } + + if (service_found) + { + UINT16 tmp_svc = 0xFFFF; + bta_dm_search_cb.services_found |= + (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index-1)); + tmp_svc = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index-1]; + /* Add to the list of UUIDs */ + sdpu_uuid16_to_uuid128(tmp_svc, uuid_list[num_uuids]); + num_uuids++; + } + } + } + + if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK && + bta_dm_search_cb.services_to_search == 0) + { +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + if ( bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID && + bta_dm_search_cb.uuid_to_search > 0) + bta_dm_search_cb.uuid_to_search --; + + if (bta_dm_search_cb.uuid_to_search == 0 || + bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID) +#endif + bta_dm_search_cb.service_index++; + } + else /* regular one service per search or PNP search */ + break; + + } + while(bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID); + +// GKI_freebuf(bta_dm_search_cb.p_sdp_db); +// bta_dm_search_cb.p_sdp_db = NULL; + APPL_TRACE_DEBUG1("bta_dm_sdp_result services_found = %04x", bta_dm_search_cb.services_found); + + /* Collect the 128-bit services here and put them into the list */ + if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) + { + p_sdp_rec = NULL; + do + { + tBT_UUID temp_uuid; + /* find a service record, report it */ + p_sdp_rec = SDP_FindServiceInDb_128bit(bta_dm_search_cb.p_sdp_db, p_sdp_rec); + if (p_sdp_rec) + { + if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid)) + { + memcpy(uuid_list[num_uuids], temp_uuid.uu.uuid128, MAX_UUID_SIZE); + num_uuids++; + } + } + } while (p_sdp_rec); + } + /* if there are more services to search for */ + if(bta_dm_search_cb.services_to_search) + { + /* Free up the p_sdp_db before checking the next one */ + bta_dm_free_sdp_db(NULL); + bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); + } + else + { + /* callbacks */ + /* start next bd_addr if necessary */ + + BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; + p_msg->disc_result.result.disc_res.p_raw_data = NULL; + p_msg->disc_result.result.disc_res.raw_data_size = 0; + p_msg->disc_result.result.disc_res.num_uuids = num_uuids; + p_msg->disc_result.result.disc_res.p_uuid_list = NULL; + if (num_uuids > 0) { + p_msg->disc_result.result.disc_res.p_uuid_list = (UINT8*)GKI_getbuf(num_uuids*MAX_UUID_SIZE); + if (p_msg->disc_result.result.disc_res.p_uuid_list) { + memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list, + num_uuids*MAX_UUID_SIZE); + } else { + p_msg->disc_result.result.disc_res.num_uuids = 0; + APPL_TRACE_ERROR1("%s: Unable to allocate memory for uuid_list", __FUNCTION__); + } + } + //copy the raw_data to the discovery result structure + // + APPL_TRACE_DEBUG2("bta_dm_sdp_result (raw_data used = 0x%x raw_data_ptr = 0x%x)\r\n",bta_dm_search_cb.p_sdp_db->raw_used, bta_dm_search_cb.p_sdp_db->raw_data); + + if ( bta_dm_search_cb.p_sdp_db != NULL && bta_dm_search_cb.p_sdp_db->raw_used != 0 && + bta_dm_search_cb.p_sdp_db->raw_data != NULL) { + + p_msg->disc_result.result.disc_res.p_raw_data = GKI_getbuf(bta_dm_search_cb.p_sdp_db->raw_used); + if ( NULL != p_msg->disc_result.result.disc_res.p_raw_data ) { + memcpy( p_msg->disc_result.result.disc_res.p_raw_data, + bta_dm_search_cb.p_sdp_db->raw_data, + bta_dm_search_cb.p_sdp_db->raw_used ); + + p_msg->disc_result.result.disc_res.raw_data_size = + bta_dm_search_cb.p_sdp_db->raw_used; + + } else { + APPL_TRACE_DEBUG1("bta_dm_sdp_result GKI Alloc failed to allocate %d bytes !!\r\n",bta_dm_search_cb.p_sdp_db->raw_used); + } + + bta_dm_search_cb.p_sdp_db->raw_data = NULL; //no need to free this - it is a global assigned. + bta_dm_search_cb.p_sdp_db->raw_used = 0; + bta_dm_search_cb.p_sdp_db->raw_size = 0; + } + else { + APPL_TRACE_DEBUG0("bta_dm_sdp_result raw data size is 0 or raw_data is null!!\r\n"); + } + /* Done with p_sdp_db. Free it */ + bta_dm_free_sdp_db(NULL); + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + + //Piggy back the SCN over result field + if( scn_found ) + { + p_msg->disc_result.result.disc_res.result = (3 + bta_dm_search_cb.peer_scn); + p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK; + + APPL_TRACE_EVENT1(" Piggy back the SCN over result field SCN=%d", bta_dm_search_cb.peer_scn); + + } + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + bta_dm_get_remname(), (BD_NAME_LEN-1)); + + /* make sure the string is null terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + bta_sys_sendmsg(p_msg); + } + + } + + } + else + { + /* conn failed. No need for timer */ + if(p_data->sdp_event.sdp_result == SDP_CONN_FAILED || p_data->sdp_event.sdp_result == SDP_CONN_REJECTED + || p_data->sdp_event.sdp_result == SDP_SECURITY_ERR) + bta_dm_search_cb.wait_disc = FALSE; + + /* not able to connect go to next device */ + GKI_freebuf(bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.p_sdp_db = NULL; + + BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = BTA_FAILURE; + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + bta_dm_get_remname(), (BD_NAME_LEN-1)); + + /* make sure the string is null terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_search_cmpl +** +** Description Sends event to application +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cmpl (tBTA_DM_MSG *p_data) +{ + APPL_TRACE_DEBUG0("bta_dm_search_cmpl"); + +#if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) + utl_freebuf((void **)&bta_dm_search_cb.p_srvc_uuid); +#endif + + if (p_data->hdr.layer_specific == BTA_DM_API_DI_DISCOVER_EVT) + bta_dm_di_disc_cmpl(p_data); + else + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, NULL); +} + +/******************************************************************************* +** +** Function bta_dm_disc_result +** +** Description Service discovery result when discovering services on a device +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disc_result (tBTA_DM_MSG *p_data) +{ + tBTA_DM_MSG * p_msg; + + APPL_TRACE_DEBUG0("bta_dm_disc_result"); + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + /* if any BR/EDR service discovery has been done, report the event */ + if ((bta_dm_search_cb.services & ((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK ) & ~BTA_BLE_SERVICE_MASK))) +#endif + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result); + + /* send a message to change state */ + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_search_result +** +** Description Service discovery result while searching for devices +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_result (tBTA_DM_MSG *p_data) +{ + APPL_TRACE_DEBUG2("bta_dm_search_result searching:0x%04x, result:0x%04x", + bta_dm_search_cb.services, + p_data->disc_result.result.disc_res.services); + + /* call back if application wants name discovery or found services that application is searching */ + if (( !bta_dm_search_cb.services ) + ||(( bta_dm_search_cb.services ) && ( p_data->disc_result.result.disc_res.services ))) + { + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result); + } + + /* if searching did not initiate to create link */ + if(!bta_dm_search_cb.wait_disc ) + { +#if ( BTM_EIR_CLIENT_INCLUDED == TRUE ) + /* if service searching is done with EIR, don't search next device */ + if( bta_dm_search_cb.p_btm_inq_info ) +#endif + bta_dm_discover_next_device(); + } + else + { + /* wait until link is disconnected or timeout */ + bta_dm_search_cb.sdp_results = TRUE; + bta_dm_search_cb.search_timer.p_cback = (TIMER_CBACK*)&bta_dm_search_timer_cback; + bta_sys_start_timer(&bta_dm_search_cb.search_timer, 0, 1000*(L2CAP_LINK_INACTIVITY_TOUT+1) ); + } + +} + +/******************************************************************************* +** +** Function bta_dm_search_timer_cback +** +** Description Called when ACL disconnect time is over +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_search_timer_cback (TIMER_LIST_ENT *p_tle) +{ + + APPL_TRACE_EVENT0(" bta_dm_search_timer_cback "); + bta_dm_search_cb.wait_disc = FALSE; + + /* proceed with next device */ + bta_dm_discover_next_device(); + +} + + +/******************************************************************************* +** +** Function bta_dm_free_sdp_db +** +** Description Frees SDP data base +** +** Returns void +** +*******************************************************************************/ +void bta_dm_free_sdp_db (tBTA_DM_MSG *p_data) +{ + if(bta_dm_search_cb.p_sdp_db) + { + GKI_freebuf(bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.p_sdp_db = NULL; + } + +} + +/******************************************************************************* +** +** Function bta_dm_queue_search +** +** Description Queues search command while search is being cancelled +** +** Returns void +** +*******************************************************************************/ +void bta_dm_queue_search (tBTA_DM_MSG *p_data) +{ + + bta_dm_search_cb.p_search_queue = (tBTA_DM_MSG *)GKI_getbuf(sizeof(tBTA_DM_API_SEARCH)); + memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_SEARCH)); + +} + +/******************************************************************************* +** +** Function bta_dm_queue_disc +** +** Description Queues discovery command while search is being cancelled +** +** Returns void +** +*******************************************************************************/ +void bta_dm_queue_disc (tBTA_DM_MSG *p_data) +{ + + bta_dm_search_cb.p_search_queue = (tBTA_DM_MSG *)GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER)); + memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_DISCOVER)); + +} + +/******************************************************************************* +** +** Function bta_dm_search_clear_queue +** +** Description Clears the queue if API search cancel is called +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_clear_queue (tBTA_DM_MSG *p_data) +{ + + if(bta_dm_search_cb.p_search_queue) + { + GKI_freebuf(bta_dm_search_cb.p_search_queue); + bta_dm_search_cb.p_search_queue = NULL; + } + + +} + +/******************************************************************************* +** +** Function bta_dm_search_cancel_cmpl +** +** Description Search cancel is complete +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cancel_cmpl (tBTA_DM_MSG *p_data) +{ + + if(bta_dm_search_cb.p_search_queue) + { + bta_sys_sendmsg(bta_dm_search_cb.p_search_queue); + bta_dm_search_cb.p_search_queue = NULL; + } + +} + +/******************************************************************************* +** +** Function bta_dm_search_cancel_transac_cmpl +** +** Description Current Service Discovery or remote name procedure is +** completed after search cancellation +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG *p_data) +{ + + if(bta_dm_search_cb.p_sdp_db) + { + GKI_freebuf(bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.p_sdp_db = NULL; + } + + bta_dm_search_cancel_notify(NULL); +} + + +/******************************************************************************* +** +** Function bta_dm_search_cancel_notify +** +** Description Notify application that search has been cancelled +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data) +{ + if (bta_dm_search_cb.p_search_cback) + { + bta_dm_search_cb.p_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL); + } + if (!bta_dm_search_cb.name_discover_done) + { + BTM_CancelRemoteDeviceName(); + } +#if ((BLE_INCLUDED == TRUE) && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + if (bta_dm_search_cb.gatt_disc_active) + { + bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr); + } +#endif + +} + +/******************************************************************************* +** +** Function bta_dm_find_services +** +** Description Starts discovery on a device +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_find_services ( BD_ADDR bd_addr) +{ + + tSDP_UUID uuid; + UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_EXT_BRCM_VERSION}; + UINT16 num_attrs = 1; + tBTA_DM_MSG *p_msg; + + memset (&uuid, 0, sizeof(tSDP_UUID)); + + while(bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) + { + if( bta_dm_search_cb.services_to_search + & (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))) + { + if((bta_dm_search_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_DM_SDP_DB_SIZE)) != NULL) + { + APPL_TRACE_DEBUG1("bta_dm_search_cb.services = %04x***********", bta_dm_search_cb.services); + /* try to search all services by search based on L2CAP UUID */ + if(bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK ) + { + APPL_TRACE_ERROR1("services_to_search = %08x",bta_dm_search_cb.services_to_search); + if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) + { + uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[0]; + bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK; + } + else + { + uuid.uu.uuid16 = UUID_PROTOCOL_L2CAP; + bta_dm_search_cb.services_to_search = 0; + } + } + else + { +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + /* for LE only profile */ + if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) + { + if (bta_dm_search_cb.uuid_to_search > 0 && bta_dm_search_cb.p_srvc_uuid) + { + memcpy(&uuid, + (const void *)(bta_dm_search_cb.p_srvc_uuid + \ + bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search), + sizeof(tBT_UUID)); + + bta_dm_search_cb.uuid_to_search -- ; + } + else + uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]; + + /* last one? clear the BLE service bit if all discovery has been done */ + if (bta_dm_search_cb.uuid_to_search == 0) + bta_dm_search_cb.services_to_search &= + (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))); + + } + else +#endif + { + /* remove the service from services to be searched */ + bta_dm_search_cb.services_to_search &= + (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))); + uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]; + } + } + + if (uuid.len == 0) + uuid.len = LEN_UUID_16; + +#if 0 + if (uuid.uu.uuid16 == UUID_SERVCLASS_PNP_INFORMATION) + { + num_attrs = 2; + } +#endif + + if (bta_dm_search_cb.service_index == BTA_USER_SERVICE_ID) + { + memcpy(&uuid, &bta_dm_search_cb.uuid, sizeof(tSDP_UUID)); + } + + + APPL_TRACE_ERROR1("****************search UUID = %04x***********", uuid.uu.uuid16); + //SDP_InitDiscoveryDb (bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, num_attrs, attr_list); + SDP_InitDiscoveryDb (bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1, &uuid, 0, NULL); + + + memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); + bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf; + + bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF; + + if (!SDP_ServiceSearchAttributeRequest (bd_addr, bta_dm_search_cb.p_sdp_db, &bta_dm_sdp_callback)) + { + /* if discovery not successful with this device + proceed to next one */ + GKI_freebuf(bta_dm_search_cb.p_sdp_db); + bta_dm_search_cb.p_sdp_db = NULL; + bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID; + + } + else + { +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + if ((bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID && + bta_dm_search_cb.uuid_to_search == 0) || + bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID) +#endif + bta_dm_search_cb.service_index++; + return; + } + } + else + { + APPL_TRACE_ERROR0("#### Failed to allocate SDP DB buffer! ####"); + } + } + + bta_dm_search_cb.service_index++; + } + + /* no more services to be discovered */ + if(bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) + { + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + bta_dm_get_remname(), (BD_NAME_LEN-1)); + + /* make sure the string is terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_discover_next_device +** +** Description Starts discovery on the next device in Inquiry data base +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_discover_next_device(void) +{ + + tBTA_DM_MSG * p_msg; + + APPL_TRACE_DEBUG0("bta_dm_discover_next_device"); + + /* searching next device on inquiry result */ + if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbNext(bta_dm_search_cb.p_btm_inq_info)) != NULL) + { + bta_dm_search_cb.name_discover_done = FALSE; + bta_dm_search_cb.peer_name[0] = 0; + bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); + } + else + { + /* no devices, search complete */ + bta_dm_search_cb.services = 0; + + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; + p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_dm_discover_device +** +** Description Starts name and service discovery on the device +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_discover_device(BD_ADDR remote_bd_addr) +{ + tBTA_DM_MSG * p_msg; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; +#endif + + APPL_TRACE_DEBUG6("bta_dm_discover_device, BDA:0x%02X%02X%02X%02X%02X%02X", + remote_bd_addr[0],remote_bd_addr[1], + remote_bd_addr[2],remote_bd_addr[3], + remote_bd_addr[4],remote_bd_addr[5]); + + bdcpy(bta_dm_search_cb.peer_bdaddr, remote_bd_addr); + + APPL_TRACE_DEBUG2("bta_dm_discover_device name_discover_done = %d p_btm_inq_info 0x%x ", + bta_dm_search_cb.name_discover_done, + bta_dm_search_cb.p_btm_inq_info + ); + if ( bta_dm_search_cb.p_btm_inq_info ) { + + APPL_TRACE_DEBUG1("bta_dm_discover_device appl_knows_rem_name %d", + bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name + ); + } + + /* if name discovery is not done and application needs remote name */ + if ((!bta_dm_search_cb.name_discover_done) + && (( bta_dm_search_cb.p_btm_inq_info == NULL ) + ||(bta_dm_search_cb.p_btm_inq_info && (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) + { + if( bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr) == TRUE ) + { + return; + } + else + { + /* starting name discovery failed */ + bta_dm_search_cb.name_discover_done = TRUE; + } + } + + /* if application wants to discover service */ + if ( bta_dm_search_cb.services ) + { + /* initialize variables */ + bta_dm_search_cb.service_index = 0; + bta_dm_search_cb.services_found = 0; + bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid; +#endif +#if ( BTM_EIR_CLIENT_INCLUDED == TRUE ) + if ((bta_dm_search_cb.p_btm_inq_info != NULL) && + bta_dm_search_cb.services != BTA_USER_SERVICE_MASK + &&(bta_dm_search_cb.sdp_search == FALSE)) + { + /* check if EIR provides the information of supported services */ + bta_dm_eir_search_services( &bta_dm_search_cb.p_btm_inq_info->results, + &bta_dm_search_cb.services_to_search, + &bta_dm_search_cb.services_found ); + } + + /* if seaching with EIR is not completed */ + if(bta_dm_search_cb.services_to_search) +#endif + { + /* check whether connection already exists to the device + if connection exists, we don't have to wait for ACL + link to go down to start search on next device */ + if(BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr)) + bta_dm_search_cb.wait_disc = FALSE; + else + bta_dm_search_cb.wait_disc = TRUE; + +#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + if ( bta_dm_search_cb.p_btm_inq_info ) + { + APPL_TRACE_DEBUG3("bta_dm_discover_device p_btm_inq_info 0x%x results.device_type 0x%x services_to_search 0x%x", + bta_dm_search_cb.p_btm_inq_info, + bta_dm_search_cb.p_btm_inq_info->results.device_type, + bta_dm_search_cb.services_to_search + ); + } + BTM_ReadDevInfo(remote_bd_addr, &dev_type, &addr_type); + + if (dev_type == BT_DEVICE_TYPE_BLE) + /* + if ( bta_dm_search_cb.p_btm_inq_info != NULL && + bta_dm_search_cb.p_btm_inq_info->results.device_type == BT_DEVICE_TYPE_BLE && + (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK))*/ + { + if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) + { + //set the raw data buffer here + memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); + bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf; + + bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF; + bta_dm_search_cb.ble_raw_used = 0; + + /* start GATT for service discovery */ + btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr); + return; + } + } + else +#endif + { + bta_dm_search_cb.sdp_results = FALSE; + bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); + + return; + } + } + } + + /* name discovery and service discovery are done for this device */ + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + /* initialize the data structure - includes p_raw_data and raw_data_size */ + memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES)); + p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + (char*)bta_dm_search_cb.peer_name, (BD_NAME_LEN-1)); + + /* make sure the string is terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_sdp_callback +** +** Description Callback from sdp with discovery status +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_sdp_callback (UINT16 sdp_status) +{ + + tBTA_DM_SDP_RESULT * p_msg; + + if ((p_msg = (tBTA_DM_SDP_RESULT *) GKI_getbuf(sizeof(tBTA_DM_SDP_RESULT))) != NULL) + { + p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT; + p_msg->sdp_result = sdp_status; + bta_sys_sendmsg(p_msg); + + } +} + +/******************************************************************************* +** +** Function bta_dm_inq_results_cb +** +** Description Inquiry results callback from BTM +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_inq_results_cb (tBTM_INQ_RESULTS *p_inq, UINT8 *p_eir) +{ + + tBTA_DM_SEARCH result; + tBTM_INQ_INFO *p_inq_info; + UINT16 service_class; + + bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr); + memcpy(result.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN); + BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class); + result.inq_res.is_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER)?TRUE:FALSE; + result.inq_res.rssi = p_inq->rssi; + +#if (BLE_INCLUDED == TRUE) + result.inq_res.ble_addr_type = p_inq->ble_addr_type; + result.inq_res.inq_result_type = p_inq->inq_result_type; + result.inq_res.device_type = p_inq->device_type; + +#endif + + /* application will parse EIR to find out remote device name */ + result.inq_res.p_eir = p_eir; + + if((p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr)) != NULL) + { + /* initialize remt_name_not_required to FALSE so that we get the name by default */ + result.inq_res.remt_name_not_required = FALSE; + + } + + if(bta_dm_search_cb.p_search_cback) + bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result); + + if(p_inq_info) + { + /* application indicates if it knows the remote name, inside the callback + copy that to the inquiry data base*/ + if(result.inq_res.remt_name_not_required) + p_inq_info->appl_knows_rem_name = TRUE; + + } + + +} + + +/******************************************************************************* +** +** Function bta_dm_inq_cmpl_cb +** +** Description Inquiry complete callback from BTM +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_inq_cmpl_cb (void * p_result) +{ + + tBTA_DM_MSG * p_msg; + + APPL_TRACE_DEBUG0("bta_dm_inq_cmpl_cb"); + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT; + p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp; + bta_sys_sendmsg(p_msg); + + } + + +} + +/******************************************************************************* +** +** Function bta_dm_service_search_remname_cback +** +** Description Remote name call back from BTM during service discovery +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_service_search_remname_cback (BD_ADDR bd_addr, DEV_CLASS dc, BD_NAME bd_name) +{ + tBTM_REMOTE_DEV_NAME rem_name; + tBTM_STATUS btm_status; + + APPL_TRACE_DEBUG1("bta_dm_service_search_remname_cback name=<%s>", bd_name); + + /* if this is what we are looking for */ + if (!bdcmp( bta_dm_search_cb.peer_bdaddr, bd_addr)) + { + rem_name.length = strlen((char*)bd_name); + if (rem_name.length > (BD_NAME_LEN-1)) + { + rem_name.length = (BD_NAME_LEN-1); + rem_name.remote_bd_name[(BD_NAME_LEN-1)] = 0; + } + BCM_STRNCPY_S((char*)rem_name.remote_bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1)); + rem_name.status = BTM_SUCCESS; + + bta_dm_remname_cback(&rem_name); + } + else + { + /* get name of device */ + btm_status = BTM_ReadRemoteDeviceName (bta_dm_search_cb.peer_bdaddr, + (tBTM_CMPL_CB *) bta_dm_remname_cback); + if ( btm_status == BTM_BUSY ) + { + /* wait for next chance(notification of remote name discovery done) */ + APPL_TRACE_DEBUG0("bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName is busy"); + } + else if ( btm_status != BTM_CMD_STARTED ) + { + /* if failed to start getting remote name then continue */ + APPL_TRACE_WARNING1("bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName returns 0x%02X", btm_status); + + rem_name.length = 0; + rem_name.remote_bd_name[0] = 0; + rem_name.status = btm_status; + bta_dm_remname_cback(&rem_name); + } + } +} + + +/******************************************************************************* +** +** Function bta_dm_remname_cback +** +** Description Remote name complete call back from BTM +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_remname_cback (tBTM_REMOTE_DEV_NAME *p_remote_name) +{ + tBTA_DM_REM_NAME * p_msg; + + APPL_TRACE_DEBUG1("bta_dm_remname_cback name=<%s>", p_remote_name->remote_bd_name); + + /* remote name discovery is done but it could be failed */ + bta_dm_search_cb.name_discover_done = TRUE; + BCM_STRNCPY_S((char*)bta_dm_search_cb.peer_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN-1)); + bta_dm_search_cb.peer_name[BD_NAME_LEN-1]=0; + + BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback); + + if ((p_msg = (tBTA_DM_REM_NAME *) GKI_getbuf(sizeof(tBTA_DM_REM_NAME))) != NULL) + { + bdcpy (p_msg->result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->result.disc_res.bd_name, sizeof(BD_NAME), (char*)p_remote_name->remote_bd_name, (BD_NAME_LEN-1)); + + /* make sure the string is null terminated */ + p_msg->result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + p_msg->hdr.event = BTA_DM_REMT_NAME_EVT; + bta_sys_sendmsg(p_msg); + + } +} + +/******************************************************************************* +** +** Function bta_dm_authorize_cback +** +** Description cback requesting authorization +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_authorize_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, + UINT8 *service_name, UINT8 service_id, BOOLEAN is_originator) +{ + tBTA_DM_SEC sec_event; + UINT8 index = 1; + + bdcpy(sec_event.authorize.bd_addr, bd_addr); + memcpy(sec_event.authorize.dev_class, dev_class, DEV_CLASS_LEN); + + BCM_STRNCPY_S((char*)sec_event.authorize.bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1)); + + /* make sure the string is null terminated */ + sec_event.authorize.bd_name[BD_NAME_LEN-1] = 0; + +#if ( defined(BTA_JV_INCLUDED) && BTA_JV_INCLUDED == TRUE ) + sec_event.authorize.service = service_id; +#endif + + while(index < BTA_MAX_SERVICE_ID) + { + /* get the BTA service id corresponding to BTM id */ + if(bta_service_id_to_btm_srv_id_lkup_tbl[index] == service_id) + { + sec_event.authorize.service = index; + break; + } + index++; + } + + + /* if supported service callback otherwise not authorized */ + if(bta_dm_cb.p_sec_cback && (index < BTA_MAX_SERVICE_ID +#if ( defined(BTA_JV_INCLUDED) && BTA_JV_INCLUDED == TRUE ) + /* pass through JV service ID */ + || (service_id >= BTA_FIRST_JV_SERVICE_ID && service_id <= BTA_LAST_JV_SERVICE_ID) +#endif + )) + { + bta_dm_cb.p_sec_cback(BTA_DM_AUTHORIZE_EVT, &sec_event); + return BTM_CMD_STARTED; + } + else + { + return BTM_NOT_AUTHORIZED; + } +} + + + + + +/******************************************************************************* +** +** Function bta_dm_pinname_cback +** +** Description Callback requesting pin_key +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pinname_cback (void *p_data) +{ + tBTM_REMOTE_DEV_NAME *p_result = (tBTM_REMOTE_DEV_NAME *)p_data; + tBTA_DM_SEC sec_event; + UINT32 bytes_to_copy; + tBTA_DM_SEC_EVT event = bta_dm_cb.pin_evt; + + if (BTA_DM_SP_CFM_REQ_EVT == event) + { + /* Retrieved saved device class and bd_addr */ + bdcpy(sec_event.cfm_req.bd_addr, bta_dm_cb.pin_bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.cfm_req.dev_class, bta_dm_cb.pin_dev_class); + + if (p_result && p_result->status == BTM_SUCCESS) + { + bytes_to_copy = (p_result->length < (BD_NAME_LEN-1)) + ? p_result->length : (BD_NAME_LEN-1); + memcpy(sec_event.cfm_req.bd_name, p_result->remote_bd_name, bytes_to_copy); + sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0; + } + else /* No name found */ + sec_event.cfm_req.bd_name[0] = 0; + + sec_event.key_notif.passkey = bta_dm_cb.num_val; /* get PIN code numeric number */ + + /* 1 additional event data fields for this event */ + sec_event.cfm_req.just_works = bta_dm_cb.just_works; + } + else + { + /* Retrieved saved device class and bd_addr */ + bdcpy(sec_event.pin_req.bd_addr, bta_dm_cb.pin_bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, bta_dm_cb.pin_dev_class); + + if (p_result && p_result->status == BTM_SUCCESS) + { + bytes_to_copy = (p_result->length < (BD_NAME_LEN-1)) + ? p_result->length : (BD_NAME_LEN-1); + memcpy(sec_event.pin_req.bd_name, p_result->remote_bd_name, bytes_to_copy); + sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0; + } + else /* No name found */ + sec_event.pin_req.bd_name[0] = 0; + + event = bta_dm_cb.pin_evt; + sec_event.key_notif.passkey = bta_dm_cb.num_val; /* get PIN code numeric number */ + } + + if( bta_dm_cb.p_sec_cback ) + bta_dm_cb.p_sec_cback(event, &sec_event); +} + + + +/******************************************************************************* +** +** Function bta_dm_pin_cback +** +** Description Callback requesting pin_key +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_pin_cback (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name) +{ + tBTA_DM_SEC sec_event; + + if (!bta_dm_cb.p_sec_cback) + return BTM_NOT_AUTHORIZED; + + /* If the device name is not known, save bdaddr and devclass and initiate a name request */ + if (bd_name[0] == 0) + { + bta_dm_cb.pin_evt = BTA_DM_PIN_REQ_EVT; + bdcpy(bta_dm_cb.pin_bd_addr, bd_addr); + BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, dev_class); + if ((BTM_ReadRemoteDeviceName(bd_addr, bta_dm_pinname_cback)) == BTM_CMD_STARTED) + return BTM_CMD_STARTED; + + APPL_TRACE_WARNING0(" bta_dm_pin_cback() -> Failed to start Remote Name Request "); + } + + bdcpy(sec_event.pin_req.bd_addr, bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, dev_class); + BCM_STRNCPY_S((char*)sec_event.pin_req.bd_name, sizeof(BD_NAME), (char*)bd_name, (BD_NAME_LEN-1)); + sec_event.pin_req.bd_name[BD_NAME_LEN-1] = 0; + + bta_dm_cb.p_sec_cback(BTA_DM_PIN_REQ_EVT, &sec_event); + return BTM_CMD_STARTED; +} + + + +/******************************************************************************* +** +** Function bta_dm_link_key_request_cback +** +** Description Callback requesting linkkey +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_link_key_request_cback (BD_ADDR bd_addr, LINK_KEY key) +{ + /* Application passes all link key to + BTM during initialization using add_device + API. If BTM doesn't have the link key in it's + data base, that's because application doesn't + it */ + + return BTM_NOT_AUTHORIZED; +} + + + + + +/******************************************************************************* +** +** Function bta_dm_new_link_key_cback +** +** Description Callback from BTM to notify new link key +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class, + BD_NAME bd_name, LINK_KEY key, UINT8 key_type) +{ + tBTA_DM_SEC sec_event; + tBTA_DM_AUTH_CMPL *p_auth_cmpl; + UINT8 event; + + memset (&sec_event, 0, sizeof(tBTA_DM_SEC)); + + /* Not AMP Key type */ + if (key_type != HCI_LKEY_TYPE_AMP_WIFI && key_type != HCI_LKEY_TYPE_AMP_UWB) + { + event = BTA_DM_AUTH_CMPL_EVT; + p_auth_cmpl = &sec_event.auth_cmpl; + + bdcpy(p_auth_cmpl->bd_addr, bd_addr); + + memcpy(p_auth_cmpl->bd_name, bd_name, (BD_NAME_LEN-1)); + p_auth_cmpl->bd_name[BD_NAME_LEN-1] = 0; + + p_auth_cmpl->key_present = TRUE; + p_auth_cmpl->key_type = key_type; + p_auth_cmpl->success = TRUE; + + memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN); + sec_event.auth_cmpl.fail_reason = HCI_SUCCESS; + + if(bta_dm_cb.p_sec_cback) + { + bta_dm_cb.p_sec_cback(event, &sec_event); + } + } + else + { + APPL_TRACE_WARNING0(" bta_dm_new_link_key_cback() Received AMP Key?? "); + } + + return BTM_CMD_STARTED; +} + + +/******************************************************************************* +** +** Function bta_dm_authentication_complete_cback +** +** Description Authentication complete callback from BTM +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,BD_NAME bd_name, int result) +{ + + tBTA_DM_SEC sec_event; + + if(result != BTM_SUCCESS) + { + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + bdcpy(sec_event.auth_cmpl.bd_addr, bd_addr); + + memcpy(sec_event.auth_cmpl.bd_name, bd_name, (BD_NAME_LEN-1)); + sec_event.auth_cmpl.bd_name[BD_NAME_LEN-1] = 0; + +/* taken care of by memset [above] + sec_event.auth_cmpl.key_present = FALSE; + sec_event.auth_cmpl.success = FALSE; +*/ + sec_event.auth_cmpl.fail_reason = (UINT8)result; + if(bta_dm_cb.p_sec_cback) + { + bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + } + } + + return BTM_SUCCESS; +} + +/******************************************************************************* +** +** Function bta_dm_sp_cback +** +** Description simple pairing callback from BTM +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data) +{ + tBTM_STATUS status = BTM_CMD_STARTED; + tBTA_DM_SEC sec_event; + tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT; + + APPL_TRACE_EVENT1("bta_dm_sp_cback: %d", event); + if (!bta_dm_cb.p_sec_cback) + return BTM_NOT_AUTHORIZED; + + /* TODO_SP */ + switch(event) + { + case BTM_SP_IO_REQ_EVT: +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + /* translate auth_req */ + bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap, + &p_data->io_req.oob_data, &p_data->io_req.auth_req, p_data->io_req.is_orig); +#endif +#if BTM_OOB_INCLUDED == FALSE + status = BTM_SUCCESS; +#endif + + APPL_TRACE_EVENT2("io mitm: %d oob_data:%d", p_data->io_req.auth_req, p_data->io_req.oob_data); + break; + case BTM_SP_IO_RSP_EVT: +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap, + p_data->io_rsp.oob_data, p_data->io_rsp.auth_req ); +#endif + break; + + case BTM_SP_CFM_REQ_EVT: + pin_evt = BTA_DM_SP_CFM_REQ_EVT; + bta_dm_cb.just_works = sec_event.cfm_req.just_works = p_data->cfm_req.just_works; + sec_event.cfm_req.loc_auth_req = p_data->cfm_req.loc_auth_req; + sec_event.cfm_req.rmt_auth_req = p_data->cfm_req.rmt_auth_req; + sec_event.cfm_req.loc_io_caps = p_data->cfm_req.loc_io_caps; + sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps; + /* continue to next case */ +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + /* Passkey entry mode, mobile device with output capability is very + unlikely to receive key request, so skip this event */ + /*case BTM_SP_KEY_REQ_EVT: */ + case BTM_SP_KEY_NOTIF_EVT: +#endif + bta_dm_cb.num_val = sec_event.key_notif.passkey = p_data->key_notif.passkey; + /* If the device name is not known, save bdaddr and devclass and initiate a name request */ + if (p_data->key_notif.bd_name[0] == 0) + { + bta_dm_cb.pin_evt = pin_evt; + bdcpy(bta_dm_cb.pin_bd_addr, p_data->key_notif.bd_addr); + BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->key_notif.dev_class); + if ((BTM_ReadRemoteDeviceName(p_data->key_notif.bd_addr, bta_dm_pinname_cback)) == BTM_CMD_STARTED) + return BTM_CMD_STARTED; + + APPL_TRACE_WARNING0(" bta_dm_sp_cback() -> Failed to start Remote Name Request "); + } + bdcpy(sec_event.key_notif.bd_addr, p_data->key_notif.bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class, p_data->key_notif.dev_class); + BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), (char*)p_data->key_notif.bd_name, (BD_NAME_LEN-1)); + sec_event.key_notif.bd_name[BD_NAME_LEN-1] = 0; + + bta_dm_cb.p_sec_cback(pin_evt, &sec_event); + + break; + +#if BTM_OOB_INCLUDED == TRUE + case BTM_SP_LOC_OOB_EVT: + bta_dm_co_loc_oob((BOOLEAN)(p_data->loc_oob.status == BTM_SUCCESS), + p_data->loc_oob.c, p_data->loc_oob.r); + break; + + case BTM_SP_RMT_OOB_EVT: + /* If the device name is not known, save bdaddr and devclass and initiate a name request */ + if (p_data->rmt_oob.bd_name[0] == 0) + { + bta_dm_cb.pin_evt = BTA_DM_SP_RMT_OOB_EVT; + bdcpy(bta_dm_cb.pin_bd_addr, p_data->rmt_oob.bd_addr); + BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, p_data->rmt_oob.dev_class); + if ((BTM_ReadRemoteDeviceName(p_data->rmt_oob.bd_addr, bta_dm_pinname_cback)) == BTM_CMD_STARTED) + return BTM_CMD_STARTED; + + APPL_TRACE_WARNING0(" bta_dm_sp_cback() -> Failed to start Remote Name Request "); + } + bdcpy(sec_event.rmt_oob.bd_addr, p_data->rmt_oob.bd_addr); + BTA_COPY_DEVICE_CLASS(sec_event.rmt_oob.dev_class, p_data->rmt_oob.dev_class); + BCM_STRNCPY_S((char*)sec_event.rmt_oob.bd_name, sizeof(BD_NAME), (char*)p_data->rmt_oob.bd_name, (BD_NAME_LEN-1)); + sec_event.rmt_oob.bd_name[BD_NAME_LEN-1] = 0; + + bta_dm_cb.p_sec_cback(BTA_DM_SP_RMT_OOB_EVT, &sec_event); + + bta_dm_co_rmt_oob(p_data->rmt_oob.bd_addr); + break; +#endif + case BTM_SP_COMPLT_EVT: + /* do not report this event - handled by link_key_callback or auth_complete_callback */ + break; + + case BTM_SP_KEYPRESS_EVT: + memcpy(&sec_event.key_press, &p_data->key_press, sizeof(tBTM_SP_KEYPRESS)); + bta_dm_cb.p_sec_cback(BTA_DM_SP_KEYPRESS_EVT, &sec_event); + break; + + case BTM_SP_UPGRADE_EVT: + bta_dm_co_lk_upgrade(p_data->upgrade.bd_addr, &p_data->upgrade.upgrade ); + break; + + default: + status = BTM_NOT_AUTHORIZED; + break; + } + APPL_TRACE_EVENT1("dm status: %d", status); + return status; +} + +/******************************************************************************* +** +** Function bta_dm_local_name_cback +** +** Description Callback from btm after local name is read +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_local_name_cback(UINT8 *p_name) +{ + tBTA_DM_SEC sec_event; + + BTM_GetLocalDeviceAddr(sec_event.enable.bd_addr); + sec_event.enable.status = BTA_SUCCESS; + + if(bta_dm_cb.p_sec_cback) + bta_dm_cb.p_sec_cback(BTA_DM_ENABLE_EVT, &sec_event); +} + +/******************************************************************************* +** +** Function bta_dm_signal_strength +** +** Description Callback from btm after local bdaddr is read +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_signal_strength(tBTA_DM_MSG *p_data) +{ + + if(p_data->sig_strength.start) + { + bta_dm_cb.signal_strength_mask = p_data->sig_strength.mask; + bta_dm_cb.signal_strength_period = p_data->sig_strength.period; + bta_dm_signal_strength_timer_cback(NULL); + } + else + { + bta_sys_stop_timer(&bta_dm_cb.signal_strength_timer); + } + +} +/******************************************************************************* +** +** Function bta_dm_signal_strength_timer_cback +** +** Description Periodic timer callback to read signal strength +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_signal_strength_timer_cback (TIMER_LIST_ENT *p_tle) +{ + + UINT8 i; + + if(bta_dm_cb.signal_strength_mask & BTA_SIG_STRENGTH_RSSI_MASK) + { + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + BTM_ReadRSSI (bta_dm_cb.device_list.peer_device[i].peer_bdaddr, (tBTM_CMPL_CB *)bta_dm_rssi_cback); + + } + } + if(bta_dm_cb.signal_strength_mask & BTA_SIG_STRENGTH_LINK_QUALITY_MASK) + { + + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + BTM_ReadLinkQuality (bta_dm_cb.device_list.peer_device[i].peer_bdaddr, (tBTM_CMPL_CB *)bta_dm_link_quality_cback); + } + + } + + if(bta_dm_cb.signal_strength_period) + { + bta_dm_cb.signal_strength_timer.p_cback = (TIMER_CBACK*)&bta_dm_signal_strength_timer_cback; + bta_sys_start_timer(&bta_dm_cb.signal_strength_timer, 0, (UINT32)1000*bta_dm_cb.signal_strength_period); + } +} + + +#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_bl_change_cback +** +** Description Callback from btm when acl connection goes up or down +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data) +{ + + tBTA_DM_ACL_CHANGE * p_msg; + + if ((p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE))) != NULL) + { + p_msg->event = p_data->event; + p_msg->is_new = FALSE; + + switch(p_msg->event) + { + case BTM_BL_CONN_EVT: + p_msg->is_new = TRUE; + bdcpy(p_msg->bd_addr, p_data->conn.p_bda); + break; + case BTM_BL_DISCN_EVT: + bdcpy(p_msg->bd_addr, p_data->discn.p_bda); + break; + case BTM_BL_UPDATE_EVT: + p_msg->busy_level = p_data->update.busy_level; + break; + case BTM_BL_ROLE_CHG_EVT: + p_msg->new_role = p_data->role_chg.new_role; + p_msg->hci_status = p_data->role_chg.hci_status; + bdcpy(p_msg->bd_addr, p_data->role_chg.p_bda); + break; + case BTM_BL_COLLISION_EVT: + bdcpy(p_msg->bd_addr, p_data->conn.p_bda); + break;; + } + + p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT; + bta_sys_sendmsg(p_msg); + + } + +} +#else + +/******************************************************************************* +** +** Function bta_dm_acl_change_cback +** +** Description Callback from btm when acl connection goes up or down +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_acl_change_cback (BD_ADDR p_bda, DEV_CLASS p_dc, BD_NAME p_bdn, + BD_FEATURES features, BOOLEAN is_new) +{ + + tBTA_DM_ACL_CHANGE * p_msg; + + if ((p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE))) != NULL) + { + bdcpy (p_msg->bd_addr, p_bda); + p_msg->is_new = is_new; + + /* This is collision case */ + if (features != NULL) + { + if ((features[0] == 0xFF) && !is_new) + p_msg->event = BTM_BL_COLLISION_EVT; + } + + p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT; + bta_sys_sendmsg(p_msg); + + } + +} +#endif +/******************************************************************************* +** +** Function bta_dm_rs_cback +** +** Description Receives the role switch complete event +** +** Returns +** +*******************************************************************************/ +static void bta_dm_rs_cback (tBTM_ROLE_SWITCH_CMPL *p1) +{ + APPL_TRACE_WARNING1("bta_dm_rs_cback:%d", bta_dm_cb.rs_event); + if(bta_dm_cb.rs_event == BTA_DM_API_SEARCH_EVT) + { + bta_dm_cb.search_msg.rs_res = BTA_DM_RS_OK; /* do not care about the result for now */ + bta_dm_cb.rs_event = 0; + bta_dm_search_start((tBTA_DM_MSG *)&bta_dm_cb.search_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_check_av +** +** Description This function checks if AV is active +** if yes, make sure the AV link is master +** +** Returns BOOLEAN - TRUE, if switch is in progress +** +*******************************************************************************/ +static BOOLEAN bta_dm_check_av(UINT16 event) +{ + BOOLEAN switching = FALSE; + UINT8 i; + tBTA_DM_PEER_DEVICE *p_dev; + + APPL_TRACE_WARNING1("bta_dm_check_av:%d", bta_dm_cb.cur_av_count); + if(bta_dm_cb.cur_av_count) + { + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + p_dev = &bta_dm_cb.device_list.peer_device[i]; + APPL_TRACE_WARNING3("[%d]: state:%d, info:x%x", i, p_dev->conn_state, p_dev->info); + if((p_dev->conn_state == BTA_DM_CONNECTED) && (p_dev->info & BTA_DM_DI_AV_ACTIVE)) + { + /* make master and take away the role switch policy */ + if(BTM_CMD_STARTED == BTM_SwitchRole (p_dev->peer_bdaddr, HCI_ROLE_MASTER, (tBTM_CMPL_CB *)bta_dm_rs_cback)) + { + /* the role switch command is actually sent */ + bta_dm_cb.rs_event = event; + switching = TRUE; + } + /* else either already master or can not switch for some reasons */ + bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_dev->peer_bdaddr); + break; + } + } + } + return switching; +} + +/******************************************************************************* +** +** Function bta_dm_acl_change +** +** Description Process BTA_DM_ACL_CHANGE_EVT +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_acl_change(tBTA_DM_MSG *p_data) +{ + + UINT8 i; + UINT8 *p; + tBTA_DM_SEC conn; + BOOLEAN is_new = p_data->acl_change.is_new; + BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr; + BOOLEAN need_policy_change = FALSE; + BOOLEAN issue_unpair_cb = FALSE; + +#if (defined(BTM_BUSY_LEVEL_CHANGE_INCLUDED) && BTM_BUSY_LEVEL_CHANGE_INCLUDED == TRUE) + tBTA_DM_PEER_DEVICE *p_dev; + + switch(p_data->acl_change.event) + { + case BTM_BL_UPDATE_EVT: /* busy level update */ + if( bta_dm_cb.p_sec_cback ) + { + conn.busy_level.level = p_data->acl_change.busy_level; + bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn); + } + return; + + case BTM_BL_ROLE_CHG_EVT: /* role change event */ + p_dev = bta_dm_find_peer_device(p_bda); + if(p_dev) + { + APPL_TRACE_DEBUG3("bta_dm_acl_change role chg info:x%x new_role:%d dev count:%d", + p_dev->info, p_data->acl_change.new_role, bta_dm_cb.device_list.count); + if(p_dev->info & BTA_DM_DI_AV_ACTIVE) + { + /* there's AV activity on this link */ + if(p_data->acl_change.new_role == HCI_ROLE_SLAVE && bta_dm_cb.device_list.count > 1 + && p_data->acl_change.hci_status == HCI_SUCCESS) + { + /* more than one connections and the AV connection is role switched to slave + * switch it back to master and remove the switch policy */ + BTM_SwitchRole(p_bda, BTM_ROLE_MASTER, NULL); + need_policy_change = TRUE; + } + else if (bta_dm_cfg.avoid_scatter && (p_data->acl_change.new_role == HCI_ROLE_MASTER)) + { + /* if the link updated to be master include AV activities, remove the switch policy */ + need_policy_change = TRUE; + } + + if(need_policy_change) + { + bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_dev->peer_bdaddr); + } + } + else + { + /* there's AV no activity on this link and role switch happened + * check if AV is active + * if so, make sure the AV link is master */ + bta_dm_check_av(0); + } + bta_sys_notify_role_chg(p_data->acl_change.bd_addr, p_data->acl_change.new_role, p_data->acl_change.hci_status); + bdcpy(conn.role_chg.bd_addr, p_bda); + conn.role_chg.new_role = (UINT8) p_data->acl_change.new_role; + if( bta_dm_cb.p_sec_cback ) + bta_dm_cb.p_sec_cback(BTA_DM_ROLE_CHG_EVT, &conn); + } + return; + } +#endif + + /* Collision report from Stack: Notify profiles */ + if (p_data->acl_change.event == BTM_BL_COLLISION_EVT) + { + bta_sys_notify_collision (p_bda); + return; + } + + if(is_new) + { + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + if(!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda)) + break; + + } + + if(i == bta_dm_cb.device_list.count) + { + bdcpy(bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count].peer_bdaddr, p_bda); + bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count].link_policy = bta_dm_cb.cur_policy; + bta_dm_cb.device_list.count++; + } + + bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_CONNECTED; + bta_dm_cb.device_list.peer_device[i].pref_role = BTA_ANY_ROLE; + bdcpy(conn.link_up.bd_addr, p_bda); + bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_NONE; + if( ((NULL != (p = BTM_ReadLocalFeatures ())) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) && + ((NULL != (p = BTM_ReadRemoteFeatures (p_bda))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) ) + { + /* both local and remote devices support SSR */ + bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_USE_SSR; + } + APPL_TRACE_WARNING1("info:x%x", bta_dm_cb.device_list.peer_device[i].info); + if( bta_dm_cb.p_sec_cback ) + bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, &conn); + + } + else + { + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + if(bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda)) + continue; + + if( bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING ) + { + BTM_SecDeleteDevice(bta_dm_cb.device_list.peer_device[i].peer_bdaddr); + issue_unpair_cb = TRUE; + } + + for(; i<bta_dm_cb.device_list.count ; i++) + { + memcpy(&bta_dm_cb.device_list.peer_device[i], &bta_dm_cb.device_list.peer_device[i+1], sizeof(bta_dm_cb.device_list.peer_device[i])); + } + break; + } + if(bta_dm_cb.device_list.count) + bta_dm_cb.device_list.count--; + + if(bta_dm_search_cb.wait_disc && !bdcmp(bta_dm_search_cb.peer_bdaddr, p_bda)) + { + bta_dm_search_cb.wait_disc = FALSE; + + if(bta_dm_search_cb.sdp_results) + { + APPL_TRACE_EVENT0(" timer stopped "); + bta_sys_stop_timer(&bta_dm_search_cb.search_timer); + bta_dm_discover_next_device(); + } + + } + + if(bta_dm_cb.disabling) + { + if(!BTM_GetNumAclLinks()) + { + bta_sys_stop_timer(&bta_dm_cb.disable_timer); + bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_conn_down_timer_cback; + /* start a timer to make sure that the profiles get the disconnect event */ + bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 1000); + } + } + + bdcpy(conn.link_down.bd_addr, p_bda); + conn.link_down.status = (UINT8) btm_get_acl_disc_reason_code(); + if( bta_dm_cb.p_sec_cback ) + { + bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn); + if( issue_unpair_cb ) + bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn); + } + } + + bta_dm_adjust_roles(TRUE); +} + +/******************************************************************************* +** +** Function bta_dm_disable_conn_down_timer_cback +** +** Description Sends disable event to application +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle) +{ + tBTA_SYS_HW_MSG *sys_enable_event; + + /* register our callback to SYS HW manager */ + bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback ); + + /* send a message to BTA SYS */ + if ((sys_enable_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + sys_enable_event->hdr.event = BTA_SYS_API_DISABLE_EVT; + sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH; + bta_sys_sendmsg(sys_enable_event); + } + + bta_dm_cb.disabling = FALSE; + +} + +/******************************************************************************* +** +** Function bta_dm_rssi_cback +** +** Description Callback from btm with rssi values +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_rssi_cback (tBTM_RSSI_RESULTS *p_result) +{ + tBTA_DM_SEC sec_event; + + if(p_result->status == BTM_SUCCESS) + { + + bdcpy(sec_event.sig_strength.bd_addr, p_result->rem_bda); + sec_event.sig_strength.mask = BTA_SIG_STRENGTH_RSSI_MASK; + sec_event.sig_strength.rssi_value = p_result->rssi; + if( bta_dm_cb.p_sec_cback!= NULL ) + bta_dm_cb.p_sec_cback(BTA_DM_SIG_STRENGTH_EVT, &sec_event); + + } +} + +/******************************************************************************* +** +** Function bta_dm_link_quality_cback +** +** Description Callback from btm with link quality value +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_link_quality_cback (tBTM_LINK_QUALITY_RESULTS *p_result) +{ + + tBTA_DM_SEC sec_event; + + if(p_result->status == BTM_SUCCESS) + { + + bdcpy(sec_event.sig_strength.bd_addr, p_result->rem_bda); + sec_event.sig_strength.mask = BTA_SIG_STRENGTH_LINK_QUALITY_MASK; + sec_event.sig_strength.link_quality_value = p_result->link_quality; + if( bta_dm_cb.p_sec_cback!= NULL ) + bta_dm_cb.p_sec_cback(BTA_DM_SIG_STRENGTH_EVT, &sec_event); + + } +} + +/******************************************************************************* +** +** Function bta_dm_rm_cback +** +** Description Role management callback from sys +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + + UINT8 j; + tBTA_PREF_ROLES role; + tBTA_DM_PEER_DEVICE *p_dev; + + p_dev = bta_dm_find_peer_device(peer_addr); + if( status == BTA_SYS_CONN_OPEN) + { + if(p_dev) + { + /* Do not set to connected if we are in the middle of unpairing. When AV stream is + * started it fakes out a SYS_CONN_OPEN to potentially trigger a role switch command. + * But this should not be done if we are in the middle of unpairing. + */ + if (p_dev->conn_state != BTA_DM_UNPAIRING) + p_dev->conn_state = BTA_DM_CONNECTED; + + for(j=1; j<= p_bta_dm_rm_cfg[0].app_id; j++) + { + if(((p_bta_dm_rm_cfg[j].app_id == app_id) || (p_bta_dm_rm_cfg[j].app_id == BTA_ALL_APP_ID)) + && (p_bta_dm_rm_cfg[j].id == id)) + { + role = p_bta_dm_rm_cfg[j].cfg; + + if(role > p_dev->pref_role ) + p_dev->pref_role = role; + break; + } + } + + } + + } + + if((BTA_ID_AV == id)||(BTA_ID_AVK ==id)) + { + if( status == BTA_SYS_CONN_BUSY) + { + if(p_dev) + p_dev->info |= BTA_DM_DI_AV_ACTIVE; + /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */ + if(BTA_ID_AV == id) + bta_dm_cb.cur_av_count = app_id; + } + else if( status == BTA_SYS_CONN_IDLE) + { + if(p_dev) + p_dev->info &= ~BTA_DM_DI_AV_ACTIVE; + /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */ + if(BTA_ID_AV == id) + bta_dm_cb.cur_av_count = app_id; + } + APPL_TRACE_WARNING2("bta_dm_rm_cback:%d, status:%d", bta_dm_cb.cur_av_count, status); + } + + + bta_dm_adjust_roles(FALSE); + +} + +/******************************************************************************* +** +** Function bta_dm_dev_blacklisted_for_switch +** +** Description Checks if the device is blacklisted for immediate role switch after connection. +** +** Returns TRUE if dev is blacklisted else FALSE +** +*******************************************************************************/ +static BOOLEAN bta_dm_dev_blacklisted_for_switch (BD_ADDR remote_bd_addr) +{ + UINT16 manufacturer = 0; + UINT16 lmp_sub_version = 0; + UINT8 lmp_version = 0; + UINT8 i = 0; + + if (BTM_ReadRemoteVersion(remote_bd_addr, &lmp_version, + &manufacturer, &lmp_sub_version) == BTM_SUCCESS) + { + /* Check if this device version info matches with is + blacklisted versions for role switch */ + for (i = 0; i < BTA_DM_MAX_ROLE_SWITCH_BLACKLIST_COUNT; i++) + { + if ((bta_role_switch_blacklist[i].lmp_version == lmp_version) && + (bta_role_switch_blacklist[i].manufacturer == manufacturer)&& + ((bta_role_switch_blacklist[i].lmp_sub_version & lmp_sub_version) == + bta_role_switch_blacklist[i].lmp_sub_version)) + { + APPL_TRACE_EVENT0("Black list F/W version matches.. Delay Role Switch..."); + return TRUE; + } + + } + } + return FALSE; +} + +/******************************************************************************* +** +** Function bta_dm_delay_role_switch_cback +** +** Description Callback from btm to delay a role switch +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_delay_role_switch_cback(TIMER_LIST_ENT *p_tle) +{ + APPL_TRACE_EVENT0("bta_dm_delay_role_switch_cback: initiating Delayed RS"); + bta_dm_adjust_roles (FALSE); +} + +/******************************************************************************* +** +** Function bta_dm_adjust_roles +** +** Description Adjust roles +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_adjust_roles(BOOLEAN delay_role_switch) +{ + + UINT8 i; + BOOLEAN set_master_role = FALSE; + + if(bta_dm_cb.device_list.count) + { + + /* the configuration is no scatternet + * or AV connection exists and there are more than one ACL link */ + if( (p_bta_dm_rm_cfg[0].cfg == BTA_DM_NO_SCATTERNET) || + (bta_dm_cb.cur_av_count && bta_dm_cb.device_list.count > 1) ) + { + + L2CA_SetDesireRole (HCI_ROLE_MASTER); + set_master_role = TRUE; + + } + + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + if(bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED) + { + if(!set_master_role && (bta_dm_cb.device_list.peer_device[i].pref_role != BTA_ANY_ROLE) + && (p_bta_dm_rm_cfg[0].cfg == BTA_DM_PARTIAL_SCATTERNET)) + { + L2CA_SetDesireRole (HCI_ROLE_MASTER); + set_master_role = TRUE; + } + + if((bta_dm_cb.device_list.peer_device[i].pref_role == BTA_MASTER_ROLE_ONLY) + || (bta_dm_cb.device_list.count > 1)) + { + + /* Initiating immediate role switch with certain remote devices + has caused issues due to role switch colliding with link encryption setup and + causing encryption (and in turn the link) to fail . These device . Firmware + versions are stored in a blacklist and role switch with these devices are + delayed to avoid the collision with link encryption setup */ + + if ((delay_role_switch == FALSE) || + (bta_dm_dev_blacklisted_for_switch( + bta_dm_cb.device_list.peer_device[i].peer_bdaddr) == FALSE)) + { + BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr, + HCI_ROLE_MASTER, NULL); + } + else + { + bta_dm_cb.switch_delay_timer.p_cback = + (TIMER_CBACK*)&bta_dm_delay_role_switch_cback; + bta_sys_start_timer(&bta_dm_cb.switch_delay_timer, 0, 500); + } + } + + } + } + + + if(!set_master_role) + { + + L2CA_SetDesireRole (L2CAP_DESIRED_LINK_ROLE); + + } + + } + else + { + L2CA_SetDesireRole (L2CAP_DESIRED_LINK_ROLE); + } + + +} + +/******************************************************************************* +** +** Function bta_dm_get_remname +** +** Description Returns a pointer to the remote name stored in the DM control +** block if it exists, or from the BTM memory. +** +** Returns char * - Pointer to the remote device name +*******************************************************************************/ +static char *bta_dm_get_remname(void) +{ + char *p_name = bta_dm_search_cb.peer_name; + char *p_temp; + + /* If the name isn't already stored, try retrieving from BTM */ + if (*p_name == '\0') + if ((p_temp = BTM_SecReadDevName(bta_dm_search_cb.peer_bdaddr)) != NULL) + p_name = p_temp; + + return p_name; +} + +/******************************************************************************* +** +** Function bta_dm_bond_cancel_complete_cback +** +** Description Authentication complete callback from BTM +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result) +{ + + tBTA_DM_SEC sec_event; + + if (result == BTM_SUCCESS) + sec_event.bond_cancel_cmpl.result = BTA_SUCCESS; + else + sec_event.bond_cancel_cmpl.result = BTA_FAILURE; + + if(bta_dm_cb.p_sec_cback) + { + bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event); + } +} + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE ) + #if ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) +/******************************************************************************* +** +** Function bta_dm_update_eir_uuid +** +** Description +** +** +*******************************************************************************/ +void bta_dm_update_eir_uuid (tBTA_DM_MSG *p_data) +{ + tBTA_DM_API_UPDATE_EIR_UUID *p_msg = (tBTA_DM_API_UPDATE_EIR_UUID *)p_data; + UINT8 xx; + UINT8 empty_slot = BTA_EIR_SERVER_NUM_CUSTOM_UUID; + UINT8 match_slot = BTA_EIR_SERVER_NUM_CUSTOM_UUID; + + for (xx = 0; xx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; xx++) + { + if (bta_dm_cb.custom_uuid[xx].len == 0) + { + if (empty_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID) + empty_slot = xx; + } + else if (match_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID) + { + if (!memcmp (bta_dm_cb.custom_uuid[xx].uu.uuid128, p_msg->uuid.uu.uuid128, p_msg->uuid.len)) + { + match_slot = xx;; + } + } + } + + if (p_msg->is_add) + { + if (match_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID) + { + if (empty_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID) + { + APPL_TRACE_ERROR0("No space to add UUID for EIR"); + return; + } + else + { + memcpy (&(bta_dm_cb.custom_uuid[empty_slot]), &(p_msg->uuid), sizeof(tBT_UUID)); + } + } + else + { + APPL_TRACE_ERROR0("UUID is already added for EIR"); + return; + } + } + else + { + if (match_slot == BTA_EIR_SERVER_NUM_CUSTOM_UUID) + { + APPL_TRACE_ERROR0("UUID is not found for EIR"); + return; + } + else + { + memset (&(bta_dm_cb.custom_uuid[match_slot]), 0, sizeof(tBT_UUID)); + } + } + + bta_dm_set_eir (NULL); +} + #endif + +/******************************************************************************* +** +** Function bta_dm_set_eir_config +** +** Description +** +** +*******************************************************************************/ +void bta_dm_set_eir_config (tBTA_DM_MSG *p_data) +{ + if (p_data->set_eir_cfg.p_eir_cfg) + { + /* User defined config */ + p_bta_dm_eir_cfg = p_data->set_eir_cfg.p_eir_cfg; + } + else + { + /* Back to default config */ + p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF*)&bta_dm_eir_cfg; + } + + bta_dm_set_eir (NULL); +} + +/******************************************************************************* +** +** Function bta_dm_set_eir +** +** Description This function creates EIR tagged data and writes it to controller. +** +** Returns None +** +*******************************************************************************/ +static void bta_dm_set_eir (char *local_name) +{ + BT_HDR *p_buf; + UINT8 *p; + UINT8 *p_length; +#if (BTA_EIR_CANNED_UUID_LIST != TRUE) + UINT8 *p_type; + UINT8 max_num_uuid; +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + UINT8 custom_uuid_idx; +#endif +#endif +#if (BTM_EIR_DEFAULT_FEC_REQUIRED == FALSE) + UINT8 free_eir_length = HCI_EXT_INQ_RESPONSE_LEN; +#else + UINT8 free_eir_length = HCI_DM5_PACKET_SIZE; +#endif + UINT8 num_uuid; + UINT8 data_type; + UINT8 local_name_len; + + /* wait until complete to disable */ + if (bta_dm_cb.disable_timer.in_use) + return; + +#if ( BTA_EIR_CANNED_UUID_LIST != TRUE ) + /* wait until App is ready */ + if (bta_dm_cb.app_ready_timer.in_use) + return; + + /* if local name is not provided, get it from controller */ + if( local_name == NULL ) + { + if( BTM_ReadLocalDeviceName( &local_name ) != BTM_SUCCESS ) + { + APPL_TRACE_ERROR0("Fail to read local device name for EIR"); + } + } +#endif + + /* Allocate a buffer to hold HCI command */ + if ((p_buf = (BT_HDR *)GKI_getpoolbuf(BTM_CMD_POOL_ID)) == NULL) + { + APPL_TRACE_ERROR0("bta_dm_set_eir couldn't allocate buffer"); + return; + } + p = (UINT8 *)p_buf + BTM_HCI_EIR_OFFSET; + + memset(p, 0x00, HCI_EXT_INQ_RESPONSE_LEN ); + + APPL_TRACE_DEBUG0("BTA is generating EIR"); + + if( local_name ) + local_name_len = strlen( local_name ); + else + local_name_len = 0; + + data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE; + /* if local name is longer than minimum length of shortened name */ + /* check whether it needs to be shortened or not */ + if( local_name_len > p_bta_dm_eir_cfg->bta_dm_eir_min_name_len ) + { + /* get number of UUID 16-bit list */ +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len/LEN_UUID_16; +#else + max_num_uuid = (free_eir_length - 2)/LEN_UUID_16; + data_type = BTM_GetEirSupportedServices( bta_dm_cb.eir_uuid, &p, + max_num_uuid, &num_uuid ); + p = (UINT8 *)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */ +#endif + + /* if UUID doesn't fit remaing space, shorten local name */ + if ( local_name_len > (free_eir_length - 4 - num_uuid*LEN_UUID_16)) + { + APPL_TRACE_WARNING0("BTA EIR: local name is shortened"); + local_name_len = p_bta_dm_eir_cfg->bta_dm_eir_min_name_len; + data_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE; + } + else + data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE; + } + + UINT8_TO_STREAM(p, local_name_len + 1); + UINT8_TO_STREAM(p, data_type); + memcpy(p, local_name, local_name_len); + p += local_name_len; + free_eir_length -= local_name_len + 2; + +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + /* if UUID list is provided as static data in configuration */ + if(( p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0 ) + &&(p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) + { + if( free_eir_length > LEN_UUID_16 + 2) + { + free_eir_length -= 2; + + if( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) + { + num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16; + data_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE; + } + else /* not enough room for all UUIDs */ + { + APPL_TRACE_WARNING0("BTA EIR: UUID 16-bit list is truncated"); + num_uuid = free_eir_length / LEN_UUID_16; + data_type = BTM_EIR_MORE_16BITS_UUID_TYPE; + } + UINT8_TO_STREAM(p, num_uuid * LEN_UUID_16 + 1); + UINT8_TO_STREAM(p, data_type); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, num_uuid * LEN_UUID_16 ); + p += num_uuid * LEN_UUID_16; + free_eir_length -= num_uuid * LEN_UUID_16; + } + } +#else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ + /* if UUID list is dynamic */ + if ( free_eir_length >= 2) + { + p_length = p++; + p_type = p++; + num_uuid = 0; + + max_num_uuid = (free_eir_length - 2)/LEN_UUID_16; + data_type = BTM_GetEirSupportedServices( bta_dm_cb.eir_uuid, &p, max_num_uuid, &num_uuid ); + + if( data_type == BTM_EIR_MORE_16BITS_UUID_TYPE ) + { + APPL_TRACE_WARNING0("BTA EIR: UUID 16-bit list is truncated"); + } +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + else + { + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) + { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_16) + { + if ( num_uuid < max_num_uuid ) + { + UINT16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid16); + num_uuid++; + } + else + { + data_type = BTM_EIR_MORE_16BITS_UUID_TYPE; + APPL_TRACE_WARNING0("BTA EIR: UUID 16-bit list is truncated"); + break; + } + } + } + } +#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_16 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * LEN_UUID_16 + 2; + } +#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */ + +#if ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + /* Adding 32-bit UUID list */ + if ( free_eir_length >= 2) + { + p_length = p++; + p_type = p++; + num_uuid = 0; + data_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE; + + max_num_uuid = (free_eir_length - 2)/LEN_UUID_32; + + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) + { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_32) + { + if ( num_uuid < max_num_uuid ) + { + UINT32_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid32); + num_uuid++; + } + else + { + data_type = BTM_EIR_MORE_32BITS_UUID_TYPE; + APPL_TRACE_WARNING0("BTA EIR: UUID 32-bit list is truncated"); + break; + } + } + } + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_32 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * LEN_UUID_32 + 2; + } + + /* Adding 128-bit UUID list */ + if ( free_eir_length >= 2) + { + p_length = p++; + p_type = p++; + num_uuid = 0; + data_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE; + + max_num_uuid = (free_eir_length - 2)/LEN_UUID_128; + + for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID; custom_uuid_idx++) + { + if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_128) + { + if ( num_uuid < max_num_uuid ) + { + ARRAY16_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid128); + num_uuid++; + } + else + { + data_type = BTM_EIR_MORE_128BITS_UUID_TYPE; + APPL_TRACE_WARNING0("BTA EIR: UUID 128-bit list is truncated"); + break; + } + } + } + + UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_128 + 1); + UINT8_TO_STREAM(p_type, data_type); + free_eir_length -= num_uuid * LEN_UUID_128 + 2; + } +#endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */ + + /* if Flags are provided in configuration */ + if(( p_bta_dm_eir_cfg->bta_dm_eir_flag_len > 0 ) + &&( p_bta_dm_eir_cfg->bta_dm_eir_flags ) + &&( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2 )) + { + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 1); + UINT8_TO_STREAM(p, BTM_EIR_FLAGS_TYPE); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_flags, + p_bta_dm_eir_cfg->bta_dm_eir_flag_len); + p += p_bta_dm_eir_cfg->bta_dm_eir_flag_len; + free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2; + } + + /* if Inquiry Tx Resp Power compiled */ + if((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && + (free_eir_length >= 3)) + { + UINT8_TO_STREAM(p, 2); /* Length field */ + UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE); + UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power)); + free_eir_length -= 3; + } + + /* if Manufacturer Specific are provided in configuration */ + if(( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0 ) + &&( p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec ) + &&( free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2 )) + { + p_length = p; + + UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1); + UINT8_TO_STREAM(p, BTM_EIR_MANUFACTURER_SPECIFIC_TYPE); + memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec, + p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len); + p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len; + free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2; + + } + else + { + p_length = NULL; + } + + if( free_eir_length ) + UINT8_TO_STREAM(p, 0); /* terminator of significant part */ + + BTM_WriteEIR( p_buf ); + +} +#endif + +#if ( BTM_EIR_CLIENT_INCLUDED == TRUE ) +/******************************************************************************* +** +** Function bta_dm_eir_search_services +** +** Description This function searches services in received EIR +** +** Returns None +** +*******************************************************************************/ +static void bta_dm_eir_search_services( tBTM_INQ_RESULTS *p_result, + tBTA_SERVICE_MASK *p_services_to_search, + tBTA_SERVICE_MASK *p_services_found) +{ + tBTA_SERVICE_MASK service_index = 0; + tBTM_EIR_SEARCH_RESULT result; + + APPL_TRACE_DEBUG6("BTA searching services in EIR of BDA:0x%02X%02X%02X%02X%02X%02X", + p_result->remote_bd_addr[0],p_result->remote_bd_addr[1], + p_result->remote_bd_addr[2],p_result->remote_bd_addr[3], + p_result->remote_bd_addr[4],p_result->remote_bd_addr[5]); + + APPL_TRACE_DEBUG1(" with services_to_search=0x%08X", *p_services_to_search); + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + /* always do GATT based service discovery by SDP instead of from EIR */ + /* if GATT based service is also to be put in EIR, need to modify this */ + while (service_index < (BTA_MAX_SERVICE_ID - 1)) +#else + while(service_index < BTA_MAX_SERVICE_ID) +#endif + { + if( *p_services_to_search + & (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index))) + { + result = BTM_HasInquiryEirService( p_result, + bta_service_id_to_uuid_lkup_tbl[service_index] ); + + /* Searching for HSP v1.2 only device */ + if ((result != BTM_EIR_FOUND) && + (bta_service_id_to_uuid_lkup_tbl[service_index] == UUID_SERVCLASS_HEADSET)) + { + result = BTM_HasInquiryEirService (p_result, UUID_SERVCLASS_HEADSET_HS); + } + + if( result == BTM_EIR_FOUND ) + { + /* If Plug and Play service record, need to check to see if Broadcom stack */ + /* However, EIR data doesn't have EXT_BRCM_VERSION so just skip it */ + if( bta_service_id_to_uuid_lkup_tbl[service_index] + != UUID_SERVCLASS_PNP_INFORMATION ) + { + + *p_services_found |= + (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)); + /* remove the service from services to be searched */ + *p_services_to_search &= + (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index))); + } + } + else if( result == BTM_EIR_NOT_FOUND ) + { + /* remove the service from services to be searched */ + *p_services_to_search &= + (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index))); + } + } + + service_index++; + } + + APPL_TRACE_ERROR2("BTA EIR search result, services_to_search=0x%08X, services_found=0x%08X", + *p_services_to_search, *p_services_found); +} +#endif + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) +/******************************************************************************* +** +** Function bta_dm_eir_update_uuid +** +** Description This function adds or removes service UUID in EIR database. +** +** Returns None +** +*******************************************************************************/ +void bta_dm_eir_update_uuid(UINT16 uuid16, BOOLEAN adding) +{ + /* if this UUID is not advertised in EIR */ + if( !BTM_HasEirService( p_bta_dm_eir_cfg->uuid_mask, uuid16 )) + return; + + if( adding ) + { + APPL_TRACE_EVENT1("Adding UUID=0x%04X into EIR", uuid16); + + BTM_AddEirService( bta_dm_cb.eir_uuid, uuid16 ); + } + else + { + APPL_TRACE_EVENT1("Removing UUID=0x%04X from EIR", uuid16); + + BTM_RemoveEirService( bta_dm_cb.eir_uuid, uuid16 ); + } + + bta_dm_set_eir (NULL); + + APPL_TRACE_EVENT2("bta_dm_eir_update_uuid UUID bit mask=0x%08X %08X", + bta_dm_cb.eir_uuid[1], bta_dm_cb.eir_uuid[0] ); +} +#endif + +/******************************************************************************* +** +** Function bta_dm_enable_test_mode +** +** Description enable test mode +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_enable_test_mode(tBTA_DM_MSG *p_data) +{ + BTM_EnableTestMode(); +} + +/******************************************************************************* +** +** Function bta_dm_disable_test_mode +** +** Description disable test mode +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disable_test_mode(tBTA_DM_MSG *p_data) +{ + BTM_DeviceReset(NULL); +} + +/******************************************************************************* +** +** Function bta_dm_execute_callback +** +** Description Just execute a generic call back in the context of the BTU/BTA tack +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_execute_callback(tBTA_DM_MSG *p_data) +{ + /* sanity check */ + if(p_data->exec_cback.p_exec_cback == NULL) + { + return; + } + + p_data->exec_cback.p_exec_cback(p_data->exec_cback.p_param); +} +/******************************************************************************* +** +** Function bta_dm_encrypt_cback +** +** Description link encryption complete callback. +** +** Returns None +** +*******************************************************************************/ +void bta_dm_encrypt_cback(BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result) +{ + tBTA_STATUS bta_status = BTA_SUCCESS; + tBTA_DM_ENCRYPT_CBACK *p_callback = bta_dm_cb.p_encrypt_cback; + + bta_dm_cb.p_encrypt_cback = NULL; + switch (result) + { + case BTM_SUCCESS: + break; + case BTM_WRONG_MODE: + bta_status = BTA_WRONG_MODE; + break; + case BTM_NO_RESOURCES: + bta_status = BTA_NO_RESOURCES; + break; + case BTM_BUSY: + bta_status = BTA_BUSY; + break; + default: + bta_status = BTA_FAILURE; + break; + } + + APPL_TRACE_DEBUG2("bta_dm_encrypt_cback status =%d p_callback=0x%x", bta_status, p_callback); + + if (p_callback) + { + (*p_callback)(bd_addr, bta_status); + } +} +/******************************************************************************* +** +** Function bta_dm_set_encryption +** +** Description This function to encrypt the link +** +** Returns None +** +*******************************************************************************/ +void bta_dm_set_encryption (tBTA_DM_MSG *p_data) +{ + + APPL_TRACE_DEBUG0("bta_dm_set_encryption"); //todo + if (!p_data->set_encryption.p_callback) + { + APPL_TRACE_ERROR0("bta_dm_set_encryption callback is not provided"); + return; + } + + if (bta_dm_cb.p_encrypt_cback) + { + (*p_data->set_encryption.p_callback)(p_data->set_encryption.bd_addr, BTA_BUSY); + return; + } + + + bta_dm_cb.p_encrypt_cback = p_data->set_encryption.p_callback; + bta_dm_cb.sec_act = p_data->set_encryption.sec_act; + BTM_SetEncryption(p_data->set_encryption.bd_addr, bta_dm_encrypt_cback, &bta_dm_cb.sec_act); +} + +/******************************************************************************* +** +** Function bta_dm_set_afh_channels +** +** Description set afh channels +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_set_afh_channels(tBTA_DM_MSG * p_data) +{ + + BTM_SetAfhChannels(p_data->set_afhchannels.first,p_data->set_afhchannels.last); +} + +/******************************************************************************* +** +** Function bta_dm_set_afh_channel_assesment +** +** Description set afh channel assesment +** +** +** Returns void +** +*******************************************************************************/ + +void bta_dm_set_afh_channel_assesment (tBTA_DM_MSG * p_data) +{ + BTM_SetAfhChannelAssessment(p_data->set_afh_channel_assessment.enable_or_disable); +} + +#if (BLE_INCLUDED == TRUE) +#if (SMP_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_ble_smp_cback +** +** Description Callback for BLE SMP +** +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_DATA *p_data) +{ + tBTM_STATUS status = BTM_SUCCESS; + tBTA_DM_SEC sec_event; + + if (!bta_dm_cb.p_sec_cback) + return BTM_NOT_AUTHORIZED; + + memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); + switch (event) + { + case BTM_LE_IO_REQ_EVT: +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + + bta_dm_co_ble_io_req(bda, + &p_data->io_req.io_cap, + &p_data->io_req.oob_data, + &p_data->io_req.auth_req, + &p_data->io_req.max_key_size, + &p_data->io_req.init_keys, + &p_data->io_req.resp_keys); +#endif +#if BTM_OOB_INCLUDED == FALSE + status = BTM_SUCCESS; +#endif + APPL_TRACE_EVENT2("io mitm: %d oob_data:%d", p_data->io_req.auth_req, p_data->io_req.oob_data); + + break; + + case BTM_LE_SEC_REQUEST_EVT: + bdcpy(sec_event.ble_req.bd_addr, bda); + BCM_STRNCPY_S((char*)sec_event.ble_req.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + bta_dm_cb.p_sec_cback(BTA_DM_BLE_SEC_REQ_EVT, &sec_event); + break; + + case BTM_LE_KEY_NOTIF_EVT: + bdcpy(sec_event.key_notif.bd_addr, bda); + BCM_STRNCPY_S((char*)sec_event.key_notif.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + sec_event.key_notif.passkey = p_data->key_notif; + bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_NOTIF_EVT, &sec_event); + break; + + case BTM_LE_KEY_REQ_EVT: + bdcpy(sec_event.ble_req.bd_addr, bda); + bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_REQ_EVT, &sec_event); + break; + + case BTM_LE_OOB_REQ_EVT: + bdcpy(sec_event.ble_req.bd_addr, bda); + bta_dm_cb.p_sec_cback(BTA_DM_BLE_OOB_REQ_EVT, &sec_event); + break; + + case BTM_LE_KEY_EVT: + bdcpy(sec_event.ble_key.bd_addr, bda); + sec_event.ble_key.key_type = p_data->key.key_type; + memcpy(&sec_event.ble_key.key_value, p_data->key.p_key_value, sizeof(tBTM_LE_KEY_VALUE)); + bta_dm_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event); + break; + + case BTM_LE_COMPLT_EVT: + bdcpy(sec_event.auth_cmpl.bd_addr, bda); + if (p_data->complt.reason != 0) + sec_event.auth_cmpl.fail_reason = BTA_DM_AUTH_CONVERT_SMP_CODE(((UINT8)p_data->complt.reason)); + else + sec_event.auth_cmpl.success = TRUE; + + if (bta_dm_cb.p_sec_cback) + { + //bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event); + bta_dm_cb.p_sec_cback(BTA_DM_BLE_AUTH_CMPL_EVT, &sec_event); + } + + break; + + default: + status = BTM_NOT_AUTHORIZED; + break; + } + return status; +} +#endif /* SMP_INCLUDED == TRUE */ + +/******************************************************************************* +** +** Function bta_dm_ble_id_key_cback +** +** Description Callback for BLE local ID keys +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_ble_id_key_cback (UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key) +{ + UINT8 evt; + tBTA_DM_SEC dm_key; + + switch (key_type) + { + case BTM_BLE_KEY_TYPE_ID: + case BTM_BLE_KEY_TYPE_ER: + if (bta_dm_cb.p_sec_cback) + { + memcpy(&dm_key.ble_id_keys, p_key, sizeof(tBTM_BLE_LOCAL_KEYS)); + + evt = (key_type == BTM_BLE_KEY_TYPE_ID) ? BTA_DM_BLE_LOCAL_IR_EVT :\ + BTA_DM_BLE_LOCAL_ER_EVT; + bta_dm_cb.p_sec_cback(evt, &dm_key); + } + break; + + default: + APPL_TRACE_DEBUG1("Unknown key type %d", key_type); + break; + } + return; + +} + +/******************************************************************************* +** +** Function bta_dm_add_blekey +** +** Description This function adds an BLE Key to an security database entry. +** This function shall only be called AFTER BTA_DmAddBleDevice has been called. +** It is normally called during host startup to restore all required information +** stored in the NVRAM. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_add_blekey (tBTA_DM_MSG *p_data) +{ + if (!BTM_SecAddBleKey (p_data->add_ble_key.bd_addr, + (tBTM_LE_KEY_VALUE *)&p_data->add_ble_key.blekey, + p_data->add_ble_key.key_type)) + { + APPL_TRACE_ERROR2 ("BTA_DM: Error adding BLE Key for device %08x%04x", + (p_data->add_ble_key.bd_addr[0]<<24)+(p_data->add_ble_key.bd_addr[1]<<16)+\ + (p_data->add_ble_key.bd_addr[2]<<8)+p_data->add_ble_key.bd_addr[3], + (p_data->add_ble_key.bd_addr[4]<<8)+p_data->add_ble_key.bd_addr[5]); + } +} + +/******************************************************************************* +** +** Function bta_dm_add_ble_device +** +** Description This function adds an BLE device to an security database entry. +** It is normally called during host startup to restore all required information +** stored in the NVRAM. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_add_ble_device (tBTA_DM_MSG *p_data) +{ + if (!BTM_SecAddBleDevice (p_data->add_ble_device.bd_addr, NULL, + p_data->add_ble_device.dev_type , + p_data->add_ble_device.addr_type)) + { + APPL_TRACE_ERROR2 ("BTA_DM: Error adding BLE Device for device %08x%04x", + (p_data->add_ble_device.bd_addr[0]<<24)+(p_data->add_ble_device.bd_addr[1]<<16)+ \ + (p_data->add_ble_device.bd_addr[2]<<8)+p_data->add_ble_device.bd_addr[3], + (p_data->add_ble_device.bd_addr[4]<<8)+p_data->add_ble_device.bd_addr[5]); + } +} + +/******************************************************************************* +** +** Function bta_dm_add_ble_device +** +** Description This function adds an BLE device to an security database entry. +** It is normally called during host startup to restore all required information +** stored in the NVRAM. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_passkey_reply (tBTA_DM_MSG *p_data) +{ + if (p_data->pin_reply.accept) + { + + BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_SUCCESS, p_data->ble_passkey_reply.passkey); + } + else + { + BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED, p_data->ble_passkey_reply.passkey); + } + +} + +/******************************************************************************* +** +** Function bta_dm_security_grant +** +** Description This function grant SMP security request access. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_security_grant (tBTA_DM_MSG *p_data) +{ + BTM_SecurityGrant(p_data->ble_sec_grant.bd_addr, p_data->ble_sec_grant.res); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_bg_conn_type +** +** Description This function set the BLE background connection type +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data) +{ + BTM_BleSetBgConnType(p_data->ble_set_bd_conn_type.bg_conn_type, + p_data->ble_set_bd_conn_type.p_select_cback); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_conn_params +** +** Description This function set the preferred connection parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_conn_params (tBTA_DM_MSG *p_data) +{ + BTM_BleSetPrefConnParams(p_data->ble_set_conn_params.peer_bda, + p_data->ble_set_conn_params.conn_int_min, + p_data->ble_set_conn_params.conn_int_max, + p_data->ble_set_conn_params.slave_latency, + p_data->ble_set_conn_params.supervision_tout); +} + +/******************************************************************************* +** +** Function bta_dm_ble_set_scan_params +** +** Description This function set the preferred connection scan parameters. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_ble_set_scan_params (tBTA_DM_MSG *p_data) +{ + BTM_BleSetConnScanParams(p_data->ble_set_scan_params.scan_int, + p_data->ble_set_scan_params.scan_window); +} + +#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + +/******************************************************************************* +** +** Function btm_dm_start_disc_gatt_services +** +** Description This function starts a GATT service search request. +** +** Parameters: +** +*******************************************************************************/ +static void btm_dm_start_disc_gatt_services (UINT16 conn_id) +{ + tBT_UUID *p_uuid = bta_dm_search_cb.p_srvc_uuid + + bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search; + + p_uuid = bta_dm_search_cb.p_srvc_uuid + + bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search; + + /* always search for all services */ + BTA_GATTC_ServiceSearchRequest(conn_id, p_uuid); +} + +/******************************************************************************* +** +** Function bta_dm_gatt_disc_result +** +** Description This function process the GATT service search result. +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id) +{ + tBTA_DM_SEARCH result; + + /* + * This logic will not work for gatt case. We are checking against the bluetooth profiles here + * just copy the GATTID in raw data field and send it across. + */ + + + if ( bta_dm_search_cb.ble_raw_used + sizeof(tBTA_GATT_ID) < bta_dm_search_cb.ble_raw_size ) + { + APPL_TRACE_DEBUG3("ADDING BLE SERVICE uuid=0x%x, ble_ptr = 0x%x, ble_raw_used = 0x%x", service_id.uuid.uu.uuid16,bta_dm_search_cb.p_ble_rawdata,bta_dm_search_cb.ble_raw_used); + + memcpy((bta_dm_search_cb.p_ble_rawdata + bta_dm_search_cb.ble_raw_used), &service_id, + sizeof(service_id) ); + + bta_dm_search_cb.ble_raw_used += sizeof(service_id); + + } + else + { + APPL_TRACE_ERROR3("%s out of room to accomodate more service ids ble_raw_size = %d ble_raw_used = %d", __FUNCTION__,bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used ); + } + + APPL_TRACE_ERROR1("bta_dm_gatt_disc_result serivce_id len=%d ", service_id.uuid.len); + if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) + { + + /* send result back to app now, one by one */ + bdcpy (result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)result.disc_ble_res.bd_name, sizeof(BD_NAME), bta_dm_get_remname(), (BD_NAME_LEN-1)); + memcpy(&result.disc_ble_res.service, &service_id.uuid, sizeof(tBT_UUID)); + + bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result); + } +} + +/******************************************************************************* +** +** Function bta_dm_gatt_disc_complete +** +** Description This function process the GATT service search complete. +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_gatt_disc_complete(UINT16 conn_id, tBTA_GATT_STATUS status) +{ + tBTA_DM_MSG *p_msg; + + APPL_TRACE_DEBUG1("bta_dm_gatt_disc_complete conn_id = %d",conn_id); + + if (bta_dm_search_cb.uuid_to_search > 0) bta_dm_search_cb.uuid_to_search --; + + if (status == BTA_GATT_OK && bta_dm_search_cb.uuid_to_search > 0) + { + btm_dm_start_disc_gatt_services(conn_id); + } + else + { + bta_dm_search_cb.uuid_to_search = 0; + + /* no more services to be discovered */ + if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT; + p_msg->disc_result.result.disc_res.result = (status == BTA_GATT_OK) ? BTA_SUCCESS :BTA_FAILURE; + p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; + bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); + BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), + bta_dm_get_remname(), (BD_NAME_LEN-1)); + + /* make sure the string is terminated */ + p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; + + p_msg->disc_result.result.disc_res.device_type = BT_DEVICE_TYPE_BLE; + if ( bta_dm_search_cb.ble_raw_used > 0 ) + { + p_msg->disc_result.result.disc_res.p_raw_data = GKI_getbuf(bta_dm_search_cb.ble_raw_used); + + memcpy( p_msg->disc_result.result.disc_res.p_raw_data, + bta_dm_search_cb.p_ble_rawdata, + bta_dm_search_cb.ble_raw_used ); + + p_msg->disc_result.result.disc_res.raw_data_size = bta_dm_search_cb.ble_raw_used; + } + else + { + p_msg->disc_result.result.disc_res.p_raw_data = NULL; + bta_dm_search_cb.p_ble_rawdata = 0; + } + + bta_sys_sendmsg(p_msg); + } + if (conn_id != BTA_GATT_INVALID_CONN_ID) + { + BTA_GATTC_Close(conn_id); + } + bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID; + bta_dm_search_cb.gatt_disc_active = FALSE; + } +} + +/******************************************************************************* +** +** Function btm_dm_start_gatt_discovery +** +** Description This is GATT initiate the service search by open a GATT connection +** first. +** +** Parameters: +** +*******************************************************************************/ +void btm_dm_start_gatt_discovery (BD_ADDR bd_addr) +{ + bta_dm_search_cb.gatt_disc_active = TRUE; + BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, TRUE); +} + +/******************************************************************************* +** +** Function bta_dm_cancel_gatt_discovery +** +** Description This is GATT cancel the GATT service search. +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr) +{ + if (bta_dm_search_cb.conn_id == BTA_GATT_INVALID_CONN_ID) + { + BTA_GATTC_CancelOpen(bta_dm_search_cb.client_if, bd_addr, TRUE); + } + + bta_dm_gatt_disc_complete(bta_dm_search_cb.conn_id, (tBTA_GATT_STATUS) BTA_GATT_ERROR); +} + +/******************************************************************************* +** +** Function bta_dm_proc_open_evt +** +** Description process BTA_GATTC_OPEN_EVT in DM. +** +** Parameters: +** +*******************************************************************************/ +void bta_dm_proc_open_evt(tBTA_GATTC_OPEN *p_data) +{ + UINT8 *p1; + UINT8 *p2; + + p1 = bta_dm_search_cb.peer_bdaddr; + p2 = p_data->remote_bda; + + APPL_TRACE_DEBUG5("DM Search state= %d search_cb.peer_dbaddr: [%08x%04x] connected_bda= [%08x%04x] ", + bta_dm_search_cb.state, + ((p1[0])<<24)+((p1[1])<<16)+((p1[2])<<8)+(p1[3]), + ((p1[4])<<8)+ p1[5], + ((p2[0])<<24)+((p2[1])<<16)+((p2[2])<<8)+(p2[3]), + ((p2[4])<<8)+ p2[5]); + + APPL_TRACE_DEBUG3("BTA_GATTC_OPEN_EVT conn_id = %d client_if=%d status = %d" , + p_data->conn_id, + p_data->client_if, + p_data->status); + + bta_dm_search_cb.conn_id = p_data->conn_id; + + if (p_data->status == BTA_GATT_OK) + { + btm_dm_start_disc_gatt_services(p_data->conn_id); + } + else + { + bta_dm_gatt_disc_complete(BTA_GATT_INVALID_CONN_ID, p_data->status); + } +} + +/******************************************************************************* +** +** Function bta_dm_gattc_callback +** +** Description This is GATT client callback function used in DM. +** +** Parameters: +** +*******************************************************************************/ +static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data) +{ + APPL_TRACE_DEBUG1("bta_dm_gattc_callback event = %d", event); + + switch (event) + { + case BTA_GATTC_REG_EVT: + APPL_TRACE_DEBUG1("BTA_GATTC_REG_EVT client_if = %d", p_data->reg_oper.client_if); + if (p_data->reg_oper.status == BTA_GATT_OK) + bta_dm_search_cb.client_if = p_data->reg_oper.client_if; + else + bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF; + break; + + case BTA_GATTC_OPEN_EVT: + bta_dm_proc_open_evt(&p_data->open); + break; + + case BTA_GATTC_SEARCH_RES_EVT: + bta_dm_gatt_disc_result(p_data->srvc_res.service_uuid.id); + break; + + case BTA_GATTC_SEARCH_CMPL_EVT: + if ( bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) + bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id, p_data->search_cmpl.status); + break; + + case BTA_GATTC_CLOSE_EVT: + APPL_TRACE_DEBUG1("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason); + /* in case of disconnect before search is completed */ + if ( (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) && + !memcmp(p_data->close.remote_bda, bta_dm_search_cb.peer_bdaddr, BD_ADDR_LEN)) + { + bta_dm_gatt_disc_complete((UINT16)BTA_GATT_INVALID_CONN_ID, (tBTA_GATT_STATUS) BTA_GATT_ERROR); + } + break; + + default: + break; + } +} + +#endif /* BTA_GATT_INCLUDED */ + +#endif /* BLE_INCLUDED */ diff --git a/bta/dm/bta_dm_api.c b/bta/dm/bta_dm_api.c new file mode 100644 index 0000000..06e3b93 --- /dev/null +++ b/bta/dm/bta_dm_api.c @@ -0,0 +1,1616 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 API implementation file for the BTA device manager. + * + ******************************************************************************/ + +#include "gki.h" +#include "bd.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +#include "bta_sys_int.h" +#include "btm_api.h" +#include "btm_int.h" +#include <string.h> + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_dm_reg = +{ + bta_dm_sm_execute, + bta_dm_sm_disable +}; + +static const tBTA_SYS_REG bta_dm_search_reg = +{ + bta_dm_search_sm_execute, + bta_dm_search_sm_disable +}; + +/******************************************************************************* +** +** Function BTA_EnableBluetooth +** +** Description Enables bluetooth service. This function must be +** called before any other functions in the BTA API are called. +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback) +{ + + tBTA_DM_API_ENABLE *p_msg; + + /* Bluetooth disabling is in progress */ + if (bta_dm_cb.disabling) + return BTA_FAILURE; + + memset(&bta_dm_cb, 0, sizeof(bta_dm_cb)); + + GKI_sched_lock(); + bta_sys_register (BTA_ID_DM, &bta_dm_reg ); + bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg ); + + /* if UUID list is not provided as static data */ + bta_sys_eir_register(bta_dm_eir_update_uuid); + + GKI_sched_unlock(); + + if ((p_msg = (tBTA_DM_API_ENABLE *) GKI_getbuf(sizeof(tBTA_DM_API_ENABLE))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_ENABLE_EVT; + p_msg->p_sec_cback = p_cback; + bta_sys_sendmsg(p_msg); + return BTA_SUCCESS; + } + return BTA_FAILURE; + +} + +/******************************************************************************* +** +** Function BTA_DisableBluetooth +** +** Description Disables bluetooth service. This function is called when +** the application no longer needs bluetooth service +** +** Returns void +** +*******************************************************************************/ +tBTA_STATUS BTA_DisableBluetooth(void) +{ + + BT_HDR *p_msg; + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_DM_API_DISABLE_EVT; + bta_sys_sendmsg(p_msg); + } + else + { + return BTA_FAILURE; + } + + return BTA_SUCCESS; +} + +/******************************************************************************* +** +** Function BTA_EnableTestMode +** +** Description Enables bluetooth device under test mode +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +tBTA_STATUS BTA_EnableTestMode(void) +{ + BT_HDR *p_msg; + + APPL_TRACE_API0("BTA_EnableTestMode"); + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_DM_API_ENABLE_TEST_MODE_EVT; + bta_sys_sendmsg(p_msg); + return BTA_SUCCESS; + } + return BTA_FAILURE; +} + +/******************************************************************************* +** +** Function BTA_DisableTestMode +** +** Description Disable bluetooth device under test mode +** +** +** Returns None +** +*******************************************************************************/ +void BTA_DisableTestMode(void) +{ + BT_HDR *p_msg; + + APPL_TRACE_API0("BTA_DisableTestMode"); + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_DM_API_DISABLE_TEST_MODE_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmIsDeviceUp +** +** Description Called during startup to check whether the bluetooth module +** is up and ready +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN BTA_DmIsDeviceUp(void) +{ + + BOOLEAN status; + + GKI_sched_lock(); + status = BTM_IsDeviceUp(); + GKI_sched_unlock(); + return status; + +} + +/******************************************************************************* +** +** Function BTA_DmSetDeviceName +** +** Description This function sets the Bluetooth name of local device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetDeviceName(char *p_name) +{ + + tBTA_DM_API_SET_NAME *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_NAME *) GKI_getbuf(sizeof(tBTA_DM_API_SET_NAME))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_SET_NAME_EVT; + /* truncate the name if needed */ + BCM_STRNCPY_S(p_msg->name, sizeof(p_msg->name), p_name, BD_NAME_LEN-1); + p_msg->name[BD_NAME_LEN-1]=0; + + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmSetVisibility +** +** Description This function sets the Bluetooth connectable, +** discoverable, pairable and conn paired only modes of local device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, UINT8 pairable_mode, UINT8 conn_filter ) +{ + + tBTA_DM_API_SET_VISIBILITY *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_VISIBILITY *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_SET_VISIBILITY_EVT; + p_msg->disc_mode = disc_mode; + p_msg->conn_mode = conn_mode; + p_msg->pair_mode = pairable_mode; + p_msg->conn_paired_only = conn_filter; + + + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmSetScanParam +** +** Description This function sets the parameters for page scan and +** inquiry scan. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetScanParam (UINT16 page_scan_interval, UINT16 page_scan_window, + UINT16 inquiry_scan_interval, UINT16 inquiry_scan_window) +{ + APPL_TRACE_API4 ("BTA_DmSetScanParam: %d, %d, %d, %d", + page_scan_interval, page_scan_window, + inquiry_scan_interval, inquiry_scan_window); + + bta_dm_cb.page_scan_interval = page_scan_interval; + bta_dm_cb.page_scan_window = page_scan_window; + bta_dm_cb.inquiry_scan_interval = inquiry_scan_interval; + bta_dm_cb.inquiry_scan_window = inquiry_scan_window; +} + +/******************************************************************************* +** +** Function BTA_DmSetAfhChannels +** +** Description This function sets the AFH first and +** last disable channel, so channels within +** that range are disabled. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetAfhChannels(UINT8 first, UINT8 last) +{ + + tBTA_DM_API_SET_AFH_CHANNELS_EVT *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_AFH_CHANNELS_EVT *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_SET_AFH_CHANNELS_EVT; + p_msg->first = first; + p_msg->last = last; + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_SetAfhChannelAssessment +** +** Description This function is called to set the channel assessment mode on or off +** +** Returns status +** +*******************************************************************************/ +void BTA_DmSetAfhChannelAssessment (BOOLEAN enable_or_disable) +{ + tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT *) GKI_getbuf(sizeof(tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_SET_AFH_CHANNEL_ASSESMENT_EVT; + p_msg->enable_or_disable = enable_or_disable; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmVendorSpecificCommand +** +** Description This function sends the vendor specific command +** to the controller +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +tBTA_STATUS BTA_DmVendorSpecificCommand (UINT16 opcode, UINT8 param_len, + UINT8 *p_param_buf, + tBTA_VENDOR_CMPL_CBACK *p_cback) +{ + + tBTA_DM_API_VENDOR_SPECIFIC_COMMAND *p_msg; + UINT16 size; + + /* If p_cback is NULL, Notify application */ + if (p_cback == NULL) + { + return (BTA_FAILURE); + } + else + { + size = sizeof (tBTA_DM_API_VENDOR_SPECIFIC_COMMAND) + param_len; + if ((p_msg = (tBTA_DM_API_VENDOR_SPECIFIC_COMMAND *) GKI_getbuf(size)) != NULL) + { + p_msg->hdr.event = BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT; + p_msg->opcode = opcode; + p_msg->param_len = param_len; + p_msg->p_param_buf = (UINT8 *)(p_msg + 1); + p_msg->p_cback = p_cback; + + memcpy (p_msg->p_param_buf, p_param_buf, param_len); + + bta_sys_sendmsg(p_msg); + } + return (BTA_SUCCESS); + } +} +/******************************************************************************* +** +** Function BTA_DmSearch +** +** Description This function searches for peer Bluetooth devices. It performs +** an inquiry and gets the remote name for devices. Service +** discovery is done if services is non zero +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback) +{ + + tBTA_DM_API_SEARCH *p_msg; + + if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH)); + + p_msg->hdr.event = BTA_DM_API_SEARCH_EVT; + memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ)); + p_msg->services = services; + p_msg->p_cback = p_cback; + p_msg->rs_res = BTA_DM_RS_NONE; + bta_sys_sendmsg(p_msg); + } + +} + + +/******************************************************************************* +** +** Function BTA_DmSearchCancel +** +** Description This function cancels a search initiated by BTA_DmSearch +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSearchCancel(void) +{ + BT_HDR *p_msg; + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_DM_API_SEARCH_CANCEL_EVT; + bta_sys_sendmsg(p_msg); + } + +} + +/******************************************************************************* +** +** Function BTA_DmDiscover +** +** Description This function does service discovery for services of a +** peer device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search) +{ + tBTA_DM_API_DISCOVER *p_msg; + + if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_DISCOVER)); + + p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->services = services; + p_msg->p_cback = p_cback; + p_msg->sdp_search = sdp_search; + bta_sys_sendmsg(p_msg); + } + +} + +/******************************************************************************* +** +** Function BTA_DmDiscoverUUID +** +** Description This function does service discovery for services of a +** peer device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID *uuid, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search) +{ + tBTA_DM_API_DISCOVER *p_msg; + + if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(sizeof(tBTA_DM_API_DISCOVER))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->services = BTA_USER_SERVICE_MASK; //Not exposed at API level + p_msg->p_cback = p_cback; + p_msg->sdp_search = sdp_search; + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + p_msg->num_uuid = 0; + p_msg->p_uuid = NULL; +#endif + memcpy( &p_msg->uuid, uuid, sizeof(tSDP_UUID) ); + bta_sys_sendmsg(p_msg); + } + +} +/******************************************************************************* +** +** Function BTA_DmIsMaster +** +** Description This function checks if the local device is the master of +** the link to the given device +** +** Returns TRUE if master. +** FALSE if not. +** +*******************************************************************************/ +BOOLEAN BTA_DmIsMaster(BD_ADDR bd_addr) +{ + BOOLEAN is_master = FALSE; + UINT8 link_role; + + BTM_GetRole(bd_addr, &link_role); + APPL_TRACE_API1("BTA_DmIsMaster role:x%x", link_role); + if(link_role == BTM_ROLE_MASTER) + { + is_master = TRUE; + } + return is_master; +} + +/******************************************************************************* +** +** Function BTA_DmBond +** +** Description This function initiates a bonding procedure with a peer +** device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBond(BD_ADDR bd_addr) +{ + tBTA_DM_API_BOND *p_msg; + + if ((p_msg = (tBTA_DM_API_BOND *) GKI_getbuf(sizeof(tBTA_DM_API_BOND))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BOND_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmBondCancel +** +** Description This function cancels the bonding procedure with a peer +** device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBondCancel(BD_ADDR bd_addr) +{ + tBTA_DM_API_BOND_CANCEL *p_msg; + + if ((p_msg = (tBTA_DM_API_BOND_CANCEL *) GKI_getbuf(sizeof(tBTA_DM_API_BOND_CANCEL))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_BOND_CANCEL_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmPinReply +** +** Description This function provides a pincode for a remote device when +** one is requested by DM through BTA_DM_PIN_REQ_EVT +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmPinReply(BD_ADDR bd_addr, BOOLEAN accept, UINT8 pin_len, UINT8 *p_pin) + +{ + tBTA_DM_API_PIN_REPLY *p_msg; + + if ((p_msg = (tBTA_DM_API_PIN_REPLY *) GKI_getbuf(sizeof(tBTA_DM_API_PIN_REPLY))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_PIN_REPLY_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + if(accept) + { + p_msg->pin_len = pin_len; + memcpy(p_msg->p_pin, p_pin, pin_len); + } + bta_sys_sendmsg(p_msg); + } + +} + +/******************************************************************************* +** +** Function BTA_DmLinkPolicy +** +** Description This function sets/clears the link policy mask to the given +** bd_addr. +** If clearing the sniff or park mode mask, the link is put +** in active mode. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmLinkPolicy(BD_ADDR bd_addr, tBTA_DM_LP_MASK policy_mask, + BOOLEAN set) +{ + tBTA_DM_API_LINK_POLICY *p_msg; + + if ((p_msg = (tBTA_DM_API_LINK_POLICY *) GKI_getbuf(sizeof(tBTA_DM_API_LINK_POLICY))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_LINK_POLICY_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->policy_mask = policy_mask; + p_msg->set = set; + bta_sys_sendmsg(p_msg); + } +} + + +#if (BTM_OOB_INCLUDED == TRUE) +/******************************************************************************* +** +** Function BTA_DmLocalOob +** +** Description This function retrieves the OOB data from local controller. +** The result is reported by bta_dm_co_loc_oob(). +** +** Returns void +** +*******************************************************************************/ +void BTA_DmLocalOob(void) +{ + tBTA_DM_API_LOC_OOB *p_msg; + + if ((p_msg = (tBTA_DM_API_LOC_OOB *) GKI_getbuf(sizeof(tBTA_DM_API_LOC_OOB))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_LOC_OOB_EVT; + bta_sys_sendmsg(p_msg); + } +} +#endif /* BTM_OOB_INCLUDED */ +/******************************************************************************* +** +** Function BTA_DmConfirm +** +** Description This function accepts or rejects the numerical value of the +** Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT +** +** Returns void +** +*******************************************************************************/ +void BTA_DmConfirm(BD_ADDR bd_addr, BOOLEAN accept) +{ + tBTA_DM_API_CONFIRM *p_msg; + + if ((p_msg = (tBTA_DM_API_CONFIRM *) GKI_getbuf(sizeof(tBTA_DM_API_CONFIRM))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_CONFIRM_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmPasskeyCancel +** +** Description This function is called to cancel the simple pairing process +** reported by BTA_DM_SP_KEY_NOTIF_EVT +** +** Returns void +** +*******************************************************************************/ +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) +void BTA_DmPasskeyCancel(BD_ADDR bd_addr) +{ + tBTA_DM_API_PASKY_CANCEL *p_msg; + + if ((p_msg = (tBTA_DM_API_PASKY_CANCEL *) \ + GKI_getbuf(sizeof(tBTA_DM_API_PASKY_CANCEL))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_PASKY_CANCEL_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + bta_sys_sendmsg(p_msg); + } +} +#endif + + +/******************************************************************************* +** +** Function BTA_DmAddDevice +** +** Description This function adds a device to the security database list of +** peer device +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key, + tBTA_SERVICE_MASK trusted_mask, BOOLEAN is_trusted, + UINT8 key_type, tBTA_IO_CAP io_cap) +{ + + tBTA_DM_API_ADD_DEVICE *p_msg; + + if ((p_msg = (tBTA_DM_API_ADD_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_DEVICE))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_DEVICE)); + + p_msg->hdr.event = BTA_DM_API_ADD_DEVICE_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->tm = trusted_mask; + p_msg->is_trusted = is_trusted; + p_msg->io_cap = io_cap; + + if (link_key) + { + p_msg->link_key_known = TRUE; + p_msg->key_type = key_type; + memcpy(p_msg->link_key, link_key, LINK_KEY_LEN); + } + + /* Load device class if specified */ + if (dev_class) + { + p_msg->dc_known = TRUE; + memcpy (p_msg->dc, dev_class, DEV_CLASS_LEN); + } + + memset (p_msg->bd_name, 0, BD_NAME_LEN); + memset (p_msg->features, 0, BD_FEATURES_LEN); + + bta_sys_sendmsg(p_msg); + } +} + + +/******************************************************************************* +** +** Function BTA_DmRemoveDevice +** +** Description This function removes a device fromthe security database list of +** peer device +** +** +** Returns void +** +*******************************************************************************/ +tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr) +{ + tBTA_DM_API_REMOVE_DEVICE *p_msg; + + if ((p_msg = (tBTA_DM_API_REMOVE_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_REMOVE_DEVICE))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_REMOVE_DEVICE)); + + p_msg->hdr.event = BTA_DM_API_REMOVE_DEVICE_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + bta_sys_sendmsg(p_msg); + } + else + { + return BTA_FAILURE; + } + + return BTA_SUCCESS; +} + +/******************************************************************************* +** +** Function BTA_DmAddDevWithName +** +** Description This function is newer version of BTA_DmAddDevice() +** which added bd_name and features as input parameters. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmAddDevWithName (BD_ADDR bd_addr, DEV_CLASS dev_class, + BD_NAME bd_name, BD_FEATURES features, + LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask, + BOOLEAN is_trusted, UINT8 key_type, tBTA_IO_CAP io_cap) +{ + tBTA_DM_API_ADD_DEVICE *p_msg; + + if ((p_msg = (tBTA_DM_API_ADD_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_DEVICE))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_DEVICE)); + + p_msg->hdr.event = BTA_DM_API_ADD_DEVICE_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->tm = trusted_mask; + p_msg->is_trusted = is_trusted; + p_msg->io_cap = io_cap; + + if (link_key) + { + p_msg->link_key_known = TRUE; + p_msg->key_type = key_type; + memcpy(p_msg->link_key, link_key, LINK_KEY_LEN); + } + + /* Load device class if specified */ + if (dev_class) + { + p_msg->dc_known = TRUE; + memcpy (p_msg->dc, dev_class, DEV_CLASS_LEN); + } + + if (bd_name) + memcpy(p_msg->bd_name, bd_name, BD_NAME_LEN); + + if (features) + memcpy(p_msg->features, features, BD_FEATURES_LEN); + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmAuthorizeReply +** +** Description This function provides an authorization reply when authorization +** is requested by BTA through BTA_DM_AUTHORIZE_EVT +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +void BTA_DmAuthorizeReply(BD_ADDR bd_addr, tBTA_SERVICE_ID service, tBTA_AUTH_RESP response) +{ + + tBTA_DM_API_AUTH_REPLY *p_msg; + + if ((p_msg = (tBTA_DM_API_AUTH_REPLY *) GKI_getbuf(sizeof(tBTA_DM_API_AUTH_REPLY))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_AUTH_REPLY_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->service = service; + p_msg->response = response; + + bta_sys_sendmsg(p_msg); + } + +} + +/******************************************************************************* +** +** Function BTA_DmSignalStrength +** +** Description This function initiates RSSI and channnel quality +** measurments. BTA_DM_SIG_STRENGTH_EVT is sent to +** application with the values of RSSI and channel +** quality +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSignalStrength(tBTA_SIG_STRENGTH_MASK mask, UINT16 period, BOOLEAN start) +{ + + tBTA_API_DM_SIG_STRENGTH *p_msg; + + if ((p_msg = (tBTA_API_DM_SIG_STRENGTH *) GKI_getbuf(sizeof(tBTA_API_DM_SIG_STRENGTH))) != NULL) + { + p_msg->hdr.event = BTA_API_DM_SIG_STRENGTH_EVT; + p_msg->mask = mask; + p_msg->period = period; + p_msg->start = start; + + bta_sys_sendmsg(p_msg); + } + + +} + +/******************************************************************************* +** +** Function BTA_DmWriteInqTxPower +** +** Description This command is used to write the inquiry transmit power level +** used to transmit the inquiry (ID) data packets. +** +** Parameters tx_power - tx inquiry power to use, valid value is -70 ~ 20 + +** Returns void +** +*******************************************************************************/ +void BTA_DmWriteInqTxPower(INT8 tx_power) +{ + + tBTA_API_DM_TX_INQPWR *p_msg; + + if ((p_msg = (tBTA_API_DM_TX_INQPWR *) GKI_getbuf(sizeof(tBTA_API_DM_TX_INQPWR))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_TX_INQPWR_EVT; + p_msg->tx_power = tx_power; + + bta_sys_sendmsg(p_msg); + } +} + + +/******************************************************************************* +** +** Function BTA_DmEirAddUUID +** +** Description This function is called to add UUID into EIR. +** +** Parameters tBT_UUID - UUID +** +** Returns None +** +*******************************************************************************/ +void BTA_DmEirAddUUID (tBT_UUID *p_uuid) +{ +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + tBTA_DM_API_UPDATE_EIR_UUID *p_msg; + + if ((p_msg = (tBTA_DM_API_UPDATE_EIR_UUID *) GKI_getbuf(sizeof(tBTA_DM_API_UPDATE_EIR_UUID))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_UPDATE_EIR_UUID_EVT; + p_msg->is_add = TRUE; + memcpy (&(p_msg->uuid), p_uuid, sizeof(tBT_UUID)); + + bta_sys_sendmsg(p_msg); + } +#endif +} + +/******************************************************************************* +** +** Function BTA_DmEirRemoveUUID +** +** Description This function is called to remove UUID from EIR. +** +** Parameters tBT_UUID - UUID +** +** Returns None +** +*******************************************************************************/ +void BTA_DmEirRemoveUUID (tBT_UUID *p_uuid) +{ +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + tBTA_DM_API_UPDATE_EIR_UUID *p_msg; + + if ((p_msg = (tBTA_DM_API_UPDATE_EIR_UUID *) GKI_getbuf(sizeof(tBTA_DM_API_UPDATE_EIR_UUID))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_UPDATE_EIR_UUID_EVT; + p_msg->is_add = FALSE; + memcpy (&(p_msg->uuid), p_uuid, sizeof(tBT_UUID)); + + bta_sys_sendmsg(p_msg); + } +#endif +} + +/******************************************************************************* +** +** Function BTA_DmSetEIRConfig +** +** Description This function is called to override the BTA default EIR parameters. +** This funciton is only valid in a system where BTU & App task +** are in the same memory space. +** +** Parameters Pointer to User defined EIR config +** +** Returns None +** +*******************************************************************************/ +void BTA_DmSetEIRConfig (tBTA_DM_EIR_CONF *p_eir_cfg) +{ +#if (BTM_EIR_SERVER_INCLUDED == TRUE) + tBTA_DM_API_SET_EIR_CONFIG *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_EIR_CONFIG *) GKI_getbuf(sizeof(tBTA_DM_API_SET_EIR_CONFIG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_SET_EIR_CONFIG_EVT; + p_msg->p_eir_cfg = p_eir_cfg; + + bta_sys_sendmsg(p_msg); + } +#endif +} + +/******************************************************************************* +** +** Function BTA_CheckEirData +** +** Description This function is called to get EIR data from significant part. +** +** Parameters p_eir - pointer of EIR significant part +** type - finding EIR data type +** p_length - return the length of EIR data +** +** Returns pointer of EIR data +** +*******************************************************************************/ +UINT8 *BTA_CheckEirData( UINT8 *p_eir, UINT8 type, UINT8 *p_length ) +{ +#if ( BTM_EIR_CLIENT_INCLUDED == TRUE ) + return BTM_CheckEirData( p_eir, type, p_length ); +#else + return NULL; +#endif +} + +/******************************************************************************* +** +** Function BTA_GetEirService +** +** Description This function is called to get BTA service mask from EIR. +** +** Parameters p_eir - pointer of EIR significant part +** p_services - return the BTA service mask +** +** Returns None +** +*******************************************************************************/ +extern const UINT16 bta_service_id_to_uuid_lkup_tbl []; +void BTA_GetEirService( UINT8 *p_eir, tBTA_SERVICE_MASK *p_services ) +{ +#if ( BTM_EIR_CLIENT_INCLUDED == TRUE ) + UINT8 xx, yy; + UINT8 num_uuid, max_num_uuid = 32; + UINT8 uuid_list[32*LEN_UUID_16]; + UINT16 *p_uuid16 = (UINT16 *)uuid_list; + tBTA_SERVICE_MASK mask; + + BTM_GetEirUuidList( p_eir, LEN_UUID_16, &num_uuid, uuid_list, max_num_uuid); + for( xx = 0; xx < num_uuid; xx++ ) + { + mask = 1; + for( yy = 0; yy < BTA_MAX_SERVICE_ID; yy++ ) + { + if( *(p_uuid16 + xx) == bta_service_id_to_uuid_lkup_tbl[yy] ) + { + *p_services |= mask; + break; + } + mask <<= 1; + } + + /* for HSP v1.2 only device */ + if (*(p_uuid16 + xx) == UUID_SERVCLASS_HEADSET_HS) + *p_services |= BTA_HSP_SERVICE_MASK; + + if (*(p_uuid16 + xx) == UUID_SERVCLASS_HDP_SOURCE) + *p_services |= BTA_HL_SERVICE_MASK; + + if (*(p_uuid16 + xx) == UUID_SERVCLASS_HDP_SINK) + *p_services |= BTA_HL_SERVICE_MASK; + } +#endif +} + +/******************************************************************************* +** +** Function BTA_DmUseSsr +** +** Description This function is called to check if the connected peer device +** supports SSR or not. +** +** Returns TRUE, if SSR is supported +** +*******************************************************************************/ +BOOLEAN BTA_DmUseSsr( BD_ADDR bd_addr ) +{ + BOOLEAN use_ssr = FALSE; + tBTA_DM_PEER_DEVICE * p_dev = bta_dm_find_peer_device(bd_addr); + if(p_dev && (p_dev->info & BTA_DM_DI_USE_SSR) ) + use_ssr = TRUE; + return use_ssr; +} + +/******************************************************************************* +** Device Identification (DI) Server Functions +*******************************************************************************/ +/******************************************************************************* +** +** Function BTA_DmSetLocalDiRecord +** +** Description This function adds a DI record to the local SDP database. +** +** Returns BTA_SUCCESS if record set sucessfully, otherwise error code. +** +*******************************************************************************/ +tBTA_STATUS BTA_DmSetLocalDiRecord( tBTA_DI_RECORD *p_device_info, + UINT32 *p_handle ) +{ + tBTA_STATUS status = BTA_FAILURE; + + if(bta_dm_di_cb.di_num < BTA_DI_NUM_MAX) + { + if(SDP_SetLocalDiRecord((tSDP_DI_RECORD *)p_device_info, p_handle) == SDP_SUCCESS) + { + if(!p_device_info->primary_record) + { + bta_dm_di_cb.di_handle[bta_dm_di_cb.di_num] = *p_handle; + bta_dm_di_cb.di_num ++; + } + + bta_sys_add_uuid(UUID_SERVCLASS_PNP_INFORMATION); + status = BTA_SUCCESS; + } + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_DmGetLocalDiRecord +** +** Description Get a specified DI record to the local SDP database. If no +** record handle is provided, the primary DI record will be +** returned. +** +** Fills in the device information of the record +** p_handle - if p_handle == 0, the primary record is returned +** +** Returns BTA_SUCCESS if record set sucessfully, otherwise error code. +** +*******************************************************************************/ +tBTA_STATUS BTA_DmGetLocalDiRecord( tBTA_DI_GET_RECORD *p_device_info, + UINT32 *p_handle ) +{ + UINT16 status; + + status = SDP_GetLocalDiRecord(p_device_info, p_handle); + + if (status == SDP_SUCCESS) + return BTA_SUCCESS; + else + return BTA_FAILURE; + +} + +/******************************************************************************* +** Device Identification (DI) Client Functions +*******************************************************************************/ +/******************************************************************************* +** +** Function BTA_DmDiDiscover +** +** Description This function queries a remote device for DI information. +** +** +** Returns None. +** +*******************************************************************************/ +void BTA_DmDiDiscover( BD_ADDR remote_device, tBTA_DISCOVERY_DB *p_db, + UINT32 len, tBTA_DM_SEARCH_CBACK *p_cback ) +{ + tBTA_DM_API_DI_DISC *p_msg; + + if ((p_msg = (tBTA_DM_API_DI_DISC *) GKI_getbuf(sizeof(tBTA_DM_API_DI_DISC))) != NULL) + { + bdcpy(p_msg->bd_addr, remote_device); + p_msg->hdr.event = BTA_DM_API_DI_DISCOVER_EVT; + p_msg->p_sdp_db = p_db; + p_msg->len = len; + p_msg->p_cback = p_cback; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmGetDiRecord +** +** Description This function retrieves a remote device's DI record from +** the specified database. +** +** Returns BTA_SUCCESS if Get DI record is succeed. +** BTA_FAILURE if Get DI record failed. +** +*******************************************************************************/ +tBTA_STATUS BTA_DmGetDiRecord( UINT8 get_record_index, tBTA_DI_GET_RECORD *p_device_info, + tBTA_DISCOVERY_DB *p_db ) +{ + if (SDP_GetDiRecord(get_record_index, p_device_info, p_db) != SDP_SUCCESS) + return BTA_FAILURE; + else + return BTA_SUCCESS; +} + +/******************************************************************************* +** +** Function BTA_SysFeatures +** +** Description This function is called to set system features. +** +** Returns void +** +*******************************************************************************/ +void BTA_SysFeatures (UINT16 sys_features) +{ + bta_sys_cb.sys_features = sys_features; + + APPL_TRACE_API1("BTA_SysFeatures: sys_features = %d", sys_features); +} + +/******************************************************************************* +** +** Function bta_dmexecutecallback +** +** Description This function will request BTA to execute a call back in the context of BTU task +** This API was named in lower case because it is only intended +** for the internal customers(like BTIF). +** +** Returns void +** +*******************************************************************************/ +void bta_dmexecutecallback (tBTA_DM_EXEC_CBACK* p_callback, void * p_param) +{ + tBTA_DM_API_EXECUTE_CBACK *p_msg; + + if ((p_msg = (tBTA_DM_API_EXECUTE_CBACK *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) + { + p_msg->hdr.event = BTA_DM_API_EXECUTE_CBACK_EVT; + p_msg->p_param= p_param; + p_msg->p_exec_cback= p_callback; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function BTA_DmAddBleKey +** +** Description Add/modify LE device information. This function will be +** normally called during host startup to restore all required +** information stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** p_le_key - LE key values. +** key_type - LE SMP key type. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmAddBleKey (BD_ADDR bd_addr, tBTA_LE_KEY_VALUE *p_le_key, tBTA_LE_KEY_TYPE key_type) +{ +#if BLE_INCLUDED == TRUE + + tBTA_DM_API_ADD_BLEKEY *p_msg; + + if ((p_msg = (tBTA_DM_API_ADD_BLEKEY *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_BLEKEY))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_BLEKEY)); + + p_msg->hdr.event = BTA_DM_API_ADD_BLEKEY_EVT; + p_msg->key_type = key_type; + bdcpy(p_msg->bd_addr, bd_addr); + memcpy(&p_msg->blekey, p_le_key, sizeof(tBTA_LE_KEY_VALUE)); + + bta_sys_sendmsg(p_msg); + } + +#endif +} + +/******************************************************************************* +** +** Function BTA_DmAddBleDevice +** +** Description Add a BLE device. This function will be normally called +** during host startup to restore all required information +** for a LE device stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** dev_type - Remote device's device type. +** addr_type - LE device address type. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBT_DEVICE_TYPE dev_type) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_ADD_BLE_DEVICE *p_msg; + + if ((p_msg = (tBTA_DM_API_ADD_BLE_DEVICE *) GKI_getbuf(sizeof(tBTA_DM_API_ADD_BLE_DEVICE))) != NULL) + { + memset (p_msg, 0, sizeof(tBTA_DM_API_ADD_BLE_DEVICE)); + + p_msg->hdr.event = BTA_DM_API_ADD_BLEDEVICE_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->addr_type = addr_type; + p_msg->dev_type = dev_type; + + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** +** Function BTA_DmBlePasskeyReply +** +** Description Send BLE SMP passkey reply. +** +** Parameters: bd_addr - BD address of the peer +** accept - passkey entry sucessful or declined. +** passkey - passkey value, must be a 6 digit number, +** can be lead by 0. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, BOOLEAN accept, UINT32 passkey) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_PASSKEY_REPLY *p_msg; + + if ((p_msg = (tBTA_DM_API_PASSKEY_REPLY *) GKI_getbuf(sizeof(tBTA_DM_API_PASSKEY_REPLY))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_PASSKEY_REPLY)); + + p_msg->hdr.event = BTA_DM_API_BLE_PASSKEY_REPLY_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + + if(accept) + { + p_msg->passkey = passkey; + } + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** +** Function BTA_DmBleSecurityGrant +** +** Description Grant security request access. +** +** Parameters: bd_addr - BD address of the peer +** res - security grant status. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_BLE_SEC_GRANT *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_SEC_GRANT *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SEC_GRANT))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SEC_GRANT)); + + p_msg->hdr.event = BTA_DM_API_BLE_SEC_GRANT_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->res = res; + + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** +** Function BTA_DmSetBlePrefConnParams +** +** Description This function is called to set the preferred connection +** parameters when default connection parameter is not desired. +** +** Parameters: bd_addr - BD address of the peripheral +** scan_interval - scan interval +** scan_window - scan window +** min_conn_int - minimum preferred connection interval +** max_conn_int - maximum preferred connection interval +** slave_latency - preferred slave latency +** supervision_tout - preferred supervision timeout +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetBlePrefConnParams(BD_ADDR bd_addr, + UINT16 min_conn_int, UINT16 max_conn_int, + UINT16 slave_latency, UINT16 supervision_tout ) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_BLE_CONN_PARAMS *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_CONN_PARAMS *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_CONN_PARAMS))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_CONN_PARAMS)); + + p_msg->hdr.event = BTA_DM_API_BLE_CONN_PARAM_EVT; + + memcpy(p_msg->peer_bda, bd_addr, BD_ADDR_LEN); + + p_msg->conn_int_max = max_conn_int; + p_msg->conn_int_min = min_conn_int; + p_msg->slave_latency = slave_latency; + p_msg->supervision_tout = supervision_tout; + + bta_sys_sendmsg(p_msg); + } +#endif +} + +/******************************************************************************* +** +** Function BTA_DmSetBleConnScanParams +** +** Description This function is called to set scan parameters used in +** BLE connection request +** +** Parameters: scan_interval - scan interval +** scan_window - scan window +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetBleConnScanParams(UINT16 scan_interval, UINT16 scan_window ) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_BLE_SCAN_PARAMS *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_SCAN_PARAMS *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SCAN_PARAMS))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SCAN_PARAMS)); + + p_msg->hdr.event = BTA_DM_API_BLE_SCAN_PARAM_EVT; + + p_msg->scan_int = scan_interval; + p_msg->scan_window = scan_window; + + bta_sys_sendmsg(p_msg); + } +#endif +} + +/******************************************************************************* +** +** Function BTA_DmBleSetBgConnType +** +** Description This function is called to set BLE connectable mode for a +** peripheral device. +** +** Parameters bg_conn_type: it can be auto connection, or selective connection. +** p_select_cback: callback function when selective connection procedure +** is being used. +** +** Returns void +** +*******************************************************************************/ +void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback) +{ +#if BLE_INCLUDED == TRUE + tBTA_DM_API_BLE_SET_BG_CONN_TYPE *p_msg; + + if ((p_msg = (tBTA_DM_API_BLE_SET_BG_CONN_TYPE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE)); + + p_msg->hdr.event = BTA_DM_API_BLE_SET_BG_CONN_TYPE; + p_msg->bg_conn_type = bg_conn_type; + p_msg->p_select_cback = p_select_cback; + + bta_sys_sendmsg(p_msg); + } +#endif +} +/******************************************************************************* +** +** Function BTA_DmDiscoverExt +** +** Description This function does service discovery for services of a +** peer device. When services.num_uuid is 0, it indicates all +** GATT based services are to be searched; other wise a list of +** UUID of interested services should be provided through +** p_services->p_uuid. +** +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search) +{ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + tBTA_DM_API_DISCOVER *p_msg; + UINT16 len = p_services ? (sizeof(tBTA_DM_API_DISCOVER) + sizeof(tBT_UUID) * p_services->num_uuid) : + sizeof(tBTA_DM_API_DISCOVER); + + if ((p_msg = (tBTA_DM_API_DISCOVER *) GKI_getbuf(len)) != NULL) + { + memset(p_msg, 0, len); + + p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->p_cback = p_cback; + p_msg->sdp_search = sdp_search; + + if (p_services != NULL) + { + p_msg->services = p_services->srvc_mask; + p_msg->num_uuid = p_services->num_uuid; + + if (p_services->num_uuid != 0) + { + p_msg->p_uuid = (tBT_UUID *)(p_msg + 1); + memcpy(p_msg->p_uuid, p_services->p_uuid, sizeof(tBT_UUID) * p_services->num_uuid); + } + } + + bta_sys_sendmsg(p_msg); + } +#endif + +} + +/******************************************************************************* +** +** Function BTA_DmSearchExt +** +** Description This function searches for peer Bluetooth devices. It performs +** an inquiry and gets the remote name for devices. Service +** discovery is done if services is non zero +** +** Parameters p_dm_inq: inquiry conditions +** p_services: if service is not empty, service discovery will be done. +** for all GATT based service condition, put num_uuid, and +** p_uuid is the pointer to the list of UUID values. +** p_cback: callback functino when search is completed. +** +** +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSearchExt(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK_EXT *p_services, tBTA_DM_SEARCH_CBACK *p_cback) +{ +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + tBTA_DM_API_SEARCH *p_msg; + UINT16 len = p_services ? (sizeof(tBTA_DM_API_SEARCH) + sizeof(tBT_UUID) * p_services->num_uuid) : + sizeof(tBTA_DM_API_SEARCH); + + if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(len)) != NULL) + { + memset(p_msg, 0, len); + + p_msg->hdr.event = BTA_DM_API_SEARCH_EVT; + memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ)); + p_msg->p_cback = p_cback; + p_msg->rs_res = BTA_DM_RS_NONE; + + + if (p_services != NULL) + { + p_msg->services = p_services->srvc_mask; + p_msg->num_uuid = p_services->num_uuid; + + if (p_services->num_uuid != 0) + { + p_msg->p_uuid = (tBT_UUID *)(p_msg + 1); + memcpy(p_msg->p_uuid, p_services->p_uuid, sizeof(tBT_UUID) * p_services->num_uuid); + } + else + p_msg->p_uuid = NULL; + } + + bta_sys_sendmsg(p_msg); + } +#endif +} + + +/******************************************************************************* +** +** Function BTA_DmSetEncryption +** +** Description This function is called to ensure that connection is +** encrypted. Should be called only on an open connection. +** Typically only needed for connections that first want to +** bring up unencrypted links, then later encrypt them. +** +** Parameters: bd_addr - Address of the peer device +** p_callback - Pointer to callback function to indicat the +** link encryption status +** sec_act - This is the security action to indicate +** what knid of BLE security level is required for +** the BLE link if the BLE is supported +** Note: This parameter is ignored for the BR/EDR link +** or the BLE is not supported +** +** Returns void +** +*******************************************************************************/ +void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_DM_ENCRYPT_CBACK *p_callback, + tBTA_DM_BLE_SEC_ACT sec_act) +{ + tBTA_DM_API_SET_ENCRYPTION *p_msg; + + APPL_TRACE_API0("BTA_DmSetEncryption"); //todo + if ((p_msg = (tBTA_DM_API_SET_ENCRYPTION *) GKI_getbuf(sizeof(tBTA_DM_API_SET_ENCRYPTION))) != NULL) + { + memset(p_msg, 0, sizeof(tBTA_DM_API_SET_ENCRYPTION)); + + p_msg->hdr.event = BTA_DM_API_SET_ENCRYPTION_EVT; + + memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN); + p_msg->p_callback = p_callback; + p_msg->sec_act = sec_act; + + bta_sys_sendmsg(p_msg); + } +} + diff --git a/bta/dm/bta_dm_cfg.c b/bta/dm/bta_dm_cfg.c new file mode 100644 index 0000000..5e26909 --- /dev/null +++ b/bta/dm/bta_dm_cfg.c @@ -0,0 +1,424 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains compile-time configurable constants for the device + * manager. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" + +#ifndef BTA_DM_LINK_POLICY_SETTINGS +#define BTA_DM_LINK_POLICY_SETTINGS (HCI_ENABLE_MASTER_SLAVE_SWITCH | HCI_ENABLE_HOLD_MODE | HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE) +#endif + +/* page timeout in 625uS */ +#ifndef BTA_DM_PAGE_TIMEOUT +#define BTA_DM_PAGE_TIMEOUT 8192 +#endif + +/* link supervision timeout in 625uS (5 secs) */ +#ifndef BTA_DM_LINK_TIMEOUT +#define BTA_DM_LINK_TIMEOUT 8000 +#endif + +/* For Insight, PM cfg lookup tables are runtime configurable (to allow tweaking of params for power consumption measurements) */ +#ifndef BTE_SIM_APP +#define tBTA_DM_PM_TYPE_QUALIFIER const +#else +#define tBTA_DM_PM_TYPE_QUALIFIER +#endif + + +const tBTA_DM_CFG bta_dm_cfg = +{ + /* mobile phone COD */ + BTA_DM_COD, + /* link policy settings */ + BTA_DM_LINK_POLICY_SETTINGS, + /* page timeout in 625uS */ + BTA_DM_PAGE_TIMEOUT, + /* link supervision timeout in 625uS*/ + BTA_DM_LINK_TIMEOUT, + /* TRUE to avoid scatternet when av is streaming (be the master) */ + TRUE +}; + +#ifndef BTA_DM_SCATTERNET +/* By default, allow partial scatternet */ +#define BTA_DM_SCATTERNET BTA_DM_PARTIAL_SCATTERNET +#endif + +#ifndef BTA_HH_ROLE +/* By default, do not specify HH role (backward compatibility) */ +#define BTA_HH_ROLE BTA_ANY_ROLE +#endif + +#ifndef BTA_AV_ROLE +/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */ +#define BTA_AV_ROLE BTA_MASTER_ROLE_PREF +#endif + +#define BTA_DM_NUM_RM_ENTRY 4 + +/* appids for PAN used by insight sample application + these have to be same as defined in btui_int.h */ +#define BTUI_PAN_ID_PANU 0 +#define BTUI_PAN_ID_NAP 1 +#define BTUI_PAN_ID_GN 2 + +/* First element is always for SYS: + app_id = # of entries table, cfg is + device scatternet support */ +const tBTA_DM_RM bta_dm_rm_cfg[] = +{ + {BTA_ID_SYS, BTA_DM_NUM_RM_ENTRY, BTA_DM_SCATTERNET}, + {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_MASTER_ROLE_ONLY}, + {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_MASTER_ROLE_ONLY}, + {BTA_ID_HH, BTA_ALL_APP_ID, BTA_HH_ROLE}, + {BTA_ID_AV, BTA_ALL_APP_ID, BTA_AV_ROLE} +}; + + +tBTA_DM_CFG *p_bta_dm_cfg = (tBTA_DM_CFG *)&bta_dm_cfg; + +tBTA_DM_RM *p_bta_dm_rm_cfg = (tBTA_DM_RM *)&bta_dm_rm_cfg; + + +#define BTA_DM_NUM_PM_ENTRY (15+BTA_DM_NUM_JV_ID) /* number of entries in bta_dm_pm_cfg except the first */ + +tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[] = +{ + {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY, 0}, + {BTA_ID_AG, BTA_ALL_APP_ID, 0}, /* ag uses first spec table for app id 0 */ + {BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */ + {BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */ + {BTA_ID_DG, BTA_ALL_APP_ID, 2}, /* dg spec table */ + {BTA_ID_AV, BTA_ALL_APP_ID, 4}, /* av spec table */ + {BTA_ID_FTC, BTA_ALL_APP_ID, 6}, /* ftc spec table */ + {BTA_ID_FTS, BTA_ALL_APP_ID, 7}, /* fts spec table */ + {BTA_ID_HD, BTA_ALL_APP_ID, 3}, /* hd spec table */ + {BTA_ID_HH, BTA_ALL_APP_ID, 5}, /* hh spec table */ + {BTA_ID_PBC, BTA_ALL_APP_ID, 2}, /* reuse dg spec table */ + {BTA_ID_PBS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + {BTA_ID_OPC, BTA_ALL_APP_ID, 6}, /* reuse ftc spec table */ + {BTA_ID_OPS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + {BTA_ID_MSE, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + {BTA_ID_JV1, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + {BTA_ID_JV2, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */ + {BTA_ID_HL, BTA_ALL_APP_ID, 8} /* reuse fts spec table */ +}; + + +#ifdef BTE_SIM_APP /* For Insight builds only, see the detail below */ +#define BTA_DM_NUM_PM_SPEC (9 + 2) /* additional two */ +#else +#define BTA_DM_NUM_PM_SPEC 9 /* additional JV*/ +#endif + +tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = +{ + /* AG */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_SNIFF3, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ + {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* CT */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open park */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */ + {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close park */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* DG */ + { + (BTA_DM_PM_ACTIVE), /* no power saving mode allowed */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* HD */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR3), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF4, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF2, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF4, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* AV */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* HH */ + { + (BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR1), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */ + {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF2, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* FTC, OPC */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* FTS, OPS */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ + {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + }, + + /* HL */ + { + (BTA_DM_PM_SNIFF), /* allow sniff */ +#if (BTM_SSR_INCLUDED == TRUE) + (BTA_DM_PM_SSR2), /* the SSR entry */ +#endif + { + {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + } + } + +#ifdef BTE_SIM_APP /* For Insight builds only */ + /* Entries at the end of the pm_spec table are user-defined (runtime configurable), + for power consumption experiments. + Insight finds the first user-defined entry by looking for the first BTA_DM_PM_NO_PREF. + The number of user_defined specs is defined by BTA_SWRAP_UD_PM_SPEC_COUNT */ + , + {BTA_DM_PM_NO_PREF}, /* pm_spec USER_DEFINED_0 */ + {BTA_DM_PM_NO_PREF} /* pm_spec USER_DEFINED_1 */ +#endif /* BTE_SIM_APP */ +}; + +tBTA_DM_PM_TYPE_QUALIFIER tBTM_PM_PWR_MD bta_dm_pm_md[] = +{ +/* more sniff parameter entries can be added for BTA_DM_PM_SNIFF3 - BTA_DM_PM_SNIFF7, if needed +When entries are added or removed, BTA_DM_PM_PARK_IDX needs to be updated to reflect the actual index +BTA_DM_PM_PARK_IDX is defined in bta_api.h and can be override by the bdroid_buildcfg.h settings. +The SNIFF table entries must be in the order from highest latency (biggest interval) to lowest latency. +If there's a conflict among the connected services, the setting with lowest latency wins. +*/ +/* sniff modes: max interval, min interval, attempt, timeout */ + {800, 400, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF - A2DP */ + {400, 200, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF1 */ + {180, 150, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF2- HD idle */ + {150, 50, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF3- SCO open */ + { 54, 30, 4, 1, BTM_PM_MD_SNIFF}, /*for BTA_DM_PM_SNIFF4- HD active*/ + {800, 400, 0, 0, BTM_PM_MD_PARK} + +#ifdef BTE_SIM_APP /* For Insight builds only */ + /* Entries at the end of the bta_dm_pm_md table are user-defined (runtime configurable), + for power consumption experiments. + Insight finds the first user-defined entry by looking for the first 'max=0'. + The number of user_defined specs is defined by BTA_SWRAP_UD_PM_DM_COUNT */ + , + {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_0 */ + {0}, /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_0 */ + + {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_1 */ + {0} /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_1 */ +#endif /* BTE_SIM_APP */ +}; + +/* 0=max_lat -> no SSR */ +/* the smaller of the SSR max latency wins. + * the entries in this table must be from highest latency (biggest interval) to lowest latency */ +#if (BTM_SSR_INCLUDED == TRUE) +tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = +{ + /*max_lat, min_rmt_to, min_loc_to*/ + {0, 0, 0}, /* BTA_DM_PM_SSR0 - do not use SSR */ + {1600, 2, 2}, /* BTA_DM_PM_SSR1 - HH */ + {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/ + {360, 160, 2} /* BTA_DM_PM_SSR3 - HD */ +}; + +tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC *)&bta_dm_ssr_spec; +#endif + +tBTA_DM_PM_CFG *p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG *)&bta_dm_pm_cfg; +tBTA_DM_PM_SPEC *p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC *)&bta_dm_pm_spec; +tBTM_PM_PWR_MD *p_bta_dm_pm_md = (tBTM_PM_PWR_MD *)&bta_dm_pm_md; + +/* The performance impact of EIR packet size +** +** When BTM_EIR_DEFAULT_FEC_REQUIRED is TRUE, +** 1 to 17 bytes, DM1 is used and most robust. +** 18 to 121 bytes, DM3 is used but impacts inquiry scan time with large number +** of devices.(almost double with 150 users) +** 122 to 224 bytes, DM5 is used but cause quite big performance loss even with +** small number of users. so it is not recommended. +** 225 to 240 bytes, DH5 is used without FEC but it not recommended. +** (same reason of DM5) +** +** When BTM_EIR_DEFAULT_FEC_REQUIRED is FALSE, +** 1 to 27 bytes, DH1 is used but only robust at short range. +** 28 to 183 bytes, DH3 is used but only robust at short range and impacts inquiry +** scan time with large number of devices. +** 184 to 240 bytes, DH5 is used but it not recommended. +*/ + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE ) +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + /* for example */ +const UINT8 bta_dm_eir_uuid16_list[] = { 0x08, 0x11, /* Headset */ + 0x1E, 0x11, /* Handsfree */ + 0x0E, 0x11, /* AV Remote Control */ + 0x0B, 0x11, /* Audio Sink */ +}; +#endif + +/* Extended Inquiry Response */ +const tBTA_DM_EIR_CONF bta_dm_eir_cfg = +{ + 50, /* minimum length of local name when it is shortened */ + /* if length of local name is longer than this and EIR has not enough */ + /* room for all UUID list then local name is shortened to this length */ +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + 8, + (UINT8 *)bta_dm_eir_uuid16_list, +#else + { /* mask of UUID list in EIR */ + 0xFFFFFFFF, /* LSB is the first UUID of the first 32 UUIDs in BTM_EIR_UUID_LKUP_TBL */ + 0xFFFFFFFF /* LSB is the first UUID of the next 32 UUIDs in BTM_EIR_UUID_LKUP_TBL */ + /* BTM_EIR_UUID_LKUP_TBL can be overrided */ + }, +#endif + NULL, /* Inquiry TX power */ + 0, /* length of flags in bytes */ + NULL, /* flags for EIR */ + 0, /* length of manufacturer specific in bytes */ + NULL, /* manufacturer specific */ +}; +tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF*)&bta_dm_eir_cfg; +#endif diff --git a/bta/dm/bta_dm_ci.c b/bta/dm/bta_dm_ci.c new file mode 100644 index 0000000..5e2e312 --- /dev/null +++ b/bta/dm/bta_dm_ci.c @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 API implementation file for the BTA device manager. + * + ******************************************************************************/ + +#include "gki.h" +#include "bd.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +#include <string.h> +#include "bta_dm_ci.h" + + +#if (BTM_OOB_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_ci_io_req +** +** Description This function must be called in response to function +** bta_dm_co_io_req(), if *p_oob_data to BTA_OOB_UNKNOWN +** by bta_dm_co_io_req(). +** +** Returns void +** +*******************************************************************************/ +void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, tBTA_OOB_DATA oob_data, + tBTA_AUTH_REQ auth_req) + +{ + tBTA_DM_CI_IO_REQ *p_msg; + + if ((p_msg = (tBTA_DM_CI_IO_REQ *) GKI_getbuf(sizeof(tBTA_DM_CI_IO_REQ))) != NULL) + { + p_msg->hdr.event = BTA_DM_CI_IO_REQ_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->io_cap = io_cap; + p_msg->oob_data = oob_data; + p_msg->auth_req = auth_req; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_dm_ci_rmt_oob +** +** Description This function must be called in response to function +** bta_dm_co_rmt_oob() to provide the OOB data associated +** with the remote device. +** +** Returns void +** +*******************************************************************************/ +void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr, BT_OCTET16 c, BT_OCTET16 r) +{ + tBTA_DM_CI_RMT_OOB *p_msg; + + if ((p_msg = (tBTA_DM_CI_RMT_OOB *) GKI_getbuf(sizeof(tBTA_DM_CI_RMT_OOB))) != NULL) + { + p_msg->hdr.event = BTA_DM_CI_RMT_OOB_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->accept = accept; + memcpy(p_msg->c, c, BT_OCTET16_LEN); + memcpy(p_msg->r, r, BT_OCTET16_LEN); + bta_sys_sendmsg(p_msg); + } +} +#endif /* BTM_OOB_INCLUDED */ + +#if (BTM_SCO_HCI_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_dm_sco_ci_data_ready +** +** Description This function sends an event to indicating that the phone +** has SCO data ready. +** +** Parameters event: is obtained from bta_dm_sco_co_open() function, which +** is the BTA event we want to send back to BTA module +** when there is encoded data ready. +** sco_handle: is the BTA sco handle which indicate a specific +** SCO connection. +** Returns void +** +*******************************************************************************/ +void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = event; + p_buf->layer_specific = sco_handle; + + bta_sys_sendmsg(p_buf); + } +} +#endif diff --git a/bta/dm/bta_dm_int.h b/bta/dm/bta_dm_int.h new file mode 100644 index 0000000..35b369d --- /dev/null +++ b/bta/dm/bta_dm_int.h @@ -0,0 +1,989 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 private interface file for the BTA device manager. + * + ******************************************************************************/ +#ifndef BTA_DM_INT_H +#define BTA_DM_INT_H + +#include "bt_target.h" + +#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + #include "bta_gatt_api.h" +#endif + + + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + + +#define BTA_COPY_DEVICE_CLASS(coddst, codsrc) {((UINT8 *)(coddst))[0] = ((UINT8 *)(codsrc))[0]; \ + ((UINT8 *)(coddst))[1] = ((UINT8 *)(codsrc))[1]; \ + ((UINT8 *)(coddst))[2] = ((UINT8 *)(codsrc))[2];} + + +#define BTA_DM_MSG_LEN 50 + +#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id)) + +/* DM events */ +enum +{ + /* device manager local device API events */ + BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM), + BTA_DM_API_DISABLE_EVT, + BTA_DM_API_SET_NAME_EVT, + BTA_DM_API_SET_VISIBILITY_EVT, + BTA_DM_API_SET_AFH_CHANNELS_EVT, + BTA_API_DM_SIG_STRENGTH_EVT, + BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT, + BTA_DM_API_TX_INQPWR_EVT, + BTA_DM_ACL_CHANGE_EVT, + BTA_DM_API_ADD_DEVICE_EVT, + + /* security API events */ + BTA_DM_API_BOND_EVT, + BTA_DM_API_BOND_CANCEL_EVT, + BTA_DM_API_PIN_REPLY_EVT, + BTA_DM_API_LINK_POLICY_EVT, + BTA_DM_API_AUTH_REPLY_EVT, + + /* power manger events */ + BTA_DM_PM_BTM_STATUS_EVT, + BTA_DM_PM_TIMER_EVT, + + /* simple pairing events */ + BTA_DM_API_CONFIRM_EVT, + + BTA_DM_API_SET_ENCRYPTION_EVT, + +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + BTA_DM_API_PASKY_CANCEL_EVT, +#endif +#if (BTM_OOB_INCLUDED == TRUE) + BTA_DM_API_LOC_OOB_EVT, + BTA_DM_CI_IO_REQ_EVT, + BTA_DM_CI_RMT_OOB_EVT, +#endif /* BTM_OOB_INCLUDED */ + + BTA_DM_API_REMOVE_DEVICE_EVT, + +#if BLE_INCLUDED == TRUE + BTA_DM_API_ADD_BLEKEY_EVT, + BTA_DM_API_ADD_BLEDEVICE_EVT, + BTA_DM_API_BLE_PASSKEY_REPLY_EVT, + BTA_DM_API_BLE_SEC_GRANT_EVT, + BTA_DM_API_BLE_SET_BG_CONN_TYPE, + BTA_DM_API_BLE_CONN_PARAM_EVT, + BTA_DM_API_BLE_SCAN_PARAM_EVT, +#endif + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + BTA_DM_API_UPDATE_EIR_UUID_EVT, +#endif +#if (BTM_EIR_SERVER_INCLUDED == TRUE) + BTA_DM_API_SET_EIR_CONFIG_EVT, +#endif + + BTA_DM_API_ENABLE_TEST_MODE_EVT, + BTA_DM_API_DISABLE_TEST_MODE_EVT, + BTA_DM_API_EXECUTE_CBACK_EVT, + BTA_DM_API_SET_AFH_CHANNEL_ASSESMENT_EVT, + BTA_DM_MAX_EVT +}; + + +/* DM search events */ +enum +{ + /* DM search API events */ + BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH), + BTA_DM_API_SEARCH_CANCEL_EVT, + BTA_DM_API_DISCOVER_EVT, + BTA_DM_INQUIRY_CMPL_EVT, + BTA_DM_REMT_NAME_EVT, + BTA_DM_SDP_RESULT_EVT, + BTA_DM_SEARCH_CMPL_EVT, + BTA_DM_DISCOVERY_RESULT_EVT, + BTA_DM_API_DI_DISCOVER_EVT + +}; + +/* data type for BTA_DM_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_SEC_CBACK *p_sec_cback; +} tBTA_DM_API_ENABLE; + +/* data type for BTA_DM_API_SET_NAME_EVT */ +typedef struct +{ + BT_HDR hdr; + char name[BD_NAME_LEN]; +} tBTA_DM_API_SET_NAME; + +/* data type for BTA_DM_API_SET_VISIBILITY_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_DISC disc_mode; + tBTA_DM_CONN conn_mode; + UINT8 pair_mode; + UINT8 conn_paired_only; +} tBTA_DM_API_SET_VISIBILITY; + +/* data type for BTA_DM_API_SET_AFH_CHANNELS_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 first; + UINT8 last; +} tBTA_DM_API_SET_AFH_CHANNELS_EVT; + +/* data type for BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 opcode; + UINT8 param_len; + UINT8 *p_param_buf; + tBTA_VENDOR_CMPL_CBACK *p_cback; + +} tBTA_DM_API_VENDOR_SPECIFIC_COMMAND; + +enum +{ + BTA_DM_RS_NONE, /* straight API call */ + BTA_DM_RS_OK, /* the role switch result - successful */ + BTA_DM_RS_FAIL /* the role switch result - failed */ +}; +typedef UINT8 tBTA_DM_RS_RES; + +/* data type for BTA_DM_API_SEARCH_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_INQ inq_params; + tBTA_SERVICE_MASK services; + tBTA_DM_SEARCH_CBACK * p_cback; + tBTA_DM_RS_RES rs_res; +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + UINT8 num_uuid; + tBT_UUID *p_uuid; +#endif +} tBTA_DM_API_SEARCH; + +/* data type for BTA_DM_API_DISCOVER_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_SERVICE_MASK services; + tBTA_DM_SEARCH_CBACK * p_cback; + BOOLEAN sdp_search; +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE + UINT8 num_uuid; + tBT_UUID *p_uuid; +#endif + tSDP_UUID uuid; +} tBTA_DM_API_DISCOVER; + +/* data type for BTA_DM_API_DI_DISC_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_DISCOVERY_DB *p_sdp_db; + UINT32 len; + tBTA_DM_SEARCH_CBACK * p_cback; +}tBTA_DM_API_DI_DISC; + +/* data type for BTA_DM_API_BOND_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_DM_API_BOND; + +/* data type for BTA_DM_API_BOND_CANCEL_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_DM_API_BOND_CANCEL; + +/* data type for BTA_DM_API_PIN_REPLY_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN accept; + UINT8 pin_len; + UINT8 p_pin[PIN_CODE_LEN]; +} tBTA_DM_API_PIN_REPLY; + +/* data type for BTA_DM_API_LINK_POLICY_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + UINT16 policy_mask; + BOOLEAN set; +} tBTA_DM_API_LINK_POLICY; + +/* data type for BTA_DM_API_AUTH_REPLY_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_SERVICE_ID service; + tBTA_AUTH_RESP response; +} tBTA_DM_API_AUTH_REPLY; + +/* data type for BTA_DM_API_LOC_OOB_EVT */ +typedef struct +{ + BT_HDR hdr; +} tBTA_DM_API_LOC_OOB; + +/* data type for BTA_DM_API_CONFIRM_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN accept; +} tBTA_DM_API_CONFIRM; + +/* data type for BTA_DM_API_PASKY_CANCEL_EVT*/ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_DM_API_PASKY_CANCEL; + +/* data type for BTA_DM_CI_IO_REQ_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_IO_CAP io_cap; + tBTA_OOB_DATA oob_data; + tBTA_AUTH_REQ auth_req; +} tBTA_DM_CI_IO_REQ; + +/* data type for BTA_DM_CI_RMT_OOB_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BT_OCTET16 c; + BT_OCTET16 r; + BOOLEAN accept; +} tBTA_DM_CI_RMT_OOB; + +/* data type for BTA_DM_REMT_NAME_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_SEARCH result; +} tBTA_DM_REM_NAME; + +/* data type for tBTA_DM_DISC_RESULT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_SEARCH result; +} tBTA_DM_DISC_RESULT; + + +/* data type for BTA_DM_INQUIRY_CMPL_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 num; +} tBTA_DM_INQUIRY_CMPL; + +/* data type for BTA_DM_SDP_RESULT_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 sdp_result; +} tBTA_DM_SDP_RESULT; + +/* data type for BTA_API_DM_SIG_STRENGTH_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_SIG_STRENGTH_MASK mask; + UINT16 period; + BOOLEAN start; +} tBTA_API_DM_SIG_STRENGTH; + +/* data type for tBTA_API_DM_TX_INQPWR */ +typedef struct +{ + BT_HDR hdr; + INT8 tx_power; +}tBTA_API_DM_TX_INQPWR; + +/* data type for BTA_DM_ACL_CHANGE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTM_BL_EVENT event; + UINT8 busy_level; + BOOLEAN is_new; + UINT8 new_role; + BD_ADDR bd_addr; + UINT8 hci_status; +} tBTA_DM_ACL_CHANGE; + +/* data type for BTA_DM_PM_BTM_STATUS_EVT */ +typedef struct +{ + + BT_HDR hdr; + BD_ADDR bd_addr; + tBTM_PM_STATUS status; + UINT16 value; + UINT8 hci_status; + +} tBTA_DM_PM_BTM_STATUS; + +/* data type for BTA_DM_PM_TIMER_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + +} tBTA_DM_PM_TIMER; + + +/* data type for BTA_DM_API_ADD_DEVICE_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + DEV_CLASS dc; + LINK_KEY link_key; + tBTA_SERVICE_MASK tm; + BOOLEAN is_trusted; + UINT8 key_type; + tBTA_IO_CAP io_cap; + BOOLEAN link_key_known; + BOOLEAN dc_known; + BD_NAME bd_name; + BD_FEATURES features; +} tBTA_DM_API_ADD_DEVICE; + +/* data type for BTA_DM_API_REMOVE_ACL_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_DM_API_REMOVE_DEVICE; + +/* data type for BTA_DM_API_EXECUTE_CBACK_EVT */ +typedef struct +{ + BT_HDR hdr; + void * p_param; + tBTA_DM_EXEC_CBACK *p_exec_cback; +} tBTA_DM_API_EXECUTE_CBACK; + +/* data type for tBTA_DM_API_SET_ENCRYPTION */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_ENCRYPT_CBACK *p_callback; + tBTA_DM_BLE_SEC_ACT sec_act; + BD_ADDR bd_addr; +} tBTA_DM_API_SET_ENCRYPTION; + +#if BLE_INCLUDED == TRUE +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_LE_KEY_VALUE blekey; + tBTA_LE_KEY_TYPE key_type; + +}tBTA_DM_API_ADD_BLEKEY; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBT_DEVICE_TYPE dev_type ; + tBLE_ADDR_TYPE addr_type; + +}tBTA_DM_API_ADD_BLE_DEVICE; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN accept; + UINT32 passkey; +}tBTA_DM_API_PASSKEY_REPLY; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + tBTA_DM_BLE_SEC_GRANT res; +}tBTA_DM_API_BLE_SEC_GRANT; + + +typedef struct +{ + BT_HDR hdr; + tBTA_DM_BLE_CONN_TYPE bg_conn_type; + tBTA_DM_BLE_SEL_CBACK *p_select_cback; +}tBTA_DM_API_BLE_SET_BG_CONN_TYPE; + +/* set prefered BLE connection parameters for a device */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR peer_bda; + UINT16 conn_int_min; + UINT16 conn_int_max; + UINT16 supervision_tout; + UINT16 slave_latency; + +}tBTA_DM_API_BLE_CONN_PARAMS; + +/* set scan parameter for BLE connections */ +typedef struct +{ + BT_HDR hdr; + UINT16 scan_int; + UINT16 scan_window; +}tBTA_DM_API_BLE_SCAN_PARAMS; + +#endif + +typedef struct +{ + BT_HDR hdr; + BOOLEAN enable_or_disable; +}tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT; + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) +/* data type for BTA_DM_API_UPDATE_EIR_UUID_EVT */ +typedef struct +{ + BT_HDR hdr; + BOOLEAN is_add; + tBT_UUID uuid; +}tBTA_DM_API_UPDATE_EIR_UUID; +#endif + +#if (BTM_EIR_SERVER_INCLUDED == TRUE) +/* data type for BTA_DM_API_SET_EIR_CONFIG_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_DM_EIR_CONF *p_eir_cfg; +}tBTA_DM_API_SET_EIR_CONFIG; +#endif + +/* union of all data types */ +typedef union +{ + /* GKI event buffer header */ + BT_HDR hdr; + tBTA_DM_API_ENABLE enable; + + tBTA_DM_API_SET_NAME set_name; + + tBTA_DM_API_SET_VISIBILITY set_visibility; + + tBTA_DM_API_SET_AFH_CHANNELS_EVT set_afhchannels; + + tBTA_DM_API_VENDOR_SPECIFIC_COMMAND vendor_command; + + tBTA_DM_API_ADD_DEVICE add_dev; + + tBTA_DM_API_REMOVE_DEVICE remove_dev; + + tBTA_DM_API_SEARCH search; + + tBTA_DM_API_DISCOVER discover; + + tBTA_DM_API_BOND bond; + + tBTA_DM_API_BOND_CANCEL bond_cancel; + + tBTA_DM_API_PIN_REPLY pin_reply; + tBTA_DM_API_LINK_POLICY link_policy; + + tBTA_DM_API_LOC_OOB loc_oob; + tBTA_DM_API_CONFIRM confirm; + tBTA_DM_API_PASKY_CANCEL passkey_cancel; + tBTA_DM_CI_IO_REQ ci_io_req; + tBTA_DM_CI_RMT_OOB ci_rmt_oob; + + tBTA_DM_API_AUTH_REPLY auth_reply; + + tBTA_DM_REM_NAME rem_name; + + tBTA_DM_DISC_RESULT disc_result; + + tBTA_DM_INQUIRY_CMPL inq_cmpl; + + tBTA_DM_SDP_RESULT sdp_event; + + tBTA_API_DM_SIG_STRENGTH sig_strength; + + tBTA_API_DM_TX_INQPWR tx_inq_pwr; + + tBTA_DM_ACL_CHANGE acl_change; + + tBTA_DM_PM_BTM_STATUS pm_status; + + tBTA_DM_PM_TIMER pm_timer; + + tBTA_DM_API_DI_DISC di_disc; + + tBTA_DM_API_EXECUTE_CBACK exec_cback; + + tBTA_DM_API_SET_ENCRYPTION set_encryption; + +#if BLE_INCLUDED == TRUE + tBTA_DM_API_ADD_BLEKEY add_ble_key; + tBTA_DM_API_ADD_BLE_DEVICE add_ble_device; + tBTA_DM_API_PASSKEY_REPLY ble_passkey_reply; + tBTA_DM_API_BLE_SEC_GRANT ble_sec_grant; + tBTA_DM_API_BLE_SET_BG_CONN_TYPE ble_set_bd_conn_type; + tBTA_DM_API_BLE_CONN_PARAMS ble_set_conn_params; + tBTA_DM_API_BLE_SCAN_PARAMS ble_set_scan_params; +#endif + + tBTA_DM_API_SET_AFH_CHANNEL_ASSESSMENT set_afh_channel_assessment; + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + tBTA_DM_API_UPDATE_EIR_UUID update_eir_uuid; +#endif +#if (BTM_EIR_SERVER_INCLUDED == TRUE) + tBTA_DM_API_SET_EIR_CONFIG set_eir_cfg; +#endif + +} tBTA_DM_MSG; + + +#define BTA_DM_NUM_PEER_DEVICE 7 + +#define BTA_DM_NOT_CONNECTED 0 +#define BTA_DM_CONNECTED 1 +#define BTA_DM_UNPAIRING 2 +typedef UINT8 tBTA_DM_CONN_STATE; + + +#define BTA_DM_DI_NONE 0x00 /* nothing special */ +#define BTA_DM_DI_USE_SSR 0x10 /* set this bit if ssr is supported for this link */ +#define BTA_DM_DI_AV_ACTIVE 0x20 /* set this bit if AV is active for this link */ +#define BTA_DM_DI_SET_SNIFF 0x01 /* set this bit if call BTM_SetPowerMode(sniff) */ +#define BTA_DM_DI_INT_SNIFF 0x02 /* set this bit if call BTM_SetPowerMode(sniff) & enter sniff mode */ +#define BTA_DM_DI_ACP_SNIFF 0x04 /* set this bit if peer init sniff */ +typedef UINT8 tBTA_DM_DEV_INFO; + +typedef struct +{ + BD_ADDR peer_bdaddr; + UINT16 link_policy; + tBTA_DM_CONN_STATE conn_state; + tBTA_PREF_ROLES pref_role; + BOOLEAN in_use; + tBTA_DM_DEV_INFO info; +#if (BTM_SSR_INCLUDED == TRUE) + tBTM_PM_STATUS prev_low; /* previous low power mode used */ +#endif + tBTA_DM_PM_ACTTION pm_mode_attempted; + tBTA_DM_PM_ACTTION pm_mode_failed; + +} tBTA_DM_PEER_DEVICE; + + + +/* structure to store list of + active connections */ +typedef struct +{ + tBTA_DM_PEER_DEVICE peer_device[BTA_DM_NUM_PEER_DEVICE]; + UINT8 count; + +} tBTA_DM_ACTIVE_LINK; + + +typedef struct +{ + BD_ADDR peer_bdaddr; + tBTA_SYS_ID id; + UINT8 app_id; + tBTA_SYS_CONN_STATUS state; + + +} tBTA_DM_SRVCS; + +#define BTA_DM_NUM_CONN_SRVS 5 + +typedef struct +{ + + UINT8 count; + tBTA_DM_SRVCS conn_srvc[BTA_DM_NUM_CONN_SRVS]; + +} tBTA_DM_CONNECTED_SRVCS; + +typedef struct +{ + TIMER_LIST_ENT timer; + BD_ADDR peer_bdaddr; + BOOLEAN in_use; + +} tBTA_PM_TIMER; + +extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; + +#define BTA_DM_NUM_PM_TIMER 3 + +/* DM control block */ +typedef struct +{ + BOOLEAN is_bta_dm_active; + tBTA_DM_ACTIVE_LINK device_list; + tBTA_DM_SEC_CBACK *p_sec_cback; + TIMER_LIST_ENT signal_strength_timer; + tBTA_SIG_STRENGTH_MASK signal_strength_mask; + UINT16 state; + UINT16 signal_strength_period; + BOOLEAN disabling; + TIMER_LIST_ENT disable_timer; + UINT32 wbt_sdp_handle; /* WIDCOMM Extensions SDP record handle */ + UINT8 wbt_scn; /* WIDCOMM Extensions SCN */ + UINT8 num_master_only; + UINT8 pm_id; + tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER]; + UINT32 role_policy_mask; /* the bits set indicates the modules that wants to remove role switch from the default link policy */ + UINT16 cur_policy; /* current default link policy */ + UINT16 rs_event; /* the event waiting for role switch */ + UINT8 cur_av_count; /* current AV connecions */ + BOOLEAN disable_pair_mode; /* disable pair mode or not */ + BOOLEAN conn_paired_only; /* allow connectable to paired device only or not */ + tBTA_DM_API_SEARCH search_msg; + UINT16 page_scan_interval; + UINT16 page_scan_window; + UINT16 inquiry_scan_interval; + UINT16 inquiry_scan_window; + + /* Storage for pin code request parameters */ + BD_ADDR pin_bd_addr; + DEV_CLASS pin_dev_class; + tBTA_DM_SEC_EVT pin_evt; + UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */ + BOOLEAN just_works; /* TRUE, if "Just Works" association model */ +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE ) + /* store UUID list for EIR */ + TIMER_LIST_ENT app_ready_timer; + UINT32 eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE]; +#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + tBT_UUID custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID]; +#endif + +#endif + + tBTA_DM_ENCRYPT_CBACK *p_encrypt_cback; + tBTA_DM_BLE_SEC_ACT sec_act; + TIMER_LIST_ENT switch_delay_timer; + +} tBTA_DM_CB; + +#ifndef BTA_DM_SDP_DB_SIZE +#define BTA_DM_SDP_DB_SIZE 250 +#endif + +/* DM search control block */ +typedef struct +{ + + tBTA_DM_SEARCH_CBACK * p_search_cback; + tBTM_INQ_INFO * p_btm_inq_info; + tBTA_SERVICE_MASK services; + tBTA_SERVICE_MASK services_to_search; + tBTA_SERVICE_MASK services_found; + tSDP_DISCOVERY_DB * p_sdp_db; + UINT16 state; + BD_ADDR peer_bdaddr; + BOOLEAN name_discover_done; + char peer_name[BD_NAME_LEN]; + TIMER_LIST_ENT search_timer; + UINT8 service_index; + tBTA_DM_MSG * p_search_queue; /* search or discover commands during search cancel stored here */ + BOOLEAN wait_disc; + BOOLEAN sdp_results; + tSDP_UUID uuid; + UINT8 peer_scn; + BOOLEAN sdp_search; + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +#if ((defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + tBTA_GATTC_IF client_if; + UINT8 num_uuid; + tBT_UUID *p_srvc_uuid; + UINT8 uuid_to_search; + BOOLEAN gatt_disc_active; + UINT16 conn_id; + UINT8 * p_ble_rawdata; + UINT32 ble_raw_size; + UINT32 ble_raw_used; +#endif +#endif + + +} tBTA_DM_SEARCH_CB; + +/* DI control block */ +typedef struct +{ + tSDP_DISCOVERY_DB * p_di_db; /* pointer to the DI discovery database */ + UINT8 di_num; /* total local DI record number */ + UINT32 di_handle[BTA_DI_NUM_MAX]; /* local DI record handle, the first one is primary record */ +}tBTA_DM_DI_CB; + +/* DM search state */ +enum +{ + + BTA_DM_SEARCH_IDLE, + BTA_DM_SEARCH_ACTIVE, + BTA_DM_SEARCH_CANCELLING, + BTA_DM_DISCOVER_ACTIVE + +}; + + + +typedef struct +{ + DEV_CLASS dev_class; /* local device class */ + UINT16 policy_settings; /* link policy setting hold, sniff, park, MS switch */ + UINT16 page_timeout; /* timeout for page in slots */ + UINT16 link_timeout; /* link supervision timeout in slots */ + BOOLEAN avoid_scatter; /* TRUE to avoid scatternet when av is streaming (be the master) */ + +} tBTA_DM_CFG; + +extern const UINT32 bta_service_id_to_btm_srv_id_lkup_tbl[]; + +extern const tBTA_DM_CFG bta_dm_cfg; + + + +#define BTA_ALL_APP_ID 0xff + +typedef struct +{ + UINT8 id; + UINT8 app_id; + UINT8 cfg; + +} tBTA_DM_RM ; + +extern tBTA_DM_CFG *p_bta_dm_cfg; +extern tBTA_DM_RM *p_bta_dm_rm_cfg; + +typedef struct +{ + + UINT8 id; + UINT8 app_id; + UINT8 spec_idx; /* index of spec table to use */ + +} tBTA_DM_PM_CFG; + + +typedef struct +{ + + tBTA_DM_PM_ACTTION power_mode; + UINT16 timeout; + +} tBTA_DM_PM_ACTN; + +typedef struct +{ + + UINT8 allow_mask; /* mask of sniff/hold/park modes to allow */ +#if (BTM_SSR_INCLUDED == TRUE) + UINT8 ssr; /* set SSR on conn open/unpark */ +#endif + tBTA_DM_PM_ACTN actn_tbl [BTA_DM_PM_NUM_EVTS][2]; + +} tBTA_DM_PM_SPEC; + +typedef struct +{ + UINT16 max_lat; + UINT16 min_rmt_to; + UINT16 min_loc_to; +} tBTA_DM_SSR_SPEC; + +typedef struct +{ + UINT16 manufacturer; + UINT16 lmp_sub_version; + UINT8 lmp_version; +}tBTA_DM_LMP_VER_INFO; + +extern tBTA_DM_PM_CFG *p_bta_dm_pm_cfg; +extern tBTA_DM_PM_SPEC *p_bta_dm_pm_spec; +extern tBTM_PM_PWR_MD *p_bta_dm_pm_md; +#if (BTM_SSR_INCLUDED == TRUE) +extern tBTA_DM_SSR_SPEC *p_bta_dm_ssr_spec; +#endif + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE ) +/* update dynamic BRCM Aware EIR data */ +extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg; +extern tBTA_DM_EIR_CONF *p_bta_dm_eir_cfg; +#endif + +/* DM control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_DM_CB bta_dm_cb; +#else +extern tBTA_DM_CB *bta_dm_cb_ptr; +#define bta_dm_cb (*bta_dm_cb_ptr) +#endif + +/* DM search control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_DM_SEARCH_CB bta_dm_search_cb; +#else +extern tBTA_DM_SEARCH_CB *bta_dm_search_cb_ptr; +#define bta_dm_search_cb (*bta_dm_search_cb_ptr) +#endif + +/* DI control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_DM_DI_CB bta_dm_di_cb; +#else +extern tBTA_DM_DI_CB *bta_dm_di_cb_ptr; +#define bta_dm_di_cb (*bta_dm_di_cb_ptr) +#endif + +extern BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg); +extern void bta_dm_sm_disable( void ); +extern BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg); +extern void bta_dm_search_sm_disable( void ); + + +extern void bta_dm_enable (tBTA_DM_MSG *p_data); +extern void bta_dm_disable (tBTA_DM_MSG *p_data); +extern void bta_dm_set_dev_name (tBTA_DM_MSG *p_data); +extern void bta_dm_set_visibility (tBTA_DM_MSG *p_data); +extern void bta_dm_set_afhchannels (tBTA_DM_MSG *p_data); +extern void bta_dm_vendor_spec_command(tBTA_DM_MSG *p_data); +extern void bta_dm_bond (tBTA_DM_MSG *p_data); +extern void bta_dm_bond_cancel (tBTA_DM_MSG *p_data); +extern void bta_dm_pin_reply (tBTA_DM_MSG *p_data); +extern void bta_dm_link_policy (tBTA_DM_MSG *p_data); +extern void bta_dm_auth_reply (tBTA_DM_MSG *p_data); +extern void bta_dm_signal_strength(tBTA_DM_MSG *p_data); +extern void bta_dm_tx_inqpower(tBTA_DM_MSG *p_data); +extern void bta_dm_acl_change(tBTA_DM_MSG *p_data); +extern void bta_dm_add_device (tBTA_DM_MSG *p_data); +extern void bta_dm_remove_device (tBTA_DM_MSG *p_data); + + +extern void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data); +extern void bta_dm_pm_timer(tBTA_DM_MSG *p_data); +extern void bta_dm_add_ampkey (tBTA_DM_MSG *p_data); + +#if BLE_INCLUDED == TRUE +extern void bta_dm_add_blekey (tBTA_DM_MSG *p_data); +extern void bta_dm_add_ble_device (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_passkey_reply (tBTA_DM_MSG *p_data); +extern void bta_dm_security_grant (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_conn_params (tBTA_DM_MSG *p_data); +extern void bta_dm_ble_set_scan_params (tBTA_DM_MSG *p_data); +#endif +extern void bta_dm_set_encryption(tBTA_DM_MSG *p_data); +extern void bta_dm_confirm(tBTA_DM_MSG *p_data); +extern void bta_dm_passkey_cancel(tBTA_DM_MSG *p_data); +#if (BTM_OOB_INCLUDED == TRUE) +extern void bta_dm_loc_oob(tBTA_DM_MSG *p_data); +extern void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data); +extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data); +#endif /* BTM_OOB_INCLUDED */ + +extern void bta_dm_init_pm(void); +extern void bta_dm_disable_pm(void); + +extern void bta_dm_search_start (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cancel (tBTA_DM_MSG *p_data); +extern void bta_dm_discover (tBTA_DM_MSG *p_data); +extern void bta_dm_di_disc (tBTA_DM_MSG *p_data); +extern void bta_dm_inq_cmpl (tBTA_DM_MSG *p_data); +extern void bta_dm_rmt_name (tBTA_DM_MSG *p_data); +extern void bta_dm_sdp_result (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cmpl (tBTA_DM_MSG *p_data); +extern void bta_dm_free_sdp_db (tBTA_DM_MSG *p_data); +extern void bta_dm_disc_result (tBTA_DM_MSG *p_data); +extern void bta_dm_search_result (tBTA_DM_MSG *p_data); +extern void bta_dm_discovery_cmpl (tBTA_DM_MSG *p_data); +extern void bta_dm_queue_search (tBTA_DM_MSG *p_data); +extern void bta_dm_queue_disc (tBTA_DM_MSG *p_data); +extern void bta_dm_search_clear_queue (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cancel_cmpl (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cancel_notify (tBTA_DM_MSG *p_data); +extern void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG *p_data); +extern void bta_dm_disc_rmt_name (tBTA_DM_MSG *p_data); +extern tBTA_DM_PEER_DEVICE * bta_dm_find_peer_device(BD_ADDR peer_addr); + +extern void bta_dm_pm_active(BD_ADDR peer_addr); + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE ) +void bta_dm_eir_update_uuid(UINT16 uuid16, BOOLEAN adding); +#else +#define bta_dm_eir_update_uuid(x, y) +#endif + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) +extern void bta_dm_update_eir_uuid (tBTA_DM_MSG *p_data); +#endif +#if (BTM_EIR_SERVER_INCLUDED == TRUE) +extern void bta_dm_set_eir_config (tBTA_DM_MSG *p_data); +#endif +extern void bta_dm_enable_test_mode(tBTA_DM_MSG *p_data); +extern void bta_dm_disable_test_mode(tBTA_DM_MSG *p_data); +extern void bta_dm_execute_callback(tBTA_DM_MSG *p_data); + +extern void bta_dm_set_afh_channel_assesment(tBTA_DM_MSG *p_data); + +#endif /* BTA_DM_INT_H */ + diff --git a/bta/dm/bta_dm_main.c b/bta/dm/bta_dm_main.c new file mode 100644 index 0000000..a2fec04 --- /dev/null +++ b/bta/dm/bta_dm_main.c @@ -0,0 +1,345 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 main implementation file for the BTA device manager. + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_dm_int.h" + + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_DM_CB bta_dm_cb; +tBTA_DM_SEARCH_CB bta_dm_search_cb; +tBTA_DM_DI_CB bta_dm_di_cb; +#endif + + +#define BTA_DM_NUM_ACTIONS (BTA_DM_MAX_EVT & 0x00ff) + +/* type for action functions */ +typedef void (*tBTA_DM_ACTION)(tBTA_DM_MSG *p_data); + +/* action function list */ +const tBTA_DM_ACTION bta_dm_action[] = +{ + + /* device manager local device API events */ + bta_dm_enable, /* 0 BTA_DM_API_ENABLE_EVT */ + bta_dm_disable, /* 1 BTA_DM_API_DISABLE_EVT */ + bta_dm_set_dev_name, /* 2 BTA_DM_API_SET_NAME_EVT */ + bta_dm_set_visibility, /* 3 BTA_DM_API_SET_VISIBILITY_EVT */ + bta_dm_set_afhchannels, /* 4 BTA_DM_API_SET_AFH_CHANNELS_EVT */ + bta_dm_signal_strength, /* 5 BTA_API_DM_SIG_STRENGTH_EVT */ + bta_dm_vendor_spec_command,/* 6 BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */ + bta_dm_tx_inqpower, /* 7 BTA_DM_API_SIG_STRENGTH_EVT */ + bta_dm_acl_change, /* 8 BTA_DM_ACL_CHANGE_EVT */ + bta_dm_add_device, /* 9 BTA_DM_API_ADD_DEVICE_EVT */ + + /* security API events */ + bta_dm_bond, /* 10 BTA_DM_API_BOND_EVT */ + bta_dm_bond_cancel, /* 11 BTA_DM_API_BOND_CANCEL_EVT */ + bta_dm_pin_reply, /* 12 BTA_DM_API_PIN_REPLY_EVT */ + bta_dm_link_policy, /* 13 BTA_DM_API_LINK_POLICY_EVT */ + bta_dm_auth_reply, /* 14 BTA_DM_API_AUTH_REPLY_EVT */ + + /* power manger events */ + bta_dm_pm_btm_status, /* 15 BTA_DM_PM_BTM_STATUS_EVT */ + bta_dm_pm_timer, /* 16 BTA_DM_PM_TIMER_EVT*/ + + /* simple pairing events */ + bta_dm_confirm, /* 17 BTA_DM_API_CONFIRM_EVT */ + + bta_dm_set_encryption, /* BTA_DM_API_SET_ENCRYPTION_EVT */ + +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + bta_dm_passkey_cancel, /* 19 BTA_DM_API_PASKY_CANCEL_EVT */ +#endif +#if (BTM_OOB_INCLUDED == TRUE) + bta_dm_loc_oob, /* 20 BTA_DM_API_LOC_OOB_EVT */ + bta_dm_ci_io_req_act, /* 21 BTA_DM_CI_IO_REQ_EVT */ + bta_dm_ci_rmt_oob_act, /* 22 BTA_DM_CI_RMT_OOB_EVT */ +#endif /* BTM_OOB_INCLUDED */ + + bta_dm_remove_device, /* BTA_DM_API_REMOVE_DEVICE_EVT */ + +#if BLE_INCLUDED == TRUE + bta_dm_add_blekey, /* BTA_DM_API_ADD_BLEKEY_EVT */ + bta_dm_add_ble_device, /* BTA_DM_API_ADD_BLEDEVICE_EVT */ + bta_dm_ble_passkey_reply, /* BTA_DM_API_BLE_PASSKEY_REPLY_EVT */ + bta_dm_security_grant, + bta_dm_ble_set_bg_conn_type, + bta_dm_ble_set_conn_params, /* BTA_DM_API_BLE_CONN_PARAM_EVT */ + bta_dm_ble_set_scan_params, /* BTA_DM_API_BLE_SCAN_PARAM_EVT */ +#endif + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&( BTA_EIR_CANNED_UUID_LIST != TRUE )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) + bta_dm_update_eir_uuid, /* BTA_DM_API_UPDATE_EIR_UUID_EVT */ +#endif +#if (BTM_EIR_SERVER_INCLUDED == TRUE) + bta_dm_set_eir_config, /* BTA_DM_API_SET_EIR_CONFIG_EVT */ +#endif + + bta_dm_enable_test_mode, /* BTA_DM_API_ENABLE_TEST_MODE_EVT */ + bta_dm_disable_test_mode, /* BTA_DM_API_DISABLE_TEST_MODE_EVT */ + bta_dm_execute_callback, /* BTA_DM_API_EXECUTE_CBACK_EVT */ + bta_dm_set_afh_channel_assesment /* BTA_DM_API_SET_AFH_CHANNEL_ASSESMENT_EVT */ +}; + + + +/* state machine action enumeration list */ +enum +{ + BTA_DM_API_SEARCH, /* 0 bta_dm_search_start */ + BTA_DM_API_SEARCH_CANCEL, /* 1 bta_dm_search_cancel */ + BTA_DM_API_DISCOVER, /* 2 bta_dm_discover */ + BTA_DM_INQUIRY_CMPL, /* 3 bta_dm_inq_cmpl */ + BTA_DM_REMT_NAME, /* 4 bta_dm_rmt_name */ + BTA_DM_SDP_RESULT, /* 5 bta_dm_sdp_result */ + BTA_DM_SEARCH_CMPL, /* 6 bta_dm_search_cmpl*/ + BTA_DM_FREE_SDP_DB, /* 7 bta_dm_free_sdp_db */ + BTA_DM_DISC_RESULT, /* 8 bta_dm_disc_result */ + BTA_DM_SEARCH_RESULT, /* 9 bta_dm_search_result */ + BTA_DM_QUEUE_SEARCH, /* 10 bta_dm_queue_search */ + BTA_DM_QUEUE_DISC, /* 11 bta_dm_queue_disc */ + BTA_DM_SEARCH_CLEAR_QUEUE, /* 12 bta_dm_search_clear_queue */ + BTA_DM_SEARCH_CANCEL_CMPL, /* 13 bta_dm_search_cancel_cmpl */ + BTA_DM_SEARCH_CANCEL_NOTIFY, /* 14 bta_dm_search_cancel_notify */ + BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, /* 15 bta_dm_search_cancel_transac_cmpl */ + BTA_DM_DISC_RMT_NAME, /* 16 bta_dm_disc_rmt_name */ + BTA_DM_API_DI_DISCOVER, /* 17 bta_dm_di_disc */ + BTA_DM_SEARCH_NUM_ACTIONS /* 18 */ +}; + + +/* action function list */ +const tBTA_DM_ACTION bta_dm_search_action[] = +{ + + bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */ + bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */ + bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */ + bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */ + bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */ + bta_dm_sdp_result, /* 5 BTA_DM_SDP_RESULT */ + bta_dm_search_cmpl, /* 6 BTA_DM_SEARCH_CMPL */ + bta_dm_free_sdp_db, /* 7 BTA_DM_FREE_SDP_DB */ + bta_dm_disc_result, /* 8 BTA_DM_DISC_RESULT */ + bta_dm_search_result, /* 9 BTA_DM_SEARCH_RESULT */ + bta_dm_queue_search, /* 10 BTA_DM_QUEUE_SEARCH */ + bta_dm_queue_disc, /* 11 BTA_DM_QUEUE_DISC */ + bta_dm_search_clear_queue, /* 12 BTA_DM_SEARCH_CLEAR_QUEUE */ + bta_dm_search_cancel_cmpl, /* 13 BTA_DM_SEARCH_CANCEL_CMPL */ + bta_dm_search_cancel_notify, /* 14 BTA_DM_SEARCH_CANCEL_NOTIFY */ + bta_dm_search_cancel_transac_cmpl, /* 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL */ + bta_dm_disc_rmt_name, /* 16 BTA_DM_DISC_RMT_NAME */ + bta_dm_di_disc /* 17 BTA_DM_API_DI_DISCOVER */ +}; + +#define BTA_DM_SEARCH_IGNORE BTA_DM_SEARCH_NUM_ACTIONS +/* state table information */ +#define BTA_DM_SEARCH_ACTIONS 2 /* number of actions */ +#define BTA_DM_SEARCH_NEXT_STATE 2 /* position of next state */ +#define BTA_DM_SEARCH_NUM_COLS 3 /* number of columns in state tables */ + + + +/* state table for listen state */ +const UINT8 bta_dm_search_idle_st_table[][BTA_DM_SEARCH_NUM_COLS] = +{ + +/* Event Action 1 Action 2 Next State */ +/* API_SEARCH */ {BTA_DM_API_SEARCH, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* API_SEARCH_DISC */ {BTA_DM_API_DISCOVER, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* REMT_NAME_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* SDP_RESULT_EVT */ {BTA_DM_FREE_SDP_DB, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* API_DI_DISCOVER_EVT */ {BTA_DM_API_DI_DISCOVER, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE} + +}; +const UINT8 bta_dm_search_search_active_st_table[][BTA_DM_SEARCH_NUM_COLS] = +{ + +/* Event Action 1 Action 2 Next State */ +/* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* API_SEARCH_CANCEL */ {BTA_DM_API_SEARCH_CANCEL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}, +/* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* INQUIRY_CMPL */ {BTA_DM_INQUIRY_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* REMT_NAME_EVT */ {BTA_DM_REMT_NAME, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_SEARCH_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}, +/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE} + + +}; + +const UINT8 bta_dm_search_search_cancelling_st_table[][BTA_DM_SEARCH_NUM_COLS] = +{ + +/* Event Action 1 Action 2 Next State */ +/* API_SEARCH */ {BTA_DM_QUEUE_SEARCH, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}, +/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CLEAR_QUEUE, BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_CANCELLING}, +/* API_SEARCH_DISC */ {BTA_DM_QUEUE_DISC, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}, +/* INQUIRY_CMPL */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* REMT_NAME_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, +/* SDP_RESULT_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING} + + +}; + +const UINT8 bta_dm_search_disc_active_st_table[][BTA_DM_SEARCH_NUM_COLS] = +{ + +/* Event Action 1 Action 2 Next State */ +/* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}, +/* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* REMT_NAME_EVT */ {BTA_DM_DISC_RMT_NAME, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}, +/* DISCV_RES_EVT */ {BTA_DM_DISC_RESULT, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}, +/* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE} + +}; + +typedef const UINT8 (*tBTA_DM_ST_TBL)[BTA_DM_SEARCH_NUM_COLS]; + +/* state table */ +const tBTA_DM_ST_TBL bta_dm_search_st_tbl[] = { + bta_dm_search_idle_st_table, + bta_dm_search_search_active_st_table, + bta_dm_search_search_cancelling_st_table, + bta_dm_search_disc_active_st_table +}; + + +/******************************************************************************* +** +** Function bta_dm_sm_disable +** +** Description unregister BTA DM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_sm_disable( ) +{ + bta_sys_deregister( BTA_ID_DM ); +} + + +/******************************************************************************* +** +** Function bta_dm_sm_execute +** +** Description State machine event handling function for DM +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg) +{ + UINT16 event = p_msg->event & 0x00ff; + + APPL_TRACE_EVENT1("bta_dm_sm_execute event:0x%x", event); + + /* execute action functions */ + if(event < BTA_DM_NUM_ACTIONS) + { + (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg); + } + + return TRUE; +} + +/******************************************************************************* +** +** Function bta_dm_sm_search_disable +** +** Description unregister BTA SEARCH DM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_search_sm_disable( ) +{ + bta_sys_deregister( BTA_ID_DM_SEARCH ); + +} + + +/******************************************************************************* +** +** Function bta_dm_search_sm_execute +** +** Description State machine event handling function for DM +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg) +{ + tBTA_DM_ST_TBL state_table; + UINT8 action; + int i; + + APPL_TRACE_EVENT2("bta_dm_search_sm_execute state:%d, event:0x%x", + bta_dm_search_cb.state, p_msg->event); + + /* look up the state table for the current state */ + state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state]; + + bta_dm_search_cb.state = state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE]; + + + /* execute action functions */ + for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++) + { + if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE) + { + (*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg); + } + else + { + break; + } + } + return TRUE; +} + diff --git a/bta/dm/bta_dm_pm.c b/bta/dm/bta_dm_pm.c new file mode 100644 index 0000000..8a993de --- /dev/null +++ b/bta/dm/bta_dm_pm.c @@ -0,0 +1,994 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the action functions for device manager state + * machine. + * + ******************************************************************************/ + +#include "gki.h" +#include "bd.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_dm_int.h" +#include "btm_api.h" + +#include <string.h> + + +static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +static void bta_dm_pm_set_mode(BD_ADDR peer_addr, BOOLEAN timed_out ); +static void bta_dm_pm_timer_cback(void *p_tle); +static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status); +static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr); +static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index); +static BOOLEAN bta_dm_pm_is_sco_active (); +static void bta_dm_pm_hid_check(BOOLEAN bScoActive); +static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable); +#if (BTM_SSR_INCLUDED == TRUE) +static void bta_dm_pm_ssr(BD_ADDR peer_addr); +static void bta_dm_ssr_cfg_cback(UINT8 id, UINT8 app_id, UINT16 max_lat, UINT16 min_rmt_to); +#endif + +tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; + + +/******************************************************************************* +** +** Function bta_dm_init_pm +** +** Description Initialises the BT low power manager +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_init_pm(void) +{ + + memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs)); + + /* if there are no power manger entries, so not register */ + if(p_bta_dm_pm_cfg[0].app_id != 0) + { + bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)bta_dm_pm_cback); + +#if (BTM_SSR_INCLUDED == TRUE) + bta_sys_ssr_cfg_register((tBTA_SYS_SSR_CFG_CBACK*)bta_dm_ssr_cfg_cback); +#endif + BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id, + bta_dm_pm_btm_cback); + } + + +} + + +/******************************************************************************* +** +** Function bta_dm_disable_pm +** +** Description Disable PM +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_disable_pm(void) +{ + UINT8 i; + + bta_sys_pm_register(NULL); + BTM_PmRegister( BTM_PM_DEREG, &bta_dm_cb.pm_id, NULL); + + /* Need to stop all active timers. */ + for(i=0; i<BTA_DM_NUM_PM_TIMER; i++) + { + if(bta_dm_cb.pm_timer[i].in_use) + { + APPL_TRACE_DEBUG1("stop dm_pm_timer:%d", i); + bta_sys_stop_timer(&bta_dm_cb.pm_timer[i].timer); + bta_dm_cb.pm_timer[i].in_use = FALSE; + } + } +} + +/******************************************************************************* +** +** Function bta_dm_pm_stop_timer +** +** Description stop a PM timer +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_stop_timer(BD_ADDR peer_addr) +{ + UINT8 i; + + for(i=0; i<BTA_DM_NUM_PM_TIMER; i++) + { + + if(bta_dm_cb.pm_timer[i].in_use && !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr)) + { + APPL_TRACE_DEBUG1("stop dm_pm_timer:%d", i); + bta_sys_stop_timer(&bta_dm_cb.pm_timer[i].timer); + bta_dm_cb.pm_timer[i].in_use = FALSE; + break; + } + + } +} + +/******************************************************************************* +** +** Function bta_dm_pm_cback +** +** Description Conn change callback from sys for low power management +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + + UINT8 i,j; + UINT16 policy_setting; + tBTM_STATUS btm_status; + tBTM_VERSION_INFO vers; +#if (BTM_SSR_INCLUDED == TRUE) + int index = BTA_DM_PM_SSR0; +#endif + tBTA_DM_PEER_DEVICE *p_dev; + + APPL_TRACE_DEBUG3("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id, app_id); + + btm_status = BTM_ReadLocalVersion (&vers); + p_dev = bta_dm_find_peer_device(peer_addr); + + /* Disable/Enable sniff policy on the SCO link if sco Up/Down. Will be removed in 2.2*/ + if ((btm_status == BTM_SUCCESS) && + (vers.manufacturer == LMP_COMPID_BROADCOM) && + (vers.hci_version < HCI_PROTO_VERSION_2_0) && + ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ) + { + bta_dm_pm_set_sniff_policy(p_dev, (status == BTA_SYS_SCO_OPEN)); + } + + /* find if there is an power mode entry for the service */ + for(i=1; i<=p_bta_dm_pm_cfg[0].app_id; i++) + { + + if((p_bta_dm_pm_cfg[i].id == id) + && ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[i].app_id == app_id ))) + break; + + } + + /* if no entries are there for the app_id and subystem in p_bta_dm_pm_spec*/ + if(i> p_bta_dm_pm_cfg[0].app_id) + return; + + bta_dm_pm_stop_timer(peer_addr); + /*p_dev = bta_dm_find_peer_device(peer_addr);*/ + +#if (BTM_SSR_INCLUDED == TRUE) + /* set SSR parameters on SYS CONN OPEN */ + if((BTA_SYS_CONN_OPEN == status) && p_dev && (p_dev->info & BTA_DM_DI_USE_SSR)) + { + index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr; + } +#endif + + /* if no action for the event */ + if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_ACTION) + { +#if (BTM_SSR_INCLUDED == TRUE) + if(BTA_DM_PM_SSR0 == index) /* and do not need to set SSR, return. */ +#endif + return; + } + + for(j=0; j<bta_dm_conn_srvcs.count ; j++) + { + /* check if an entry already present */ + if((bta_dm_conn_srvcs.conn_srvc[j].id == id) + && (bta_dm_conn_srvcs.conn_srvc[j].app_id == app_id ) + && !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) + break; + + } + + /* if subsystem has no more preference on the power mode remove + the cb */ + if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_PREF) + { + + if(j != bta_dm_conn_srvcs.count) + { + bta_dm_conn_srvcs.count--; + + for(; j<bta_dm_conn_srvcs.count ; j++) + { + + memcpy(&bta_dm_conn_srvcs.conn_srvc[j], &bta_dm_conn_srvcs.conn_srvc[j+1], sizeof(bta_dm_conn_srvcs.conn_srvc[j])); + + } + } + else + { + APPL_TRACE_WARNING0("bta_dm_act no entry for connected service cbs"); + return; + } + } + else if(j == bta_dm_conn_srvcs.count ) + { + /* check if we have more connected service that cbs */ + if(bta_dm_conn_srvcs.count == BTA_DM_NUM_CONN_SRVS) + { + APPL_TRACE_WARNING0("bta_dm_act no more connected service cbs"); + return; + } + + /* fill in a new cb */ + bta_dm_conn_srvcs.conn_srvc[j].id = id; + bta_dm_conn_srvcs.conn_srvc[j].app_id = app_id; + bdcpy(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr); + + APPL_TRACE_WARNING2("new conn_srvc id:%d, app_id:%d", id, app_id); + + bta_dm_conn_srvcs.count++; + bta_dm_conn_srvcs.conn_srvc[j].state = status; + } + else + { + /* no service is added or removed. only updating status. */ + bta_dm_conn_srvcs.conn_srvc[j].state = status; + } + + if(p_dev) + { + p_dev->pm_mode_attempted = 0; + p_dev->pm_mode_failed = 0; + } + +#if (BTM_SSR_INCLUDED == TRUE) + if(p_bta_dm_ssr_spec[index].max_lat) + { + bta_dm_pm_ssr(peer_addr); + } +#endif + + bta_dm_pm_set_mode(peer_addr, FALSE); + + /* perform the HID link workaround if needed + ** 1. If SCO up/down event is received OR + ** 2. If HID connection open is received and SCO is already active. + ** This will handle the case where HID connects when SCO already active + */ + if ( (btm_status == BTM_SUCCESS) && + ( ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) || + ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active()) ) ) + { + BOOLEAN bScoActive; + if (status == BTA_SYS_CONN_OPEN) + bScoActive = TRUE; + else + bScoActive = (status == BTA_SYS_SCO_OPEN); + + bta_dm_pm_hid_check(bScoActive); + } + +} + + +/******************************************************************************* +** +** Function bta_dm_pm_set_mode +** +** Description Set the power mode for the device +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_set_mode(BD_ADDR peer_addr, BOOLEAN timed_out ) +{ + + tBTA_DM_PM_ACTTION pm_action = BTA_DM_PM_NO_ACTION; + UINT16 timeout = 0; + UINT8 i,j; + tBTA_DM_PM_ACTTION failed_pm = 0; + tBTA_DM_PEER_DEVICE *p_peer_device = NULL; + tBTA_DM_PM_ACTTION allowed_modes = 0; + tBTA_DM_PM_ACTTION pref_modes = 0; + tBTA_DM_PM_CFG *p_pm_cfg; + tBTA_DM_PM_SPEC *p_pm_spec; + tBTA_DM_PM_ACTN *p_act0, *p_act1; + tBTA_DM_SRVCS *p_srvcs; + + + if(!bta_dm_cb.device_list.count) + return; + + /* see if any attempt to put device in low power mode failed */ + p_peer_device = bta_dm_find_peer_device(peer_addr); + /* if no peer device found return */ + if (p_peer_device == NULL) + return; + + failed_pm = p_peer_device->pm_mode_failed; + + for(i=0; i<bta_dm_conn_srvcs.count ; i++) + { + + p_srvcs = &bta_dm_conn_srvcs.conn_srvc[i]; + if(!bdcmp(p_srvcs->peer_bdaddr, peer_addr)) + { + + /* p_bta_dm_pm_cfg[0].app_id is the number of entries */ + for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++) + { + if((p_bta_dm_pm_cfg[j].id == p_srvcs->id) + && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID ) || + (p_bta_dm_pm_cfg[j].app_id == p_srvcs->app_id))) + break; + } + + p_pm_cfg = &p_bta_dm_pm_cfg[j]; + p_pm_spec = &p_bta_dm_pm_spec[p_pm_cfg->spec_idx]; + p_act0 = &p_pm_spec->actn_tbl[p_srvcs->state][0]; + p_act1 = &p_pm_spec->actn_tbl[p_srvcs->state][1]; + + APPL_TRACE_DEBUG3("bta_dm_pm_set_mode: srvcsid: %d, state: %d, j: %d", p_srvcs->id, p_srvcs->state, j); + allowed_modes |= p_pm_spec->allow_mask; + + /* PM actions are in the order of strictness */ + + /* first check if the first preference is ok */ + if(!(failed_pm & p_act0->power_mode)) + { + pref_modes |= p_act0->power_mode; + + if(p_act0->power_mode > pm_action) + { + pm_action = p_act0->power_mode; + timeout = p_act0->timeout; + + } + } + /* if first preference has already failed, try second preference */ + else if(!(failed_pm & p_act1->power_mode)) + { + pref_modes |= p_act1->power_mode; + + if(p_act1->power_mode > pm_action) + { + pm_action = p_act1->power_mode; + timeout = p_act1->timeout; + + } + } + } + } + + if(pm_action & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) + { + + /* some service don't like the mode */ + if(!(allowed_modes & pm_action)) + { + + /* select the other mode if its allowed and preferred, otherwise 0 which is BTA_DM_PM_NO_ACTION */ + pm_action = (allowed_modes & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & pref_modes); + + /* no timeout needed if no action is required */ + if(pm_action == BTA_DM_PM_NO_ACTION) + { + timeout = 0; + } + + } + + + } + + if(!timed_out && timeout) + { + + for(i=0; i<BTA_DM_NUM_PM_TIMER; i++) + { + + if(!bta_dm_cb.pm_timer[i].in_use) + { + bta_dm_cb.pm_timer[i].in_use = TRUE; + bdcpy(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr); + bta_dm_cb.pm_timer[i].timer.p_cback = bta_dm_pm_timer_cback; + bta_sys_start_timer(&bta_dm_cb.pm_timer[i].timer, 0, timeout); + APPL_TRACE_DEBUG2("start dm_pm_timer:%d, %d", i, timeout); + return; + + } + + } + + /* no more timers */ + if(i==BTA_DM_NUM_PM_TIMER) + { + APPL_TRACE_WARNING0("bta_dm_act dm_pm_timer no more"); + return; + } + } + + if(pm_action == BTA_DM_PM_NO_ACTION) + { + + + } + else if(pm_action == BTA_DM_PM_PARK) + { + p_peer_device->pm_mode_attempted = BTA_DM_PM_PARK; + bta_dm_pm_park(peer_addr); + + } + else if(pm_action & BTA_DM_PM_SNIFF) + { + /* dont initiate SNIFF, if link_policy has it disabled */ + if (p_peer_device->link_policy & HCI_ENABLE_SNIFF_MODE) + { + p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF; + bta_dm_pm_sniff(p_peer_device, (UINT8)(pm_action & 0x0F) ); + } + else + { + APPL_TRACE_DEBUG0("bta_dm_pm_set_mode: Link policy disallows SNIFF, ignore request"); + } + } + else if(pm_action == BTA_DM_PM_ACTIVE) + { + + bta_dm_pm_active(peer_addr); + + } + + +} + + +/******************************************************************************* +** +** Function bta_ag_pm_park +** +** Description Switch to park mode. +** +** +** Returns TRUE if park attempted, FALSE otherwise. +** +*******************************************************************************/ +static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr) +{ + + tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE; + + /* if not in park mode, switch to park */ + BTM_ReadPowerMode(peer_addr, &mode); + + if(mode != BTM_PM_MD_PARK) + { + BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &p_bta_dm_pm_md[BTA_DM_PM_PARK_IDX]); + } + return TRUE; + +} + + +/******************************************************************************* +** +** Function bta_ag_pm_sniff +** +** Description Switch to sniff mode. +** +** +** Returns TRUE if sniff attempted, FALSE otherwise. +** +*******************************************************************************/ +static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index) +{ + tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE; + tBTM_PM_PWR_MD pwr_md; + tBTM_STATUS status; + + BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode); + +#if (BTM_SSR_INCLUDED == TRUE) + APPL_TRACE_DEBUG3("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index, p_peer_dev->info); + if (mode != BTM_PM_MD_SNIFF || + (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures ()) && + HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadRemoteFeatures (p_peer_dev->peer_bdaddr)) && + !(p_peer_dev->info & BTA_DM_DI_USE_SSR))) +#else + APPL_TRACE_DEBUG2("bta_dm_pm_sniff cur:%d, idx:%d", mode, index); + if(mode != BTM_PM_MD_SNIFF) +#endif + { + /* if the current mode is not sniff, issue the sniff command. + * If sniff, but SSR is not used in this link, still issue the command */ + memcpy(&pwr_md, &p_bta_dm_pm_md[index], sizeof (tBTM_PM_PWR_MD)); + if (p_peer_dev->info & BTA_DM_DI_INT_SNIFF) + { + pwr_md.mode |= BTM_PM_MD_FORCE; + } + status = BTM_SetPowerMode (bta_dm_cb.pm_id, p_peer_dev->peer_bdaddr, &pwr_md); + if (status == BTM_CMD_STORED|| status == BTM_CMD_STARTED) + { + p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF); + p_peer_dev->info |= BTA_DM_DI_SET_SNIFF; + } + else if (status == BTM_SUCCESS) + { + APPL_TRACE_DEBUG0("bta_dm_pm_sniff BTM_SetPowerMode() returns BTM_SUCCESS"); + p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF); + } + else /* error */ + { + APPL_TRACE_ERROR1("bta_dm_pm_sniff BTM_SetPowerMode() returns ERROR status=%d", status); + p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF); + } + } + /* else already in sniff and is using SSR, do nothing */ + + return TRUE; + +} + +/******************************************************************************* +** +** Function bta_dm_pm_ssr +** +** Description checks and sends SSR parameters +** +** Returns void +** +*******************************************************************************/ +#if (BTM_SSR_INCLUDED == TRUE) +static void bta_dm_pm_ssr(BD_ADDR peer_addr) +{ + tBTA_DM_SSR_SPEC *p_spec, *p_spec_cur; + UINT8 i,j; + int ssr = BTA_DM_PM_SSR0; + + /* go through the connected services */ + for(i=0; i<bta_dm_conn_srvcs.count ; i++) + { + if(!bdcmp(bta_dm_conn_srvcs.conn_srvc[i].peer_bdaddr, peer_addr)) + { + /* p_bta_dm_pm_cfg[0].app_id is the number of entries */ + for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++) + { + /* find the associated p_bta_dm_pm_cfg */ + if((p_bta_dm_pm_cfg[j].id == bta_dm_conn_srvcs.conn_srvc[i].id) + && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID ) + || (p_bta_dm_pm_cfg[j].app_id == bta_dm_conn_srvcs.conn_srvc[i].app_id))) + { + APPL_TRACE_WARNING2("bta_dm_pm_ssr conn_srvc id:%d, app_id:%d", + bta_dm_conn_srvcs.conn_srvc[i].id, bta_dm_conn_srvcs.conn_srvc[i].app_id); + break; + } + } + + /* find the ssr index with the smallest max latency. */ + p_spec_cur = &p_bta_dm_ssr_spec[p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr]; + p_spec = &p_bta_dm_ssr_spec[ssr]; + + if (p_spec_cur->max_lat < p_spec->max_lat || + (ssr == BTA_DM_PM_SSR0 && p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr != BTA_DM_PM_SSR0)) + { + ssr = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr; + } + + } + } + + p_spec = &p_bta_dm_ssr_spec[ssr]; + APPL_TRACE_WARNING2("bta_dm_pm_ssr:%d, lat:%d", ssr, p_spec->max_lat); + if(p_spec->max_lat) + { + /* set the SSR parameters. */ + BTM_SetSsrParams (peer_addr, p_spec->max_lat, + p_spec->min_rmt_to, p_spec->min_loc_to); + } +} +/******************************************************************************* +** +** Function bta_dm_ssr_cfg_cback +** +** Description Conn change callback from sys for low power management +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_ssr_cfg_cback(UINT8 id, UINT8 app_id, + UINT16 max_lat, UINT16 min_rmt_to) +{ + tBTA_DM_SSR_SPEC *p_spec; + UINT8 i, index; + /* find if there is an power mode entry for the service */ + for(i=1; i<=p_bta_dm_pm_cfg[0].app_id; i++) + { + + if((p_bta_dm_pm_cfg[i].id == id) + && ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[i].app_id == app_id ))) + break; + + } + /* if no entries are there for the app_id and subystem in p_bta_dm_pm_spec*/ + if(i> p_bta_dm_pm_cfg[0].app_id) + return; + + index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr; + + APPL_TRACE_DEBUG2("SSR parameter changed to: max_latency: %d min_tout: %d", max_lat, min_rmt_to); + + p_spec = &p_bta_dm_ssr_spec[index]; + p_spec->max_lat = max_lat; + p_spec->min_rmt_to = min_rmt_to; +} + + +#endif +/******************************************************************************* +** +** Function bta_dm_pm_active +** +** Description Brings connection to active mode +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_pm_active(BD_ADDR peer_addr) +{ + tBTM_PM_PWR_MD pm; + + memset( (void*)&pm, 0, sizeof(pm)); + + /* switch to active mode */ + pm.mode = BTM_PM_MD_ACTIVE; + BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &pm); + + +} + + +/******************************************************************************* +** +** Function bta_dm_pm_btm_cback +** +** Description BTM power manager callback. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status) +{ + tBTA_DM_PM_BTM_STATUS *p_buf; + + if ((p_buf = (tBTA_DM_PM_BTM_STATUS *) GKI_getbuf(sizeof(tBTA_DM_PM_BTM_STATUS))) != NULL) + { + p_buf->hdr.event = BTA_DM_PM_BTM_STATUS_EVT; + p_buf->status = status; + p_buf->value = value; + p_buf->hci_status = hci_status; + bdcpy(p_buf->bd_addr, bd_addr); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_dm_pm_timer_cback +** +** Description Power management timer callback. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_dm_pm_timer_cback(void *p_tle) +{ + tBTA_DM_PM_TIMER *p_buf; + UINT8 i; + + APPL_TRACE_WARNING0("dm_pm_timer expires"); + + for(i=0; i<BTA_DM_NUM_PM_TIMER; i++) + { + + if(bta_dm_cb.pm_timer[i].in_use) + { + + if(&bta_dm_cb.pm_timer[i].timer == (TIMER_LIST_ENT*) p_tle) + { + APPL_TRACE_WARNING1("dm_pm_timer expires %d", i); + bta_dm_cb.pm_timer[i].in_use = FALSE; + break; + } + + } + + } + + + /* no more timers */ + if(i==BTA_DM_NUM_PM_TIMER) + { + return; + } + + if ((p_buf = (tBTA_DM_PM_TIMER *) GKI_getbuf(sizeof(tBTA_DM_PM_TIMER))) != NULL) + { + p_buf->hdr.event = BTA_DM_PM_TIMER_EVT; + bdcpy(p_buf->bd_addr, bta_dm_cb.pm_timer[i].peer_bdaddr); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_dm_pm_btm_status +** +** Description Process pm status event from btm +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data) +{ + + tBTA_DM_PEER_DEVICE *p_dev; + tBTA_DM_DEV_INFO info; + + APPL_TRACE_DEBUG1("bta_dm_pm_btm_status:%d", p_data->pm_status.status); + p_dev = bta_dm_find_peer_device(p_data->pm_status.bd_addr); + if(NULL == p_dev) + return; + + info = p_dev->info; + /* check new mode */ + switch (p_data->pm_status.status) + { + case BTM_PM_STS_ACTIVE: + /* if our sniff or park attempt failed + we should not try it again*/ + if (p_data->pm_status.hci_status != 0) + { + APPL_TRACE_ERROR1("bta_dm_pm_btm_status hci_status=%d", p_data->pm_status.hci_status); + p_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF); + + if(p_dev->pm_mode_attempted &(BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) + { + p_dev->pm_mode_failed + |= ((BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & p_dev->pm_mode_attempted); + bta_dm_pm_stop_timer(p_data->pm_status.bd_addr); + bta_dm_pm_set_mode(p_data->pm_status.bd_addr, FALSE); + } + } + else + { +#if (BTM_SSR_INCLUDED == TRUE) + if(p_dev->prev_low) + { + /* need to send the SSR paramaters to controller again */ + bta_dm_pm_ssr(p_dev->peer_bdaddr); + } + p_dev->prev_low = BTM_PM_STS_ACTIVE; +#endif + bta_dm_pm_stop_timer(p_data->pm_status.bd_addr); + bta_dm_pm_set_mode(p_data->pm_status.bd_addr, FALSE); + } + break; + +#if (BTM_SSR_INCLUDED == TRUE) + case BTM_PM_STS_PARK: + case BTM_PM_STS_HOLD: + /* save the previous low power mode - for SSR. + * SSR parameters are sent to controller on "conn open". + * the numbers stay good until park/hold/detach */ + if(p_dev->info & BTA_DM_DI_USE_SSR) + p_dev->prev_low = p_data->pm_status.status; + break; + + case BTM_PM_STS_SSR: + if(p_data->pm_status.value) + p_dev->info |= BTA_DM_DI_USE_SSR; + else + p_dev->info &= ~BTA_DM_DI_USE_SSR; + break; +#endif + case BTM_PM_STS_SNIFF: + p_dev->info &= ~(BTA_DM_DI_SET_SNIFF|BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF); + if (info & BTA_DM_DI_SET_SNIFF) + p_dev->info |= BTA_DM_DI_INT_SNIFF; + else + p_dev->info |= BTA_DM_DI_ACP_SNIFF; + break; + + case BTM_PM_STS_ERROR: + p_dev->info &= ~BTA_DM_DI_SET_SNIFF; + break; + + default: + break; + } + + + +} + +/******************************************************************************* +** +** Function bta_dm_pm_timer +** +** Description Process pm timer event from btm +** +** +** Returns void +** +*******************************************************************************/ +void bta_dm_pm_timer(tBTA_DM_MSG *p_data) +{ + + APPL_TRACE_WARNING0("proc dm_pm_timer expires"); + bta_dm_pm_set_mode(p_data->pm_status.bd_addr, TRUE); + + +} + +/******************************************************************************* +** +** Function bta_dm_find_peer_device +** +** Description Given an address, find the associated control block. +** +** Returns tBTA_DM_PEER_DEVICE +** +*******************************************************************************/ +tBTA_DM_PEER_DEVICE * bta_dm_find_peer_device(BD_ADDR peer_addr) +{ + tBTA_DM_PEER_DEVICE *p_dev = NULL; + int i; + + for(i=0; i<bta_dm_cb.device_list.count; i++) + { + if(!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr)) + { + p_dev = &bta_dm_cb.device_list.peer_device[i]; + break; + } + + } + return p_dev; +} + +/******************************************************************************* +** +** Function bta_dm_is_sco_active +** +** Description Loop through connected services for HFP+State=SCO +** +** Returns BOOLEAN. TRUE if SCO active, else FALSE +** +*******************************************************************************/ +static BOOLEAN bta_dm_pm_is_sco_active () +{ + int j; + BOOLEAN bScoActive = FALSE; + + for(j=0; j<bta_dm_conn_srvcs.count ; j++) + { + /* check if an entry already present */ + if ( (bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_AG ) && (bta_dm_conn_srvcs.conn_srvc[j].state == BTA_SYS_SCO_OPEN) ) + { + bScoActive = TRUE; + break; + } + } + + APPL_TRACE_DEBUG1("bta_dm_is_sco_active: SCO active: %d", bScoActive); + return bScoActive; +} + + +/******************************************************************************* +** +** Function bta_dm_pm_hid_check +** +** Description Disables/Enables sniff in link policy based on SCO Up/Down +** +** Returns None +** +*******************************************************************************/ + +static void bta_dm_pm_hid_check(BOOLEAN bScoActive) +{ + int j; + + /* if HID is active, disable the link policy */ + for(j=0; j<bta_dm_conn_srvcs.count ; j++) + { + /* check if an entry already present */ + if(bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_HH ) + { + APPL_TRACE_DEBUG2 ("SCO status change(Active: %d), modify HID link policy. state: %d", + bScoActive, bta_dm_conn_srvcs.conn_srvc[j].state); + bta_dm_pm_set_sniff_policy( bta_dm_find_peer_device(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr), bScoActive); + + /* if we had disabled link policy, seems like the hid device stop retrying SNIFF after a few tries. force sniff if needed */ + if (!bScoActive) + bta_dm_pm_set_mode(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, FALSE); + } + } + +} + +/******************************************************************************* +** +** Function bta_dm_pm_set_sniff_policy +** +** Description Disables/Enables sniff in link policy for the give device +** +** Returns None +** +*******************************************************************************/ +static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable) +{ + UINT16 policy_setting; + + if (!p_dev) + return; + + if (bDisable) + { + policy_setting = bta_dm_cb.cur_policy & + (HCI_ENABLE_MASTER_SLAVE_SWITCH | + HCI_ENABLE_HOLD_MODE | + HCI_ENABLE_PARK_MODE); + + } + else + { + /* allow sniff after sco is closed */ + policy_setting= bta_dm_cb.cur_policy; + } + + /* if disabling SNIFF, make sure link is Active */ + if (bDisable) + bta_dm_pm_active(p_dev->peer_bdaddr); + + /* update device record and set link policy */ + p_dev->link_policy = policy_setting; + BTM_SetLinkPolicy(p_dev->peer_bdaddr, &policy_setting); + +} diff --git a/bta/dm/bta_dm_sco.c b/bta/dm/bta_dm_sco.c new file mode 100644 index 0000000..803242b --- /dev/null +++ b/bta/dm/bta_dm_sco.c @@ -0,0 +1,695 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the down sampling utility to convert PCM samples in + * 16k/32k/48k/44.1k/22050/11025 sampling rate into 8K/16bits samples + * required for SCO channel format. One API function isprovided and only + * possible to be used when transmitting SCO data is sent via HCI + * interface. + * + ******************************************************************************/ +#include <string.h> +#include "bta_api.h" +#include "bta_sys.h" + +#if (BTM_SCO_HCI_INCLUDED == TRUE) + +#ifndef BTA_DM_SCO_DEBUG +#define BTA_DM_SCO_DEBUG FALSE +#endif +/***************************************************************************** +** Constants +*****************************************************************************/ + +#define BTA_DM_PCM_OVERLAP_SIZE 48 + +#define BTA_DM_PCM_SMPL_RATE_44100 44100 +#define BTA_DM_PCM_SMPL_RATE_22050 22050 +#define BTA_DM_PCM_SMPL_RATE_11025 11025 + +/***************************************************************************** +** Data types for PCM Resampling utility +*****************************************************************************/ + +typedef INT32 (*PCONVERT_TO_BT_FILTERED) (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps,INT32 *pLastCurPos, UINT8 *pOverlapArea); +typedef INT32 (*PCONVERT_TO_BT_NOFILTER) (void *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps); +typedef struct +{ + UINT8 overlap_area[BTA_DM_PCM_OVERLAP_SIZE * 4]; + UINT32 cur_pos; /* current position */ + UINT32 src_sps; /* samples per second (source audio data) */ + PCONVERT_TO_BT_FILTERED filter; /* the action function to do the + conversion 44100, 22050, 11025*/ + PCONVERT_TO_BT_NOFILTER nofilter; /* the action function to do + the conversion 48000, 32000, 16000*/ + UINT32 bits; /* number of bits per pcm sample */ + UINT32 n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */ + UINT32 sample_size; + UINT32 can_be_filtered; + UINT32 divisor; +} tBTA_DM_PCM_RESAMPLE_CB; + +tBTA_DM_PCM_RESAMPLE_CB bta_dm_pcm_cb; + +/***************************************************************************** +** Macro Definition +*****************************************************************************/ + + +#define CHECK_SATURATION16(x) \ + if (x > 32767) \ + x = 32767; \ + else if (x < -32768) \ + x = -32768; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#define CONVERT_44100_TO_BLUETOOTH(pStart, pEnd) \ + { \ + INT32 out1, out2, out3, out4, out5; \ + SRC_TYPE *pS = (SRC_TYPE *)pStart; \ + SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \ + \ + while (pS < pSEnd) \ + { \ + CurrentPos -= 8000; \ + \ + if (CurrentPos >= 0) \ + { \ + pS += SRC_CHANNELS; \ + continue; \ + } \ + CurrentPos += dwSrcSps; \ + \ + out1 = (SRC_SAMPLE(0) * 1587) \ + + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 1522) \ + + ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1337) \ + + ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 1058); \ + \ + out1 = out1 / 30000; \ + \ + out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 725) \ + + ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 384) \ + + ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 79); \ + \ + out2 = out2 / 30000; \ + \ + out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 156) \ + + ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 298) \ + + ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 345); \ + \ + out3 = out3 / 30000; \ + \ + out4 = ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 306) \ + + ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 207) \ + + ((SRC_SAMPLE(12) + SRC_SAMPLE(-12)) * 78); \ + \ + out4 = out4 / 30000; \ + \ + out5 = out1 + out2 - out3 - out4; \ + \ + CHECK_SATURATION16(out5); \ + *psBtOut++ = (INT16)out5; \ + \ + pS += SRC_CHANNELS; \ + } \ + } + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#define CONVERT_22050_TO_BLUETOOTH(pStart, pEnd) \ + { \ + INT32 out1, out2, out3, out4, out5; \ + SRC_TYPE *pS = (SRC_TYPE *)pStart; \ + SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \ + \ + while (pS < pSEnd) \ + { \ + CurrentPos -= 8000; \ + \ + if (CurrentPos >= 0) \ + { \ + pS += SRC_CHANNELS; \ + continue; \ + } \ + CurrentPos += dwSrcSps; \ + \ + out1 = (SRC_SAMPLE(0) * 2993) \ + + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2568) \ + + ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1509) \ + + ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 331); \ + \ + out1 = out1 / 30000; \ + \ + out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 454) \ + + ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 620) \ + + ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 305); \ + \ + out2 = out2 / 30000; \ + \ + out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 127) \ + + ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 350) \ + + ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 265) \ + + ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 6); \ + \ + out3 = out3 / 30000; \ + \ + out4 = ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 201); \ + \ + out4 = out4 / 30000; \ + \ + out5 = out1 - out2 + out3 - out4; \ + \ + CHECK_SATURATION16(out5); \ + *psBtOut++ = (INT16)out5; \ + \ + pS += SRC_CHANNELS; \ + } \ + } + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#define CONVERT_11025_TO_BLUETOOTH(pStart, pEnd) \ + { \ + INT32 out1; \ + SRC_TYPE *pS = (SRC_TYPE *)pStart; \ + SRC_TYPE *pSEnd = (SRC_TYPE *)pEnd; \ + \ + while (pS < pSEnd) \ + { \ + CurrentPos -= 8000; \ + \ + if (CurrentPos >= 0) \ + { \ + pS += SRC_CHANNELS; \ + continue; \ + } \ + CurrentPos += dwSrcSps; \ + \ + out1 = (SRC_SAMPLE(0) * 6349) \ + + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2874) \ + - ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1148) \ + - ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 287) \ + + ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 675) \ + - ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 258) \ + - ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 206) \ + + ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 266); \ + \ + out1 = out1 / 30000; \ + \ + CHECK_SATURATION16(out1); \ + *psBtOut++ = (INT16)out1; \ + \ + pS += SRC_CHANNELS; \ + } \ + } + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#undef SRC_CHANNELS +#undef SRC_SAMPLE +#undef SRC_TYPE + +#define SRC_TYPE UINT8 +#define SRC_CHANNELS 1 +#define SRC_SAMPLE(x) ((pS[x] - 0x80) << 8) + +/***************************************************************************** +** Local Function +*****************************************************************************/ +INT32 Convert_8M_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea) +{ + INT32 CurrentPos = *pLastCurPos; + SRC_TYPE *pIn, *pInEnd; + SRC_TYPE *pOv, *pOvEnd; + INT16 *psBtOut = (INT16 *)pDst; +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG1("Convert_8M_ToBT_Filtered, CurrentPos %d\n", CurrentPos); +#endif + memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2); + + pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE); + pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3)); + + pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE); + pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + BTA_DM_PCM_OVERLAP_SIZE); + + if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) + { + CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) + { + CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) + { + CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd); + } + + memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2); + + *pLastCurPos = CurrentPos; + + return (psBtOut - (INT16 *)pDst); +} + +INT32 Convert_8M_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps) +{ + INT32 CurrentPos; + UINT8 *pbSrc = (UINT8 *)pSrc; + INT16 *psDst = (INT16 *)pDst; + INT16 sWorker; + + // start at dwSpsSrc / 2, decrement by 8000 + // + CurrentPos = (dwSrcSps >> 1); + + while (dwSrcSamples--) + { + CurrentPos -= 8000; + + if (CurrentPos >= 0) + pbSrc++; + else + { + sWorker = *pbSrc++; + sWorker -= 0x80; + sWorker <<= 8; + + *psDst++ = sWorker; + + CurrentPos += dwSrcSps; + } + } + + return (psDst - (INT16 *)pDst); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#undef SRC_CHANNELS +#undef SRC_SAMPLE +#undef SRC_TYPE + +#define SRC_TYPE INT16 +#define SRC_CHANNELS 1 +#define SRC_SAMPLE(x) pS[x] + +INT32 Convert_16M_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea) +{ + INT32 CurrentPos = *pLastCurPos; + SRC_TYPE *pIn, *pInEnd; + SRC_TYPE *pOv, *pOvEnd; + INT16 *psBtOut = (INT16 *)pDst; + + memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2); + + pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE); + pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3)); + + pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE); + pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE); + + if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) + { + CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) + { + CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) + { + CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd); + } + + memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2); + + *pLastCurPos = CurrentPos; + + return (psBtOut - (INT16 *)pDst); +} + +INT32 Convert_16M_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps) +{ + INT32 CurrentPos; + INT16 *psSrc = (INT16 *)pSrc; + INT16 *psDst = (INT16 *)pDst; + + // start at dwSpsSrc / 2, decrement by 8000 + // + CurrentPos = (dwSrcSps >> 1); + + while (dwSrcSamples--) + { + CurrentPos -= 8000; + + if (CurrentPos >= 0) + psSrc++; + else + { + *psDst++ = *psSrc++; + + CurrentPos += dwSrcSps; + } + } + + return (psDst - (INT16 *)pDst); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#undef SRC_CHANNELS +#undef SRC_SAMPLE +#undef SRC_TYPE + +#define SRC_TYPE UINT8 +#define SRC_CHANNELS 2 +#define SRC_SAMPLE(x) ((((pS[x * 2] - 0x80) << 8) + ((pS[(x * 2) + 1] - 0x80) << 8)) >> 1) + +INT32 Convert_8S_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea) +{ + INT32 CurrentPos = *pLastCurPos; + SRC_TYPE *pIn, *pInEnd; + SRC_TYPE *pOv, *pOvEnd; + INT16 *psBtOut = (INT16 *)pDst; + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG5("Convert_8S_ToBT_Filtered CurrentPos %d, SRC_TYPE %d, SRC_CHANNELS %d, \ + dwSrcSamples %d, dwSrcSps %d", CurrentPos, sizeof (SRC_TYPE), SRC_CHANNELS, \ + dwSrcSamples, dwSrcSps); +#endif + memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2); + + pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE); + pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3)); + + pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE); + pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE); + + if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) + { + CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) + { + CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) + { + CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd); + } + + memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2); + + *pLastCurPos = CurrentPos; + + return (psBtOut - (INT16 *)pDst); +} + +INT32 Convert_8S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps) +{ + INT32 CurrentPos; + UINT8 *pbSrc = (UINT8 *)pSrc; + INT16 *psDst = (INT16 *)pDst; + INT16 sWorker, sWorker2; + + // start at dwSpsSrc / 2, decrement by 8000 + // + CurrentPos = (dwSrcSps >> 1); + + while (dwSrcSamples--) + { + CurrentPos -= 8000; + + if (CurrentPos >= 0) + pbSrc += 2; + else + { + sWorker = *(unsigned char *)pbSrc; + sWorker -= 0x80; + sWorker <<= 8; + pbSrc++; + + sWorker2 = *(unsigned char *)pbSrc; + sWorker2 -= 0x80; + sWorker2 <<= 8; + pbSrc++; + + sWorker += sWorker2; + sWorker >>= 1; + + *psDst++ = sWorker; + + CurrentPos += dwSrcSps; + } + } + + return (psDst - (INT16 *)pDst); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +#undef SRC_CHANNELS +#undef SRC_SAMPLE +#undef SRC_TYPE + +#define SRC_TYPE INT16 +#define SRC_CHANNELS 2 +#define SRC_SAMPLE(x) ((pS[x * 2] + pS[(x * 2) + 1]) >> 1) + +INT32 Convert_16S_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples, + UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea) +{ + INT32 CurrentPos = *pLastCurPos; + SRC_TYPE *pIn, *pInEnd; + SRC_TYPE *pOv, *pOvEnd; + INT16 *psBtOut = (INT16 *)pDst; + + memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2); + + pOv = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE); + pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3)); + + pIn = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE); + pInEnd = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE); + + if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) + { + CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) + { + CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd); + } + else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) + { + CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd); + CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd); + } + + memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \ + (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2); + + *pLastCurPos = CurrentPos; + + return (psBtOut - (INT16 *)pDst); +} + +INT32 Convert_16S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps) +{ + INT32 CurrentPos; + INT16 *psSrc = (INT16 *)pSrc; + INT16 *psDst = (INT16 *)pDst; + INT16 sWorker; + + // start at dwSpsSrc / 2, decrement by 8000 + // + CurrentPos = (dwSrcSps >> 1); + + while (dwSrcSamples--) + { + CurrentPos -= 8000; + + if (CurrentPos >= 0) + psSrc += 2; + else + { + /* CR 82894, to avoid overflow, divide before add */ + sWorker = ((*psSrc) >> 1 ); + psSrc++; + sWorker += ((*psSrc) >> 1 ); + psSrc++; + + *psDst++ = sWorker; + + CurrentPos += dwSrcSps; + } + } + + return (psDst - (INT16 *)pDst); +} + +/******************************************************************************* +** +** Function BTA_DmPcmInitSamples +** +** Description initialize the down sample converter. +** +** src_sps: original samples per second (source audio data) +** (ex. 44100, 48000) +** bits: number of bits per pcm sample (16) +** n_channels: number of channels (i.e. mono(1), stereo(2)...) +** +** Returns none +** +*******************************************************************************/ +void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels) +{ + tBTA_DM_PCM_RESAMPLE_CB *p_cb = &bta_dm_pcm_cb; + + p_cb->cur_pos = src_sps / 2; + p_cb->src_sps = src_sps; + p_cb->bits = bits; + p_cb->n_channels = n_channels; + p_cb->sample_size = 2; + p_cb->divisor = 2; + + memset(p_cb->overlap_area, 0, sizeof(p_cb->overlap_area) ); + + if ((src_sps == BTA_DM_PCM_SMPL_RATE_44100) || + (src_sps == BTA_DM_PCM_SMPL_RATE_22050) || + (src_sps == BTA_DM_PCM_SMPL_RATE_11025)) + p_cb->can_be_filtered = 1; + else + p_cb->can_be_filtered = 0; + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG2("bta_dm_pcm_init_samples: n_channels = %d bits = %d", n_channels, bits); +#endif + if(n_channels == 1) + { + /* mono */ + if(bits == 8) + { + p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_8M_ToBT_Filtered; + p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_8M_ToBT_NoFilter; + p_cb->divisor = 1; + } + else + { + p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_16M_ToBT_Filtered; + p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_16M_ToBT_NoFilter; + } + } + else + { + /* stereo */ + if(bits == 8) + { + p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_8S_ToBT_Filtered; + p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_8S_ToBT_NoFilter; + } + else + { + p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_16S_ToBT_Filtered; + p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_16S_ToBT_NoFilter; + p_cb->divisor = 4; + } + } + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG2("bta_pcm_init_dwn_sample: cur_pos %d, src_sps %d", \ + p_cb->cur_pos, p_cb->src_sps); + APPL_TRACE_DEBUG3("bta_pcm_init_dwn_sample: bits %d, n_channels %d, sample_size %d, ", \ + p_cb->bits, p_cb->n_channels, p_cb->sample_size); + APPL_TRACE_DEBUG3("bta_pcm_init_dwn_sample: can_be_filtered %d, n_channels: %d, \ + divisor %d", p_cb->can_be_filtered, p_cb->n_channels, p_cb->divisor); +#endif + +} + +/************************************************************************************** +** Function BTA_DmPcmResample +** +** Description Down sampling utility to convert higher sampling rate into 8K/16bits +** PCM samples. +** +** Parameters p_src: pointer to the buffer where the original sampling PCM +** are stored. +** in_bytes: Length of the input PCM sample buffer in byte. +** p_dst: pointer to the buffer which is to be used to store +** the converted PCM samples. +** +** +** Returns INT32: number of samples converted. +** +**************************************************************************************/ +INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst) +{ + UINT32 out_sample; + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG1("bta_pcm_resample : insamples %d", (in_bytes / bta_dm_pcm_cb.divisor)); +#endif + if(bta_dm_pcm_cb.can_be_filtered) + { + out_sample = (*bta_dm_pcm_cb.filter) (p_src, p_dst, (in_bytes / bta_dm_pcm_cb.divisor), + bta_dm_pcm_cb.src_sps, (INT32 *) &bta_dm_pcm_cb.cur_pos, bta_dm_pcm_cb.overlap_area); + } + else + { + out_sample = (*bta_dm_pcm_cb.nofilter) (p_src, p_dst, + (in_bytes / bta_dm_pcm_cb.divisor), bta_dm_pcm_cb.src_sps); + } + +#if BTA_DM_SCO_DEBUG + APPL_TRACE_DEBUG1("bta_pcm_resample : outsamples %d", out_sample); +#endif + + return (out_sample * bta_dm_pcm_cb.sample_size); +} +#endif diff --git a/bta/fs/bta_fs_cfg.c b/bta/fs/bta_fs_cfg.c new file mode 100644 index 0000000..0bfffcd --- /dev/null +++ b/bta/fs/bta_fs_cfg.c @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains compile-time configurable constants for the BTA File + * System. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "bta_fs_api.h" + +/* Character used as path separator */ +#ifndef BTA_FS_PATH_SEPARATOR +#define BTA_FS_PATH_SEPARATOR ((char) 0x2f) /* 0x2f ('/'), or 0x5c ('\') */ +#endif + +/* Maximum path length supported by MMI */ +#ifndef BTA_FS_PATH_LEN +#define BTA_FS_PATH_LEN 294 +#endif + +#ifndef BTA_FS_FILE_LEN +#define BTA_FS_FILE_LEN 256 +#endif + +const tBTA_FS_CFG bta_fs_cfg = +{ + BTA_FS_FILE_LEN, + BTA_FS_PATH_LEN, + BTA_FS_PATH_SEPARATOR +}; + +tBTA_FS_CFG *p_bta_fs_cfg = (tBTA_FS_CFG *)&bta_fs_cfg; + diff --git a/bta/fs/bta_fs_ci.c b/bta/fs/bta_fs_ci.c new file mode 100644 index 0000000..589a591 --- /dev/null +++ b/bta/fs/bta_fs_ci.c @@ -0,0 +1,280 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 file system call-in functions. + * + ******************************************************************************/ +#include <string.h> + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_fs_ci.h" +#include "gki.h" +#include "bd.h" + +/******************************************************************************* +** +** Function bta_fs_ci_write +** +** Description This function sends an event to IO indicating the phone +** has written the number of bytes specified in the call-out +** function, bta_fs_co_write(), and is ready for more data. +** This function is used to control the TX data flow. +** Note: The data buffer is released by the stack after +** calling this function. +** +** Parameters fd - file descriptor passed to the stack in the +** bta_fs_ci_open call-in function. +** status - BTA_FS_CO_OK or BTA_FS_CO_FAIL +** +** Returns void +** +*******************************************************************************/ +void bta_fs_ci_write(int fd, tBTA_FS_CO_STATUS status, UINT16 evt) +{ + tBTA_FS_CI_WRITE_EVT *p_evt; + + if ((p_evt = (tBTA_FS_CI_WRITE_EVT *) GKI_getbuf(sizeof(tBTA_FS_CI_WRITE_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->fd = fd; + p_evt->status = status; + + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_fs_ci_read +** +** Description This function sends an event to BTA indicating the phone has +** read in the requested amount of data specified in the +** bta_fs_co_read() call-out function. It should only be called +** when the requested number of bytes has been read in, or after +** the end of the file has been detected. +** +** Parameters fd - file descriptor passed to the stack in the +** bta_fs_ci_open call-in function. +** num_bytes_read - number of bytes read into the buffer +** specified in the read callout-function. +** status - BTA_FS_CO_OK if full buffer of data, +** BTA_FS_CO_EOF if the end of file has been reached, +** BTA_FS_CO_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_ci_read(int fd, UINT16 num_bytes_read, tBTA_FS_CO_STATUS status, UINT16 evt) +{ + tBTA_FS_CI_READ_EVT *p_evt; + + if ((p_evt = (tBTA_FS_CI_READ_EVT *) GKI_getbuf(sizeof(tBTA_FS_CI_READ_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->fd = fd; + p_evt->status = status; + p_evt->num_read = num_bytes_read; + + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_fs_ci_open +** +** Description This function sends an event to BTA indicating the phone has +** finished opening a file for reading or writing. +** +** Parameters fd - file descriptor passed to the stack in the +** bta_fs_ci_open call-in function. +** status - BTA_FS_CO_OK if file was opened in mode specified +** in the call-out function. +** BTA_FS_CO_EACCES if the file exists, but contains +** the wrong access permissions. +** BTA_FS_CO_FAIL if any other error has occurred. +** file_size - The total size of the file +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_ci_open(int fd, tBTA_FS_CO_STATUS status, UINT32 file_size, UINT16 evt) +{ + tBTA_FS_CI_OPEN_EVT *p_evt; + + if ((p_evt = (tBTA_FS_CI_OPEN_EVT *) GKI_getbuf(sizeof(tBTA_FS_CI_OPEN_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->fd = fd; + p_evt->status = status; + p_evt->file_size = file_size; + p_evt->p_file = NULL; + + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_fs_ci_direntry +** +** Description This function is called in response to the +** bta_fs_co_getdirentry call-out function. +** +** Parameters status - BTA_FS_CO_OK if p_entry points to a valid entry. +** BTA_FS_CO_EODIR if no more entries (p_entry is ignored). +** BTA_FS_CO_FAIL if any errors have occurred. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_ci_direntry(tBTA_FS_CO_STATUS status, UINT16 evt) +{ + tBTA_FS_CI_GETDIR_EVT *p_evt; + + if ((p_evt = (tBTA_FS_CI_GETDIR_EVT *)GKI_getbuf(sizeof(tBTA_FS_CI_GETDIR_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_fs_ci_resume +** +** Description This function is called in response to the +** bta_fs_co_resume call-out function. +** +** Parameters p_sess_info - the stored session ID and related information. +** timeout - the timeout for this suspended session. +** ssn - the stored session sequence number. +** info - the stored BTA specific information (like last active operation). +** status - BTA_FS_CO_OK if p_entry points to a valid entry. +** BTA_FS_CO_FAIL if any errors have occurred. +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_ci_resume (BD_ADDR_PTR p_addr, UINT8 *p_sess_info, + UINT32 timeout, UINT32 offset, UINT8 ssn, UINT8 info, + tBTA_FS_CO_STATUS status, UINT16 evt) +{ + tBTA_FS_CI_RESUME_EVT *p_evt; + UINT16 size = sizeof(tBTA_FS_CI_RESUME_EVT) + sizeof(BD_ADDR); + + if ((p_evt = (tBTA_FS_CI_RESUME_EVT *)GKI_getbuf(size)) != NULL) + { + p_evt->p_addr = NULL; + if (p_addr != NULL) + { + p_evt->p_addr = (BD_ADDR_PTR)(p_evt + 1); + bdcpy(p_evt->p_addr, p_addr); + } + p_evt->hdr.event = evt; + p_evt->p_sess_info = p_sess_info; + p_evt->timeout = timeout; + p_evt->offset = offset; + p_evt->ssn = ssn; + p_evt->info = info; + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_fs_ci_action +** +** Description This function is called in response to one of the action +** call-out functions: bta_fs_co_copy, bta_fs_co_rename or +** bta_fs_co_set_perms. +** +** Parameters status - BTA_FS_CO_OK if the action is succession. +** BTA_FS_CO_FAIL if any errors have occurred. +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_ci_action(tBTA_FS_CO_STATUS status, UINT16 evt) +{ + tBTA_FS_CI_ACTION_EVT *p_evt; + + if ((p_evt = (tBTA_FS_CI_ACTION_EVT *) GKI_getbuf(sizeof(tBTA_FS_CI_ACTION_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->status = status; + + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_fs_ci_resume_op +** +** Description This function sends an event to BTA indicating the phone has +** finished opening a file for reading or writing on resume. +** +** Parameters fd - file descriptor passed to the stack in the +** bta_fs_ci_open call-in function. +** status - BTA_FS_CO_OK if file was opened in mode specified +** in the call-out function. +** BTA_FS_CO_EACCES if the file exists, but contains +** the wrong access permissions. +** BTA_FS_CO_FAIL if any other error has occurred. +** p_file - The file name associated with fd +** file_size - The total size of the file +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_fs_ci_resume_op(int fd, tBTA_FS_CO_STATUS status, const char *p_file, + UINT32 file_size, UINT16 evt) +{ + tBTA_FS_CI_OPEN_EVT *p_evt; + UINT16 file_len = strlen(p_file) + 1; + UINT16 size = sizeof(tBTA_FS_CI_OPEN_EVT) + file_len; + char *p; + + if ((p_evt = (tBTA_FS_CI_OPEN_EVT *) GKI_getbuf(size)) != NULL) + { + p_evt->hdr.event = evt; + p_evt->fd = fd; + p_evt->status = status; + p_evt->file_size = file_size; + p = (char *)(p_evt + 1); + BCM_STRNCPY_S (p, file_len, p_file, file_len-1); + p[file_len] = '\0'; + p_evt->p_file = (const char *)p; + + bta_sys_sendmsg(p_evt); + } +} diff --git a/bta/gatt/bta_gattc_act.c b/bta/gatt/bta_gattc_act.c new file mode 100644 index 0000000..5cacf03 --- /dev/null +++ b/bta/gatt/bta_gattc_act.c @@ -0,0 +1,1802 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the GATT client action functions for the state + * machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + + +#include "utl.h" +#include "gki.h" +#include "bd.h" +#include "bta_sys.h" + +#include "bta_gattc_int.h" +#include "l2c_api.h" + + +#include <string.h> + +/***************************************************************************** +** Constants +*****************************************************************************/ +static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason); + +static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, + tGATT_CL_COMPLETE *p_data); + +static tGATT_CBACK bta_gattc_cl_cback = +{ + bta_gattc_conn_cback, + bta_gattc_cmpl_cback, + bta_gattc_disc_res_cback, + bta_gattc_disc_cmpl_cback, + NULL +}; + +/* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */ +static UINT16 bta_gattc_opcode_to_int_evt[] = +{ + BTA_GATTC_API_READ_EVT, + BTA_GATTC_API_WRITE_EVT, + BTA_GATTC_API_EXEC_EVT +}; + +#if (BT_TRACE_VERBOSE == TRUE) +static const char *bta_gattc_op_code_name[] = +{ + "Unknown", + "Discovery", + "Read", + "Write", + "Exec", + "Config", + "Notification", + "Indication" +}; +#endif +/***************************************************************************** +** Action Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_gattc_register +** +** Description Register a GATT client application with BTA. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + UINT8 i; + tBT_UUID *p_app_uuid = &p_data->api_reg.app_uuid; + tBTA_GATTC_INT_START_IF *p_buf; + + + /* todo need to check duplicate uuid */ + for (i = 0; i < BTA_GATTC_CL_MAX; i ++) + { + if (!p_cb->cl_rcb[i].in_use) + { + if ((p_app_uuid == NULL) || (p_cb->cl_rcb[i].client_if = GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0) + { + APPL_TRACE_ERROR0("Register with GATT stack failed."); + cb_data.reg_oper.status = BTA_GATT_ERROR; + } + else + + { + p_cb->cl_rcb[i].in_use = TRUE; + p_cb->cl_rcb[i].p_cback = p_data->api_reg.p_cback; + memcpy(&p_cb->cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID)); + + /* BTA use the same client interface as BTE GATT statck */ + cb_data.reg_oper.client_if = p_cb->cl_rcb[i].client_if; +// btla-specific ++ + memcpy(&(cb_data.reg_oper.app_uuid),p_app_uuid,sizeof(tBT_UUID)); +// btla-specific -- + + cb_data.reg_oper.status = BTA_GATT_OK; + + if ((p_buf = (tBTA_GATTC_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTC_INT_START_IF))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT; + p_buf->client_if = p_cb->cl_rcb[i].client_if; + + bta_sys_sendmsg(p_buf); + } + else + { + cb_data.reg_oper.status = BTA_GATT_NO_RESOURCES; + memset( &p_cb->cl_rcb[i], 0 , sizeof(tBTA_GATTC_RCB)); + } + break; + } + } + } + /* callback with register event */ + if (p_data->api_reg.p_cback) + { + (*p_data->api_reg.p_cback)(BTA_GATTC_REG_EVT, (tBTA_GATTC *)&cb_data); + } +} + +/******************************************************************************* +** +** Function bta_gattc_start_if +** +** Description start an application interface. +** +** Returns none. +** +*******************************************************************************/ +void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_msg) +{ + if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) !=NULL ) + { + GATT_StartIf(p_msg->int_start_if.client_if); + } + else + { + APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.client_if ); + } +} + + +/******************************************************************************* +** +** Function bta_gattc_deregister_cmpl +** +** Description De-Register a GATT client application with BTA completed. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_int_deregister_cmpl(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_IF client_if) +{ + tBTA_GATTC_CBACK *p_cback = p_clreg->p_cback; + tBTA_GATTC cb_data; + + + APPL_TRACE_DEBUG1("bta_gattc_int_deregister_cmpl client_if=%d", client_if ); + + GATT_Deregister(p_clreg->client_if); + memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB)); + + cb_data.reg_oper.client_if = client_if; + cb_data.reg_oper.status = BTA_GATT_OK; + + if (p_cback) + /* callback with de-register event */ + (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC *)&cb_data); +} + + +/******************************************************************************* +** +** Function bta_gattc_deregister_cmpl +** +** Description De-Register a GATT client application with BTA completed. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_IF client_if) +{ + tBTA_GATTC_INT_DEREG *p_buf; + + APPL_TRACE_DEBUG1("bta_gattc_deregister_cmpl client_if=%d", client_if ); + + if ((p_buf = (tBTA_GATTC_INT_DEREG *) GKI_getbuf(sizeof(tBTA_GATTC_INT_DEREG))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_INT_DEREG_EVT; + p_buf->client_if = client_if; + bta_sys_sendmsg(p_buf); + } + else + { + APPL_TRACE_ERROR1("bta_gattc_deregister_cmpl unable to allocate buffer to complete dereg=%d", client_if); + } + +} + +/******************************************************************************* +** +** Function bta_gattc_deregister +** +** Description De-Register a GATT client application with BTA. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_int_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) +{ + + tBTA_GATTC_IF client_if = p_data->int_dereg.client_if; + tBTA_GATTC_CBACK *p_cback; + tBTA_GATTC cb_data; + tBTA_GATTC_RCB *p_clreg; + + + APPL_TRACE_DEBUG1("bta_gattc_int_deregister_cmpl client_if=%d", client_if ); + + if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) + { + p_cback = p_clreg->p_cback; + GATT_Deregister(client_if); + memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB)); + cb_data.reg_oper.client_if = client_if; + cb_data.reg_oper.status = BTA_GATT_OK; + + if (p_cback) + /* callback with de-register event */ + (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC *)&cb_data); + } + else + { + APPL_TRACE_ERROR1("bta_gattc_int_deregister Deregister Failed, unknown client_if: %d", p_data->int_dereg.client_if); + } +} + + +/******************************************************************************* +** +** Function bta_gattc_deregister +** +** Description De-Register a GATT client application with BTA. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_RCB *p_clreg; + UINT8 i; + BT_HDR buf; + + if ((p_clreg = bta_gattc_cl_get_regcb(p_data->api_dereg.client_if)) != NULL) + { + if (p_clreg->num_clcb > 0) + { + /* close all CLCB related to this app */ + for (i= 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].in_use && (p_cb->clcb[i].p_rcb == p_clreg)) + { + p_clreg->dereg_pending = TRUE; + + buf.event = BTA_GATTC_API_CLOSE_EVT; + buf.layer_specific = p_cb->clcb[i].bta_conn_id; + bta_gattc_close(&p_cb->clcb[i], (tBTA_GATTC_DATA *)&buf) ; + } + } + } + else + bta_gattc_deregister_cmpl(p_clreg, p_clreg->client_if); + } + else + { + APPL_TRACE_ERROR1("bta_gattc_deregister Deregister Failed, unknown client_if: %d", p_data->api_dereg.client_if); + } +} +/******************************************************************************* +** +** Function bta_gattc_process_api_open +** +** Description process connect API request. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + UINT16 event = ((BT_HDR *)p_msg)->event; + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if); + + if (p_clreg != NULL) + { + if (p_msg->api_conn.is_direct) + { + if ((p_clcb = bta_gattc_find_alloc_clcb(p_msg->api_conn.client_if, + p_msg->api_conn.remote_bda)) != NULL) + { + bta_gattc_sm_execute(p_clcb, event, p_msg); + } + else + { + APPL_TRACE_ERROR0("No resources to open a new connection."); + + bta_gattc_send_open_cback(p_clreg, + BTA_GATT_NO_RESOURCES, + p_msg->api_conn.remote_bda, + BTA_GATT_INVALID_CONN_ID); + } + } + else + { + bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg); + } + } + else + { + APPL_TRACE_ERROR1("bta_gattc_process_api_open Failed, unknown client_if: %d", + p_msg->api_conn.client_if); + } +} +/******************************************************************************* +** +** Function bta_gattc_process_api_open_cancel +** +** Description process connect API request. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) +{ + UINT16 event = ((BT_HDR *)p_msg)->event; + tBTA_GATTC_CLCB *p_clcb = NULL; + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + + if (p_msg->api_cancel_conn.is_direct) + { + if ((p_clcb = bta_gattc_find_clcb_by_cif(p_msg->api_cancel_conn.client_if, + p_msg->api_cancel_conn.remote_bda)) != NULL) + { + bta_gattc_sm_execute(p_clcb, event, p_msg); + } + else + { + APPL_TRACE_ERROR0("No such connection need to be cancelled"); + + p_clreg = bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if); + + if (p_clreg && p_clreg->p_cback) + { + (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + } + } + } + else + { + bta_gattc_cancel_bk_conn(&p_msg->api_cancel_conn); + + } +} + +/******************************************************************************* +** +** Function bta_gattc_cancel_open_error +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status=BTA_GATT_ERROR; + + if ( p_clcb->p_rcb->p_cback ) + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); +} + +/******************************************************************************* +** +** Function bta_gattc_open_error +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_ERROR0("Connection already opened. wrong state"); + + bta_gattc_send_open_cback(p_clcb->p_rcb, + BTA_GATT_ALREADY_OPEN, + p_clcb->bda, + p_clcb->bta_conn_id); +} +/******************************************************************************* +** +** Function bta_gattc_open_fail +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + bta_gattc_open_error(p_clcb, p_data); + /* open failure, remove clcb */ + bta_gattc_clcb_dealloc(p_clcb); +} + +/******************************************************************************* +** +** Function bta_gattc_open +** +** Description Process API connection function. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_DATA gattc_data; + + /* open/hold a connection */ + if (!GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda, TRUE)) + { + APPL_TRACE_ERROR0("Connection open failure"); + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data); + } + else + { + /* a connected remote device */ + if (GATT_GetConnIdIfConnected(p_clcb->p_rcb->client_if, + p_data->api_conn.remote_bda, + &p_clcb->bta_conn_id)) + { + gattc_data.hdr.layer_specific = p_clcb->bta_conn_id; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data); + } + /* else wait for the callback event */ + } +} +/******************************************************************************* +** +** Function bta_gattc_init_bk_conn +** +** Description Process API Open for a background connection +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg) +{ + tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES; + UINT16 conn_id; + tBTA_GATTC_CLCB *p_clcb; + tBTA_GATTC_DATA gattc_data; + + if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE)) + { + /* alwaya call open to hold a connection */ + if (!GATT_Connect(p_data->client_if, p_data->remote_bda, FALSE)) + { + status = BTA_GATT_ERROR; + APPL_TRACE_ERROR0("bta_gattc_init_bk_conn failed"); + } + else + { + status = BTA_GATT_OK; + + /* if is a connected remote device */ + if (GATT_GetConnIdIfConnected(p_data->client_if, + p_data->remote_bda, + &conn_id)) + { + if ((p_clcb = bta_gattc_clcb_alloc(p_data->client_if, p_data->remote_bda)) != NULL) + { + gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id; + + /* open connection */ + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data); + status = BTA_GATT_OK; + } + } + } + } + + /* open failure, report OPEN_EVT */ + if (status != BTA_GATT_OK) + { + bta_gattc_send_open_cback(p_clreg, status, p_data->remote_bda, BTA_GATT_INVALID_CONN_ID); + } +} +/******************************************************************************* +** +** Function bta_gattc_cancel_bk_conn +** +** Description Process API Cancel Open for a background connection +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + + /* remove the device from the bg connection mask */ + if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, FALSE)) + { + if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, FALSE)) + { + status = BTA_GATT_OK; + } + else + { + APPL_TRACE_ERROR0("bta_gattc_cancel_bk_conn failed"); + } + } + p_clreg = bta_gattc_cl_get_regcb(p_data->client_if); + + if (p_clreg && p_clreg->p_cback) + { + (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + } + +} +/******************************************************************************* +** +** Function bta_gattc_int_cancel_open_ok +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if ( p_clcb->p_rcb->p_cback ) + { + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + } + + bta_gattc_clcb_dealloc(p_clcb); +} + +/******************************************************************************* +** +** Function bta_gattc_cancel_open +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status=BTA_GATT_ERROR; + + if (GATT_CancelConnect(p_clcb->p_rcb->client_if, p_data->api_cancel_conn.remote_bda, TRUE)) + { + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data); + } + else + { + if ( p_clcb->p_rcb->p_cback ) + { + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, (tBTA_GATTC *)&status); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_conn +** +** Description receive connection callback from stack +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_IF gatt_if; + APPL_TRACE_DEBUG1("bta_gattc_conn server cache state=%d",p_clcb->p_srcb->state); + + if (p_data != NULL) + { + APPL_TRACE_DEBUG1("bta_gattc_conn conn_id=%d",p_data->hdr.layer_specific); + + p_clcb->p_srcb->connected = TRUE; + p_clcb->bta_conn_id = p_data->hdr.layer_specific; + GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda); + + /* start database cache if needed */ + if (p_clcb->p_srcb->p_srvc_cache == NULL) + { + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) + { + p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD; + bta_gattc_sm_execute(p_clcb, BTA_GATTC_START_CACHE_EVT, p_data); + } + else /* cache is building */ + p_clcb->state = BTA_GATTC_DISCOVER_ST; + } + + else + { + /* a pending service handle change indication */ + if (p_clcb->p_srcb->srvc_hdl_chg) + { + p_clcb->p_srcb->srvc_hdl_chg = FALSE; + /* start discovery */ + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + } + + if (p_clcb->p_rcb) + { + bta_gattc_send_open_cback(p_clcb->p_rcb, + BTA_GATT_OK, + p_clcb->bda, + p_clcb->bta_conn_id); + } + } +} + +/******************************************************************************* +** +** Function bta_gattc_close_fail +** +** Description close a connection. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC cb_data; + + if ( p_clcb->p_rcb->p_cback ) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + cb_data.close.client_if = p_clcb->p_rcb->client_if; + cb_data.close.conn_id = p_data->hdr.layer_specific; + bdcpy(cb_data.close.remote_bda, p_clcb->bda); + cb_data.close.status = BTA_GATT_ERROR; + cb_data.close.reason = BTA_GATT_CONN_NONE; + + + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CLOSE_EVT, &cb_data); + } +} +/******************************************************************************* +** +** Function bta_gattc_api_close +** +** Description close a GATTC connection. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_CBACK *p_cback = p_clcb->p_rcb->p_cback; + tBTA_GATTC_RCB *p_clreg = p_clcb->p_rcb; + tBTA_GATTC cb_data; + + APPL_TRACE_DEBUG1("bta_gattc_close conn_id=%d",p_clcb->bta_conn_id); + + if (p_data->hdr.event == BTA_GATTC_API_CLOSE_EVT) + p_clcb->status = GATT_Disconnect(p_clcb->bta_conn_id); + + cb_data.close.client_if = p_clcb->p_rcb->client_if; + cb_data.close.conn_id = p_clcb->bta_conn_id; + cb_data.close.status = p_clcb->status; + cb_data.close.reason = p_clcb->reason; + bdcpy(cb_data.close.remote_bda, p_clcb->bda); + + if (p_clcb->status == BTA_GATT_OK) + { + /* if the srcb is no longer needed, reset the state */ + if ( -- p_clcb->p_srcb->num_clcb == 0) + { + APPL_TRACE_DEBUG0("Update srcb connection status"); + p_clcb->p_srcb->connected = FALSE; + p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE; + } + + bta_gattc_clcb_dealloc(p_clcb); + } + + ( * p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC *)&cb_data); + + if (-- p_clreg->num_clcb == 0 && p_clreg->dereg_pending) + { + bta_gattc_deregister_cmpl(p_clreg, p_clreg->client_if); + } + +} + +/******************************************************************************* +** +** Function bta_gattc_reset_discover_st +** +** Description when a SRCB finished discovery, tell all related clcb. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_reset_discover_st(tBTA_GATTC_SERV *p_srcb) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].p_srcb == p_srcb) + { + bta_gattc_sm_execute(&p_cb->clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT, NULL); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_set_discover_st +** +** Description when a SRCB start discovery, tell all related clcb and set +** the state. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_set_discover_st(tBTA_GATTC_SERV *p_srcb) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + UINT8 i; + +#if BLE_INCLUDED == TRUE + L2CA_EnableUpdateBleConnParams(p_srcb->server_bda, FALSE); +#endif + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (p_cb->clcb[i].p_srcb == p_srcb) + { + p_cb->clcb[i].state = BTA_GATTC_DISCOVER_ST; + } + } +} +/******************************************************************************* +** +** Function bta_gattc_start_discover +** +** Description Start a discovery on server. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + /* pending operation, wait until it finishes */ + + APPL_TRACE_DEBUG1("bta_gattc_start_discover conn_id=%d",p_clcb->bta_conn_id); + if (p_clcb->p_q_cmd != NULL && p_clcb->auto_update == BTA_GATTC_NO_SCHEDULE && + p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) + { + p_clcb->auto_update = BTA_GATTC_DISC_WAITING; + p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */ + } + else /* no pending operation, start discovery right away */ + { + p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE; + + if (p_clcb->p_srcb != NULL) + { + /* clear the service change mask */ + p_clcb->p_srcb->srvc_hdl_chg = FALSE; + p_clcb->p_srcb->update_count = 0; + + /* set all srcb related clcb into discovery ST */ + bta_gattc_set_discover_st(p_clcb->p_srcb); + + if ( bta_gattc_init_cache(p_clcb->p_srcb) || + bta_gattc_discover_pri_service(p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL) != BTA_GATT_OK) + { + APPL_TRACE_ERROR0("discovery on server failed"); + bta_gattc_reset_discover_st(p_clcb->p_srcb); + } + } + else + { + APPL_TRACE_ERROR0("unknown device, can not start discovery"); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_disc_cmpl +** +** Description discovery on server is finished +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_DATA *p_q_cmd = p_clcb->p_q_cmd; + APPL_TRACE_DEBUG1("bta_gattc_disc_cmpl conn_id=%d",p_clcb->bta_conn_id); + +#if BLE_INCLUDED == TRUE + L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, TRUE); +#endif + p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE; + + /* release pending attribute list buffer */ + utl_freebuf((void **)&p_clcb->p_srcb->p_srvc_list); + + /* get any queued command to proceed */ + if (p_q_cmd != NULL) + { + p_clcb->p_q_cmd = NULL; + + bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd); + + utl_freebuf((void **)&p_q_cmd); + + } +} +/******************************************************************************* +** +** Function bta_gattc_read +** +** Description Read an attribute +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle = 0; + tGATT_READ_PARAM read_param; + tBTA_GATTC_OP_CMPL op_cmpl; + + memset (&read_param, 0 ,sizeof(tGATT_READ_PARAM)); + memset (&op_cmpl, 0 ,sizeof(tBTA_GATTC_OP_CMPL)); + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_read.srvc_id, + &p_data->api_read.char_id, + p_data->api_read.descr_type)) == 0) + { + op_cmpl.status = BTA_GATT_ERROR; + } + else + { + read_param.by_handle.handle = handle; + read_param.by_handle.auth_req = p_data->api_read.auth_req; + + op_cmpl.status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_HANDLE, &read_param); + } + + /* read fail */ + if (op_cmpl.status != BTA_GATT_OK) + { + op_cmpl.op_code = GATTC_OPTYPE_READ; + op_cmpl.p_cmpl = NULL; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_read_multi +** +** Description read multiple +** +** Returns None. +*********************************************************************************/ +void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 i, handle; + tBTA_GATT_STATUS status = BTA_GATT_OK; + tGATT_READ_PARAM read_param; + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATTC_ATTR_ID *p_id; + tBT_UUID dummy_uuid; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + memset(&dummy_uuid, 0, sizeof(tBT_UUID)); + memset(&read_param, 0, sizeof(tGATT_READ_PARAM)); + + p_id = p_data->api_read_multi.p_id_list; + + for (i = 0; i < p_data->api_read_multi.num_attr && p_id; i ++, p_id ++) + { + handle = 0; + + if (p_id->id_type == BTA_GATT_TYPE_CHAR) + { + handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_id->id_value.char_id.srvc_id, + &p_id->id_value.char_id.char_id, + dummy_uuid); + } + else if (p_id->id_type == BTA_GATT_TYPE_CHAR_DESCR) + { + handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_id->id_value.char_descr_id.char_id.srvc_id, + &p_id->id_value.char_descr_id.char_id.char_id, + p_id->id_value.char_descr_id.descr_type); + } + else + { + APPL_TRACE_ERROR1("invalud ID type: %d", p_id->id_type); + } + + if (handle == 0) + { + status = BTA_GATT_ERROR; + break; + } + } + if (status == BTA_GATT_OK) + { + read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr; + read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req; + + status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param); + } + + /* read fail */ + if (status != BTA_GATT_OK) + { + memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL)); + + op_cmpl.status = status; + op_cmpl.op_code = GATTC_OPTYPE_READ; + op_cmpl.p_cmpl = NULL; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_write +** +** Description Write an attribute +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle = 0; + tGATT_VALUE attr = {0}; + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_write.srvc_id, + &p_data->api_write.char_id, + p_data->api_write.descr_type)) == 0) + { + status = BTA_GATT_ERROR; + } + else + { + attr.handle= handle; + attr.offset = p_data->api_write.offset; + attr.len = p_data->api_write.len; + attr.auth_req = p_data->api_write.auth_req; + + if (p_data->api_write.p_value) + memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len); + + status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr); + } + + /* write fail */ + if (status != BTA_GATT_OK) + { + memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL)); + + op_cmpl.status = status; + op_cmpl.op_code = GATTC_OPTYPE_WRITE; + op_cmpl.p_cmpl = NULL; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_execute +** +** Description send execute write +** +** Returns None. +*********************************************************************************/ +void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATT_STATUS status; + + if (bta_gattc_enqueue(p_clcb, p_data)) + { + status = GATTC_ExecuteWrite(p_clcb->bta_conn_id, p_data->api_exec.is_execute); + + if (status != BTA_GATT_OK) + { + memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL)); + + op_cmpl.status = status; + op_cmpl.op_code = GATTC_OPTYPE_EXE_WRITE; + op_cmpl.p_cmpl = NULL; + + bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl); + } + } +} + +/******************************************************************************* +** +** Function bta_gattc_confirm +** +** Description send handle value confirmation +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT16 handle; + tBT_UUID null_uuid = {0}; + + if ((handle = bta_gattc_id2handle(p_clcb->p_srcb, + &p_data->api_confirm.srvc_id, + &p_data->api_confirm.char_id, + null_uuid)) == 0) + { + APPL_TRACE_ERROR0("Can not map service/char ID into valid handle"); + } + else + { + if (GATTC_SendHandleValueConfirm(p_data->api_confirm.hdr.layer_specific, handle) + != GATT_SUCCESS) + { + APPL_TRACE_ERROR1("bta_gattc_confirm to handle [0x%04x] failed", handle); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_read_cmpl +** +** Description read complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_read_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + UINT8 event; + tBTA_GATTC cb_data; + tBTA_GATT_READ_VAL read_value; + + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + memset(&read_value, 0, sizeof(tBTA_GATT_READ_VAL)); + + cb_data.read.status = p_data->status; + + if (p_data->p_cmpl != NULL && p_data->status == BTA_GATT_OK) + { + if (bta_gattc_handle2id(p_clcb->p_srcb, + p_data->p_cmpl->att_value.handle, + &cb_data.read.srvc_id, + &cb_data.read.char_id, + &cb_data.read.descr_type) == FALSE) + { + cb_data.read.status = BTA_GATT_INTERNAL_ERROR; + APPL_TRACE_ERROR1("can not map to GATT ID. handle = 0x%04x", p_data->p_cmpl->att_value.handle); + } + else + { + cb_data.read.status = bta_gattc_pack_read_cb_data(p_clcb->p_srcb, + cb_data.read.descr_type, + &p_data->p_cmpl->att_value, + &read_value); + cb_data.read.p_value = &read_value; + } + } + else + { + cb_data.read.srvc_id = p_clcb->p_q_cmd->api_read.srvc_id; + cb_data.read.char_id = p_clcb->p_q_cmd->api_read.char_id; + cb_data.read.descr_type = p_clcb->p_q_cmd->api_read.descr_type; + } + + event = (p_clcb->p_q_cmd->api_read.descr_type.len == 0) ? BTA_GATTC_READ_CHAR_EVT: BTA_GATTC_READ_DESCR_EVT; + cb_data.read.conn_id = p_clcb->bta_conn_id; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + /* read complete, callback */ + ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data); + +} +/******************************************************************************* +** +** Function bta_gattc_write_cmpl +** +** Description read complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_write_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + tBTA_GATTC cb_data = {0}; + UINT8 event; + + cb_data.write.status = p_data->status; + + if (p_data->p_cmpl != NULL) + { + bta_gattc_handle2id(p_clcb->p_srcb, p_data->p_cmpl->handle, + &cb_data.write.srvc_id, &cb_data.write.char_id, + &cb_data.write.descr_type); + } + else + { + cb_data.write.srvc_id = p_clcb->p_q_cmd->api_write.srvc_id; + cb_data.write.char_id = p_clcb->p_q_cmd->api_write.char_id; + cb_data.write.descr_type = p_clcb->p_q_cmd->api_write.descr_type; + } + + if (p_clcb->p_q_cmd->api_write.hdr.event == BTA_GATTC_API_WRITE_EVT && + p_clcb->p_q_cmd->api_write.write_type == BTA_GATTC_WRITE_PREPARE) + + event = BTA_GATTC_PREP_WRITE_EVT; + + else if (p_clcb->p_q_cmd->api_write.descr_type.len == 0) + + event = BTA_GATTC_WRITE_CHAR_EVT; + + else + event = BTA_GATTC_WRITE_DESCR_EVT; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + cb_data.write.conn_id = p_clcb->bta_conn_id; + /* write complete, callback */ + ( *p_clcb->p_rcb->p_cback)(event, (tBTA_GATTC *)&cb_data); + +} +/******************************************************************************* +** +** Function bta_gattc_exec_cmpl +** +** Description execute write complete +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_OP_CMPL *p_data) +{ + tBTA_GATTC cb_data; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + + p_clcb->status = BTA_GATT_OK; + + /* execute complete, callback */ + cb_data.exec_cmpl.conn_id = p_clcb->bta_conn_id; + cb_data.exec_cmpl.status = p_data->status; + + ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_EXEC_EVT, &cb_data); + +} + + +/******************************************************************************* +** +** Function bta_gattc_op_cmpl +** +** Description operation completed. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + UINT8 op = (UINT8)p_data->op_cmpl.op_code; + UINT8 mapped_op = 0; + + APPL_TRACE_DEBUG1("bta_gattc_op_cmpl op = %d", op); + + if (op == GATTC_OPTYPE_INDICATION || op == GATTC_OPTYPE_NOTIFICATION) + { + APPL_TRACE_ERROR0("unexpected operation, ignored"); + } + else if (op >= GATTC_OPTYPE_READ) + { + if (p_clcb->p_q_cmd == NULL) + { + APPL_TRACE_ERROR0("No pending command"); + return; + } + if (p_clcb->p_q_cmd->hdr.event != bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) + { + mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT + GATTC_OPTYPE_READ; + if ( mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0; + +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_ERROR3("expect op:(%s :0x%04x), receive unexpected operation (%s).", + bta_gattc_op_code_name[mapped_op] , p_clcb->p_q_cmd->hdr.event, + bta_gattc_op_code_name[op]); +#else + APPL_TRACE_ERROR3("expect op:(%u :0x%04x), receive unexpected operation (%u).", + mapped_op , p_clcb->p_q_cmd->hdr.event, op); +#endif + return; + } + + /* service handle change void the response, discard it */ + if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) + { + p_clcb->auto_update = BTA_GATTC_REQ_WAITING; + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + else if (op == GATTC_OPTYPE_READ) + bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl); + + else if (op == GATTC_OPTYPE_WRITE) + bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl); + + else if (op == GATTC_OPTYPE_EXE_WRITE) + bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl); + /* + else if (op == GATTC_OPTYPE_CONFIG) // API to be added + { + } + */ + } +} +/******************************************************************************* +** +** Function bta_gattc_op_cmpl +** +** Description operation completed. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + /* receive op complete when discovery is started, ignore the response, + and wait for discovery finish and resent */ + APPL_TRACE_DEBUG1("bta_gattc_ignore_op_cmpl op = %d", p_data->hdr.layer_specific); + +} +/******************************************************************************* +** +** Function bta_gattc_search +** +** Description start a search in the local server cache +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATT_STATUS status = GATT_INTERNAL_ERROR; + tBTA_GATTC cb_data; + APPL_TRACE_DEBUG1("bta_gattc_search conn_id=%d",p_clcb->bta_conn_id); + if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) + { + status = BTA_GATT_OK; + /* search the local cache of a server device */ + bta_gattc_search_service(p_clcb, p_data->api_search.srvc_uuid); + } + cb_data.search_cmpl.status = status; + cb_data.search_cmpl.conn_id = p_clcb->bta_conn_id; + + /* end of search or no server cache available */ + ( *p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_CMPL_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gattc_q_cmd +** +** Description enqueue a command into control block, usually because discovery +** operation is busy. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + bta_gattc_enqueue(p_clcb, p_data); +} +/******************************************************************************* +** +** Function bta_gattc_cache_open +** +** Description open a NV cache for loading +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + bta_gattc_set_discover_st(p_clcb->p_srcb); + + APPL_TRACE_DEBUG1("bta_gattc_cache_open conn_id=%d",p_clcb->bta_conn_id); + bta_gattc_co_cache_open(p_clcb->p_srcb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT, + p_clcb->bta_conn_id, FALSE); +} +/******************************************************************************* +** +** Function bta_gattc_start_load +** +** Description start cache loading by sending callout open cache +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_DEBUG2("bta_gattc_ci_open conn_id=%d server state=%d" , + p_clcb->bta_conn_id, p_clcb->p_srcb->state); + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_LOAD) + { + if (p_data->ci_open.status == BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda, + BTA_GATTC_CI_CACHE_LOAD_EVT, + p_clcb->p_srcb->attr_index, + p_clcb->bta_conn_id); + } + else + { + /* cache open failure, start discovery */ + bta_gattc_start_discover(p_clcb, NULL); + } + } + if (p_clcb->p_srcb->state == BTA_GATTC_SERV_SAVE) + { + if (p_data->ci_open.status == BTA_GATT_OK) + { + if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id)) + { + p_data->ci_open.status = BTA_GATT_ERROR; + } + } + if (p_data->ci_open.status != BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, p_clcb->bta_conn_id); + bta_gattc_reset_discover_st(p_clcb->p_srcb); + + } + } +} +/******************************************************************************* +** +** Function bta_gattc_ci_load +** +** Description cache loading received. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + + APPL_TRACE_DEBUG2("bta_gattc_ci_load conn_id=%d load status=%d" , + p_clcb->bta_conn_id, p_data->ci_load.status ); + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0); + + if ((p_data->ci_load.status == BTA_GATT_OK || + p_data->ci_load.status == BTA_GATT_MORE) && + p_data->ci_load.num_attr > 0) + { + bta_gattc_rebuild_cache(p_clcb->p_srcb, p_data->ci_load.num_attr, p_data->ci_load.attr, p_clcb->p_srcb->attr_index); + + if (p_data->ci_load.status == BTA_GATT_OK) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_reset_discover_st(p_clcb->p_srcb); + + } + else /* load more */ + { + p_clcb->p_srcb->attr_index += p_data->ci_load.num_attr; + + bta_gattc_co_cache_load(p_clcb->p_srcb->server_bda, + BTA_GATTC_CI_CACHE_LOAD_EVT, + p_clcb->p_srcb->attr_index, + p_clcb->bta_conn_id); + } + } + else + { + p_clcb->p_srcb->attr_index = 0; + /* cache open failure, start discovery */ + bta_gattc_start_discover(p_clcb, NULL); + } +} +/******************************************************************************* +** +** Function bta_gattc_ci_load +** +** Description cache loading received. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + APPL_TRACE_DEBUG1("bta_gattc_ci_save conn_id=%d " , + p_clcb->bta_conn_id ); + + if (!bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id)) + { + p_clcb->p_srcb->attr_index = 0; + bta_gattc_co_cache_close(p_clcb->p_srcb->server_bda, 0); + bta_gattc_reset_discover_st(p_clcb->p_srcb); + } +} + +/******************************************************************************* +** +** Function bta_gattc_fail +** +** Description report API call failure back to apps +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + if (p_clcb->status == BTA_GATT_OK) + { + APPL_TRACE_ERROR1("operation not supported at current state [%d]", p_clcb->state); + } +} +/******************************************************************************* +** +** Function bta_gattc_conn_cback +** bta_gattc_cmpl_cback +** +** Description callback functions to GATT client stack. +** +** Returns void +** +*******************************************************************************/ +static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason) +{ + BT_HDR *p_buf; + tBTA_GATTC_CLCB *p_clcb = NULL; + + APPL_TRACE_DEBUG4("bta_gattc_conn_cback: cif = %d connected = %d conn_id = %d reaosn = 0x%04x", + gattc_if, connected, conn_id, reason); + + if (connected) + { + /* outgoing connection : locate a logic channel */ + if ((p_clcb = bta_gattc_find_clcb_by_cif(gattc_if, bda)) == NULL) + { + +#if BLE_INCLUDED == TRUE + /* for a background connection */ + if (L2CA_GetBleConnRole(bda)== HCI_ROLE_MASTER && + bta_gattc_check_bg_conn(gattc_if, bda)) + { + /* allocate a new channel */ + p_clcb = bta_gattc_clcb_alloc(gattc_if, bda); + } +#endif + } + if (p_clcb != NULL) + { + p_clcb->bta_conn_id = conn_id; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTC_INT_CONN_EVT; + p_buf->layer_specific = conn_id; + + bta_sys_sendmsg(p_buf); + } + } + } + else + { + /* connection attempt timeout, send connection callback event */ + if (reason == GATT_CONN_CANCEL ) + { + p_clcb = bta_gattc_clcb_alloc(gattc_if, bda); + p_clcb->bta_conn_id = conn_id; + } + if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) != NULL) + { + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTC_INT_DISCONN_EVT; + p_buf->layer_specific = conn_id; + p_clcb->reason = reason; + + bta_sys_sendmsg(p_buf); + } + } + else + { + APPL_TRACE_DEBUG1(" connection ID: [%d] not used by BTA", conn_id); + } + } +} +/******************************************************************************* +** +** Function bta_gattc_process_srvc_chg_ind +** +** Description process service change indication. +** +** Returns None. +** +*******************************************************************************/ +BOOLEAN bta_gattc_process_srvc_chg_ind(UINT16 conn_id, + tBTA_GATTC_RCB *p_clrcb, + tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_CLCB *p_clcb, + tBTA_GATTC_NOTIFY *p_notify, + UINT16 handle) +{ + tBT_UUID gattp_uuid, srvc_chg_uuid; + BOOLEAN processed = FALSE; + UINT8 i; + + gattp_uuid.len = 2; + gattp_uuid.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER; + + srvc_chg_uuid.len = 2; + srvc_chg_uuid.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD; + + if (bta_gattc_uuid_compare(p_notify->char_id.srvc_id.id.uuid, gattp_uuid, TRUE) && + bta_gattc_uuid_compare(p_notify->char_id.char_id.uuid, srvc_chg_uuid, TRUE)) + { + processed = TRUE; + /* mark service handle change pending */ + p_srcb->srvc_hdl_chg = TRUE; + /* clear up all notification/indication registration */ + bta_gattc_clear_notif_registration(conn_id); + /* service change indication all received, do discovery update */ + if ( ++ p_srcb->update_count == bta_gattc_num_reg_app()) + { + /* not an opened connection; or connection busy */ + /* search for first available clcb and start discovery */ + if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) + { + for (i = 0 ; i < BTA_GATTC_CLCB_MAX; i ++) + { + if (bta_gattc_cb.clcb[i].in_use && + bta_gattc_cb.clcb[i].p_srcb == p_srcb && + bta_gattc_cb.clcb[i].p_q_cmd == NULL) + { + p_clcb = &bta_gattc_cb.clcb[i]; + break; + } + } + } + /* send confirmation here if this is an indication, it should always be */ + GATTC_SendHandleValueConfirm(conn_id, handle); + + /* if connection available, refresh cache by doing discovery now */ + if (p_clcb != NULL) + bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL); + } + /* notify applicationf or service change */ + if (p_clrcb->p_cback != NULL) + { + APPL_TRACE_ERROR0("bta_gattc_process_srvc_chg_ind 2"); + (* p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT, (tBTA_GATTC *)p_srcb->server_bda); + } + + } + + return processed; + +} +/******************************************************************************* +** +** Function bta_gattc_proc_other_indication +** +** Description process all non-service change indication/notification. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB *p_clcb, UINT8 op, + tGATT_CL_COMPLETE *p_data, + tBTA_GATTC_NOTIFY *p_notify) +{ + APPL_TRACE_DEBUG2("bta_gattc_proc_other_indication check \ + p_data->att_value.handle=%d p_data->handle=%d", + p_data->att_value.handle, p_data->handle); + APPL_TRACE_DEBUG1("is_notify", p_notify->is_notify); + + p_notify->is_notify = (op == GATTC_OPTYPE_INDICATION) ? FALSE : TRUE; + p_notify->len = p_data->att_value.len; + bdcpy(p_notify->bda, p_clcb->bda); + memcpy(p_notify->value, p_data->att_value.value, p_data->att_value.len); + p_notify->conn_id = p_clcb->bta_conn_id; + + if (p_clcb->p_rcb->p_cback) + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC *)p_notify); + +} +/******************************************************************************* +** +** Function bta_gattc_process_indicate +** +** Description process indication/notification. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_process_indicate(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_CL_COMPLETE *p_data) +{ + UINT16 handle = p_data->att_value.handle; + tBTA_GATTC_CLCB *p_clcb ; + tBTA_GATTC_RCB *p_clrcb = NULL; + tBTA_GATTC_SERV *p_srcb = NULL; + tBTA_GATTC_NOTIFY notify; + BD_ADDR remote_bda; + tBTA_GATTC_IF gatt_if; + + if (!GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda)) + { + APPL_TRACE_ERROR0("indication/notif for unknown app"); + return; + } + + if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) == NULL) + { + APPL_TRACE_ERROR0("indication/notif for unregistered app"); + return; + } + + if ((p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL) + { + APPL_TRACE_ERROR0("indication/notif for unknown device, ignore"); + return; + } + + p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + if (bta_gattc_handle2id(p_srcb, handle, + ¬ify.char_id.srvc_id, + ¬ify.char_id.char_id, + ¬ify.descr_type)) + { + /* if non-service change indication/notification, forward to application */ + if (!bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, ¬ify, handle)) + { + /* if app registered for the notification */ + if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, ¬ify)) + { + /* connection not open yet */ + if (p_clcb == NULL) + { + if ((p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda)) != NULL) + { + p_clcb->bta_conn_id = conn_id; + + /* send connection event */ + bta_gattc_send_open_cback(p_clrcb, + BTA_GATT_OK, + remote_bda, + conn_id); + } + else + { + APPL_TRACE_ERROR0("No resources"); + } + } + + if (p_clcb != NULL) + bta_gattc_proc_other_indication(p_clcb, op, p_data, ¬ify); + } + /* no one intersted and need ack? */ + else if (op == GATTC_OPTYPE_INDICATION) + { + APPL_TRACE_DEBUG0("no one interested, ack now"); + GATTC_SendHandleValueConfirm(conn_id, handle); + } + } + } + else + { + APPL_TRACE_ERROR1("Indi/Notif for Unknown handle[0x%04x], can not find in local cache.", handle); + } +} + +/******************************************************************************* +** +** Function bta_gattc_cmpl_cback +** +** Description client operation complete callback register with BTE GATT. +** +** Returns None. +** +*******************************************************************************/ +static void bta_gattc_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, + tGATT_CL_COMPLETE *p_data) +{ + tBTA_GATTC_CLCB *p_clcb ; + tBTA_GATTC_OP_CMPL *p_buf; + UINT16 len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE); + + APPL_TRACE_DEBUG3("bta_gattc_cmpl_cback: conn_id = %d op = %d status = %d", + conn_id, op, status); + + /* notification and indication processed right away */ + if (op == GATTC_OPTYPE_NOTIFICATION || op == GATTC_OPTYPE_INDICATION) + { + bta_gattc_process_indicate(conn_id, op, p_data); + return; + } + /* for all other operation, not expected if w/o connection */ + else if ((p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id)) == NULL) + { + APPL_TRACE_ERROR1("bta_gattc_cmpl_cback unknown conn_id = %d, ignore data", conn_id); + return; + } + + + if ((p_buf = (tBTA_GATTC_OP_CMPL *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + p_buf->hdr.event = BTA_GATTC_OP_CMPL_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->status = status; + p_buf->op_code = op; + + if (p_data != NULL) + { + p_buf->p_cmpl = (tGATT_CL_COMPLETE *)(p_buf + 1); + memcpy(p_buf->p_cmpl, p_data, sizeof(tGATT_CL_COMPLETE)); + } + + bta_sys_sendmsg(p_buf); + } + + return; +} +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_api.c b/bta/gatt/bta_gattc_api.c new file mode 100644 index 0000000..1cace7d --- /dev/null +++ b/bta/gatt/bta_gattc_api.c @@ -0,0 +1,934 @@ +/****************************************************************************** + * + * Copyright (C) 2010-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 of the API for GATT module of BTA. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gattc_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_gatt_reg = +{ + bta_gattc_hdl_event, + NULL /* need a disable functino to be called when BT is disabled */ +}; + +/******************************************************************************* +** +** Function BTA_GATTC_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTC module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_client_cb - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb) +{ + tBTA_GATTC_API_REG *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_GATTC, &bta_gatt_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_GATTC_API_REG *) GKI_getbuf(sizeof(tBTA_GATTC_API_REG))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_REG_EVT; + if (p_app_uuid != NULL) + memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID)); + p_buf->p_cback = p_client_cb; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_AppDeregister +** +** Description This function is called to deregister an application +** from BTA GATTC module. +** +** Parameters client_if - client interface identifier. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if) +{ + tBTA_GATTC_API_DEREG *p_buf; + + if ((p_buf = (tBTA_GATTC_API_DEREG *) GKI_getbuf(sizeof(tBTA_GATTC_API_DEREG))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_DEREG_EVT; + p_buf->client_if = client_if; + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Open +** +** Description Open a direct connection or add a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTC_API_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT; + + p_buf->client_if = client_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_CancelOpen +** +** Description Cancel a direct open connection or remove a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTC_API_CANCEL_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTC_API_CANCEL_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_CANCEL_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTC_API_CANCEL_OPEN_EVT; + + p_buf->client_if = client_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_Close +** +** Description Close a connection to a GATT server. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTC_Close(UINT16 conn_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTC_API_CLOSE_EVT; + + p_buf->layer_specific = conn_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ServiceSearchRequest +** +** Description This function is called to request a GATT service discovery +** on a GATT server. This function report service search result +** by a callback event, and followed by a service search complete +** event. +** +** Parameters conn_id: connection ID. +** p_srvc_uuid: a UUID of the service application is interested in. +** If Null, discover for all services. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ServiceSearchRequest (UINT16 conn_id, tBT_UUID *p_srvc_uuid) +{ + tBTA_GATTC_API_SEARCH *p_buf; + UINT16 len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(tBT_UUID); + + if ((p_buf = (tBTA_GATTC_API_SEARCH *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_SEARCH_EVT; + p_buf->hdr.layer_specific = conn_id; + + if (p_srvc_uuid) + { + memcpy(&p_buf->srvc_uuid, p_srvc_uuid, sizeof(tBT_UUID)); + } + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstChar +** +** Description This function is called to find the first charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter to carry the characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstChar (UINT16 conn_id, tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property) +{ + tBTA_GATT_STATUS status; + + if (!p_srvc_id || !p_char_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR, p_srvc_id, NULL, + p_char_uuid_cond, &p_char_result->char_id, p_property)) + == BTA_GATT_OK) + { + memcpy(&p_char_result->srvc_id, p_srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; + +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextChar +** +** Description This function is called to find the next charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_char_id: start the characteristic search from the next record +** after the one identified by char_id. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter to carry the characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextChar (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_start_char_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property) +{ + tBTA_GATT_STATUS status; + + if (!p_start_char_id || !p_char_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR, + &p_start_char_id->srvc_id, + &p_start_char_id->char_id, + p_char_uuid_cond, + &p_char_result->char_id, + p_property)) + == BTA_GATT_OK) + { + memcpy(&p_char_result->srvc_id, &p_start_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstCharDescr +** +** Description This function is called to find the first charatceristic descriptor of the +** charatceristic on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_char_id: the characteristic ID of which the descriptor is belonged to. +** p_descr_uuid_cond: Characteristic Descr UUID, if NULL find the first available +** characteristic. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstCharDescr (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result) +{ + tBTA_GATT_STATUS status; + + if (!p_char_id || !p_descr_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + memset(p_descr_result, 0, sizeof(tBTA_GATTC_CHAR_DESCR_ID)); + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_CHAR_DESCR, + &p_char_id->srvc_id, + &p_char_id->char_id, + p_descr_uuid_cond, + &p_descr_result->char_id.char_id, + NULL)) + == BTA_GATT_OK) + { + memcpy(&p_descr_result->descr_type, &p_descr_result->char_id.char_id.uuid, sizeof(tBT_UUID)); + memcpy(&p_descr_result->char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID)); + } + + return status; + +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextCharDescr +** +** Description This function is called to find the next charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_descr_id: start the characteristic search from the next record +** after the one identified by p_start_descr_id. +** p_descr_uuid_cond: Characteristic descriptor UUID, if NULL find +** the first available characteristic descriptor. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_start_descr_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result) +{ + tBTA_GATT_STATUS status; + + if (!p_start_descr_id || !p_descr_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + memset(p_descr_result, 0, sizeof(tBTA_GATTC_CHAR_DESCR_ID)); + + if ((status = bta_gattc_query_cache(conn_id, BTA_GATTC_ATTR_TYPE_CHAR_DESCR, + &p_start_descr_id->char_id.srvc_id, + &p_start_descr_id->char_id.char_id, + p_descr_uuid_cond, + &p_descr_result->char_id.char_id, + (void *)&p_start_descr_id->descr_type)) + == BTA_GATT_OK) + { + memcpy(&p_descr_result->descr_type, &p_descr_result->char_id.char_id.uuid, sizeof(tBT_UUID)); + memcpy(&p_descr_result->char_id, p_start_descr_id, sizeof(tBTA_GATTC_CHAR_ID)); + } + + return status; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstIncludedService +** +** Description This function is called to find the first included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** p_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetFirstIncludedService(UINT16 conn_id, tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_uuid_cond, tBTA_GATTC_INCL_SVC_ID *p_result) +{ + tBTA_GATT_STATUS status; + + if (!p_srvc_id || !p_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_INCL_SRVC, + p_srvc_id, + NULL, + p_uuid_cond, + &p_result->incl_svc_id.id, + (tBTA_GATT_CHAR_PROP *)&p_result->incl_svc_id.is_primary)) + == BTA_GATT_OK) + { + memcpy(&p_result->srvc_id, p_srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} +/******************************************************************************* +** +** Function BTA_GATTC_GetNextIncludedService +** +** Description This function is called to find the next included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_id: start the search from the next record +** after the one identified by p_start_id. +** p_uuid_cond: Included service UUID, if NULL find the first available +** included service. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_GetNextIncludedService(UINT16 conn_id, + tBTA_GATTC_INCL_SVC_ID *p_start_id, + tBT_UUID *p_uuid_cond, + tBTA_GATTC_INCL_SVC_ID *p_result) +{ + tBTA_GATT_STATUS status; + + if (!p_start_id || !p_result) + return BTA_GATT_ILLEGAL_PARAMETER; + + if ((status = bta_gattc_query_cache(conn_id, + BTA_GATTC_ATTR_TYPE_INCL_SRVC, + &p_start_id->srvc_id, + &p_start_id->incl_svc_id.id, + p_uuid_cond, + &p_result->incl_svc_id.id, + (tBTA_GATT_CHAR_PROP *)&p_result->incl_svc_id.is_primary)) + == BTA_GATT_OK) + { + memcpy(&p_result->srvc_id, &p_start_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + } + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharacteristic +** +** Description This function is called to read a service's characteristics of +** the given characteritisc ID. +** +** Parameters conn_id - connectino ID. +** p_char_id - characteritic ID to read. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadCharacteristic(UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ *p_buf; + + if ((p_buf = (tBTA_GATTC_API_READ *) GKI_getbuf(sizeof(tBTA_GATTC_API_READ))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_READ)); + + p_buf->hdr.event = BTA_GATTC_API_READ_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharDescr +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters conn_id - connection ID. +** p_char_descr_id - characteritic descriptor ID to read. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_id, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ *p_buf; + + if ((p_buf = (tBTA_GATTC_API_READ *) GKI_getbuf(sizeof(tBTA_GATTC_API_READ))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_READ)); + + p_buf->hdr.event = BTA_GATTC_API_READ_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_descr_id->char_id.srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_descr_id->char_id.char_id, sizeof(tBTA_GATT_ID)); + memcpy(&p_buf->descr_type, &p_descr_id->descr_type, sizeof(tBT_UUID)); + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ReadMultiple +** +** Description This function is called to read multiple characteristic or +** characteristic descriptors. +** +** Parameters conn_id - connectino ID. +** p_read_multi - pointer to the read multiple parameter. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_read_multi, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_READ_MULTI *p_buf; + tBTA_GATTC_ATTR_ID *p_value; + UINT16 len = (UINT16)(sizeof(tBTA_GATTC_API_READ_MULTI) + + p_read_multi->num_attr * sizeof(tBTA_GATTC_ATTR_ID)); + UINT8 i; + + if ((p_buf = (tBTA_GATTC_API_READ_MULTI *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_READ_MULTI_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + p_buf->num_attr = p_read_multi->num_attr; + + if (p_buf->num_attr > 0) + { + p_buf->p_id_list = p_value = (tBTA_GATTC_ATTR_ID *)(p_buf + 1); + + for (i = 0; i < p_buf->num_attr; i ++, p_value ++) + { + memcpy(p_value, &p_read_multi->id_list[i], sizeof(tBTA_GATTC_ATTR_ID)); + } + } + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharValue +** +** Description This function is called to write characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to write. +** write_type - type of write. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_WriteCharValue ( UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATTC_WRITE_TYPE write_type, + UINT16 len, + UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + p_buf->write_type = write_type; + p_buf->len = len; + + if (p_value && len > 0) + { + p_buf->p_value = (UINT8 *)(p_buf + 1); + memcpy(p_buf->p_value, p_value, len); + } + + bta_sys_sendmsg(p_buf); + } + return; +} +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharDescr +** +** Description This function is called to write characteristic descriptor value. +** +** Parameters conn_id - connection ID +** p_char_descr_id - characteristic descriptor ID to write. +** write_type - write type. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_WriteCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id, + tBTA_GATTC_WRITE_TYPE write_type, + tBTA_GATT_UNFMT *p_data, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + UINT16 len = sizeof(tBTA_GATTC_API_WRITE) + p_data->len; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_descr_id->char_id.srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_descr_id->char_id.char_id, sizeof(tBTA_GATT_ID)); + memcpy(&p_buf->descr_type, &p_char_descr_id->descr_type, sizeof(tBT_UUID)); + p_buf->write_type = write_type; + + if (p_data && p_data->len != 0) + { + p_buf->p_value = (UINT8 *)(p_buf + 1); + p_buf->len = p_data->len; + /* pack the descr data */ + memcpy(p_buf->p_value, p_data->p_value, p_data->len); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_PrepareWrite +** +** Description This function is called to prepare write a characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - GATT characteritic ID of the service. +** offset - offset of the write value. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_PrepareWrite (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + UINT16 offset, UINT16 len, UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req) +{ + tBTA_GATTC_API_WRITE *p_buf; + + if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len); + + p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->auth_req = auth_req; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + p_buf->write_type = BTA_GATTC_WRITE_PREPARE; + p_buf->offset = offset; + p_buf->len = len; + + if (p_value && len > 0) + { + p_buf->p_value = (UINT8 *)(p_buf + 1); + memcpy(p_buf->p_value, p_value, len); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_ExecuteWrite +** +** Description This function is called to execute write a prepare write sequence. +** +** Parameters conn_id - connection ID. +** is_execute - execute or cancel. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute) +{ + tBTA_GATTC_API_EXEC *p_buf; + + if ((p_buf = (tBTA_GATTC_API_EXEC *) GKI_getbuf((UINT16)sizeof(tBTA_GATTC_API_EXEC))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_EXEC)); + + p_buf->hdr.event = BTA_GATTC_API_EXEC_EVT; + p_buf->hdr.layer_specific = conn_id; + + p_buf->is_execute = is_execute; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTC_SendIndConfirm +** +** Description This function is called to send handle value confirmation. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to confirm. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTC_SendIndConfirm (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_API_CONFIRM *p_buf; + + APPL_TRACE_API3("BTA_GATTC_SendIndConfirm conn_id=%d service uuid1=0x%x char uuid=0x%x", + conn_id, p_char_id->srvc_id.id.uuid.uu.uuid16, p_char_id->char_id.uuid.uu.uuid16); //toto + + if ((p_buf = (tBTA_GATTC_API_CONFIRM *) GKI_getbuf(sizeof(tBTA_GATTC_API_CONFIRM))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTC_API_CONFIRM)); + + p_buf->hdr.event = BTA_GATTC_API_CONFIRM_EVT; + p_buf->hdr.layer_specific = conn_id; + + memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID)); + memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID)); + + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTC_RegisterForNotifications +** +** Description This function is called to register for notification of a service. +** +** Parameters client_if - client interface. +** bda - target GATT server. +** p_char_id - pointer to GATT characteristic ID. +** +** Returns OK if registration succeed, otherwise failed. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR bda, + tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + UINT8 i; + + if (!p_char_id) + { + APPL_TRACE_ERROR0("deregistration failed, unknow char id"); + return status; + } + + /* lock other GKI task */ + GKI_sched_lock(); + + if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) + { + for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (!p_clreg->notif_reg[i].in_use) + { + memset(&p_clreg->notif_reg, 0, sizeof(tBTA_GATTC_NOTIF_REG)); + + p_clreg->notif_reg[i].in_use = TRUE; + memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN); + memcpy(&p_clreg->notif_reg[i].char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID)); + + status = BTA_GATT_OK; + break; + } + } + if (i == BTA_GATTC_NOTIF_REG_MAX) + { + status = BTA_GATT_NO_RESOURCES; + APPL_TRACE_ERROR0("Max Notification Reached, registration failed."); + } + } + else + { + APPL_TRACE_ERROR1("Client_if: %d Not Registered", client_if); + } + + GKI_sched_unlock(); + + return status; +} + +/******************************************************************************* +** +** Function BTA_GATTC_DeregisterForNotifications +** +** Description This function is called to de-register for notification of a service. +** +** Parameters client_if - client interface. +** bda - target GATT server. +** p_char_id - pointer to GATT characteristic ID. +** +** Returns OK if deregistration succeed, otherwise failed. +** +*******************************************************************************/ +tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR bda, + tBTA_GATTC_CHAR_ID *p_char_id) +{ + tBTA_GATTC_RCB *p_clreg; + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + UINT8 i; + + if (!p_char_id) + { + APPL_TRACE_ERROR0("deregistration failed, unknow char id"); + return status; + } + + /* lock other GKI task */ + GKI_sched_lock(); + + if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL) + { + for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clreg->notif_reg[i].in_use && + !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) && + !memcmp(&p_clreg->notif_reg[i].char_id, p_char_id, sizeof(tBTA_GATTC_CHAR_ID))) + { + APPL_TRACE_DEBUG0("Deregistered."); + + memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); + status = BTA_GATT_OK; + break; + } + } + if (i == BTA_GATTC_NOTIF_REG_MAX) + { + status = BTA_GATT_ERROR; + + APPL_TRACE_ERROR0("registration not found"); + } + } + else + { + APPL_TRACE_ERROR1("Client_if: %d Not Registered", client_if); + } + + GKI_sched_unlock(); + + return status; +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_cache.c b/bta/gatt/bta_gattc_cache.c new file mode 100644 index 0000000..3774df4 --- /dev/null +++ b/bta/gatt/bta_gattc_cache.c @@ -0,0 +1,1597 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the GATT client discovery procedures and cache + * related functions. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "sdp_api.h" +#include "sdpdefs.h" +#include "bta_gattc_int.h" +#include "btm_api.h" + +static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb); +static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb); + +#define BTA_GATT_SDP_DB_SIZE 750 + +/***************************************************************************** +** Constants +*****************************************************************************/ + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) +static char *bta_gattc_attr_type[] = +{ + "I", /* Included Service */ + "C", /* Characteristic */ + "D" /* Characteristic Descriptor */ +}; +/* utility functions */ + +/******************************************************************************* +** +** Function bta_gattc_display_cache_server +** +** Description debug function to display the server cache. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gattc_display_cache_server(tBTA_GATTC_CACHE *p_cache) +{ + UINT8 i = 0, j; + tBTA_GATTC_CACHE *p_cur_srvc = p_cache; + tBTA_GATTC_CACHE_ATTR *p_attr; + + APPL_TRACE_ERROR0("<================Start Server Cache =============>"); + + while (p_cur_srvc) + { + APPL_TRACE_ERROR6("Service[%d]: handle[%d ~ %d] %s[0x%04x] inst[%d]", + i, p_cur_srvc->s_handle, p_cur_srvc->e_handle, + ((p_cur_srvc->service_uuid.id.uuid.len == 2) ? "uuid16" : "uuid128"), + p_cur_srvc->service_uuid.id.uuid.uu.uuid16, + p_cur_srvc->service_uuid.id.inst_id); + i ++; + + p_attr = p_cur_srvc->p_attr; + + for (j = 0; p_attr; j ++ ) + { + APPL_TRACE_ERROR6("\t Attr[0x%04x] handle[%d] uuid[0x%04x] inst[%d] type[%s] prop[0x%1x]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, + bta_gattc_attr_type[p_attr->attr_type], p_attr->property); + + p_attr = p_attr->p_next; + } + p_cur_srvc = p_cur_srvc->p_next; + } + + APPL_TRACE_ERROR0("<================End Server Cache =============>"); + APPL_TRACE_ERROR0(" "); +} + +/******************************************************************************* +** +** Function bta_gattc_display_explore_record +** +** Description debug function to display the exploration list +** +** Returns none. +** +*******************************************************************************/ +static void bta_gattc_display_explore_record(tBTA_GATTC_ATTR_REC *p_rec, UINT8 num_rec) +{ + UINT8 i; + tBTA_GATTC_ATTR_REC *pp = p_rec; + + APPL_TRACE_ERROR0("<================Start Explore Queue =============>"); + for (i = 0; i < num_rec; i ++, pp ++) + { + APPL_TRACE_ERROR5("\t rec[%d] uuid[0x%04x] s_handle[%d] e_handle[%d] is_primary[%d]", + i + 1, pp->uuid.uu.uuid16, pp->s_handle, pp->e_handle, pp->is_primary); + } + APPL_TRACE_ERROR0("<================ End Explore Queue =============>"); + APPL_TRACE_ERROR0(" "); + +} +#endif /* BTA_GATT_DEBUG == TRUE */ + + +/******************************************************************************* +** +** Function bta_gattc_alloc_cache_buf +** +** Description Allocate a GKI buffer for database cache. +** +** Returns status +** +*******************************************************************************/ +BT_HDR *bta_gattc_alloc_cache_buf(tBTA_GATTC_SERV *p_srvc_cb) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getpoolbuf(GATT_DB_POOL_ID)) == NULL) + { + APPL_TRACE_DEBUG0("No resources: GKI buffer allocation failed."); + utl_freebuf((void **)&p_srvc_cb->p_srvc_list); + p_srvc_cb->free_byte = 0; + } + else + { + memset(p_buf, 0, GKI_get_buf_size(p_buf)); + p_srvc_cb->p_free = (UINT8 *) p_buf; + p_srvc_cb->free_byte = GKI_get_buf_size(p_buf); + + /* link into buffer queue */ + GKI_enqueue(&p_srvc_cb->cache_buffer, p_buf); + } +#if BTA_GATT_DEBUG== TRUE + APPL_TRACE_DEBUG1("allocating new buffer: free byte = %d", p_srvc_cb->free_byte); +#endif + return p_buf; +} +/******************************************************************************* +** +** Function bta_gattc_init_cache +** +** Description Initialize the database cache and discovery related resources. +** +** Returns status +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATT_STATUS status = BTA_GATT_OK; + + while (p_srvc_cb->cache_buffer.p_first) + GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer)); + + utl_freebuf((void **)&p_srvc_cb->p_srvc_list); + + if ((p_srvc_cb->p_srvc_list = (tBTA_GATTC_ATTR_REC*)GKI_getbuf(BTA_GATTC_ATTR_LIST_SIZE)) == NULL) + { + APPL_TRACE_DEBUG0("No resources: GKI buffer allocation failed."); + status = GATT_NO_RESOURCES; + } + else + { + p_srvc_cb->total_srvc = 0; + p_srvc_cb->cur_srvc_idx = + p_srvc_cb->cur_char_idx = + p_srvc_cb->next_avail_idx = 0; + + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + { + status = GATT_NO_RESOURCES; + } + else + { + p_srvc_cb->p_cur_srvc = p_srvc_cb->p_srvc_cache = NULL; + } + } + + return status; +} +/******************************************************************************* +** +** Function bta_gattc_get_srvc_inst_id +** +** Description get service instance number +** +** Returns instance ID of the service. +** +*******************************************************************************/ +static UINT8 bta_gattc_get_srvc_inst_id(tBTA_GATTC_SERV *p_srvc_cb, tBT_UUID uuid) +{ + UINT8 i = 0, inst = 0; + tBTA_GATTC_ATTR_REC *p_srvc_rec; + + for (i = 0; i < p_srvc_cb->total_srvc; i ++) + /* + for (; i < p_srvc_cb->cur_srvc_idx; i ++)*/ + { + p_srvc_rec = p_srvc_cb->p_srvc_list + i; + + if (bta_gattc_uuid_compare(p_srvc_rec->uuid, uuid, TRUE)) + inst ++; + } + return inst ; +} +/******************************************************************************* +** +** Function bta_gattc_get_char_inst_id +** +** Description get characteristic instance number +** +** Returns characteristic instance ID. +** +*******************************************************************************/ +static UINT8 bta_gattc_get_char_inst_id(tBTA_GATTC_CACHE *p_service_cache, tBT_UUID uuid) +{ + UINT8 inst = 0; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBT_UUID attr_uuid; + + p_attr = p_service_cache->p_attr; + + while (p_attr) + { + bta_gattc_pack_attr_uuid(p_attr, &attr_uuid); + + if (bta_gattc_uuid_compare(attr_uuid, uuid, TRUE)) + inst ++; + + p_attr = p_attr->p_next; + } + return inst ; +} + +/******************************************************************************* +** +** Function bta_gattc_add_srvc_to_cache +** +** Description Add a service into database cache. +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_srvc_to_cache(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 s_handle, UINT16 e_handle, + tBT_UUID *p_uuid, + BOOLEAN is_primary, UINT8 srvc_inst) +{ + tBTA_GATTC_CACHE *p_new_srvc = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("Add a service into Service"); + APPL_TRACE_DEBUG2("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, sizeof(tBTA_GATTC_CACHE)) +#endif + + if (p_srvc_cb->free_byte < sizeof(tBTA_GATTC_CACHE)) + { + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + return GATT_NO_RESOURCES; + } + + p_new_srvc = (tBTA_GATTC_CACHE *)p_srvc_cb->p_free; + /* update service information */ + p_new_srvc->s_handle = s_handle; + p_new_srvc->e_handle = e_handle; + p_new_srvc->service_uuid.is_primary = is_primary; + memcpy(&p_new_srvc->service_uuid.id.uuid, p_uuid, sizeof(tBT_UUID)); + p_new_srvc->service_uuid.id.inst_id = srvc_inst; + p_new_srvc->p_next = NULL; + + if (p_srvc_cb->p_cur_srvc != NULL) + p_srvc_cb->p_cur_srvc->p_next = p_new_srvc; + p_srvc_cb->p_cur_srvc = p_new_srvc; + + /* first service */ + if (p_srvc_cb->p_srvc_cache == NULL) + p_srvc_cb->p_srvc_cache = p_new_srvc; + + /* update buffer managament info */ + p_srvc_cb->p_free += sizeof(tBTA_GATTC_CACHE); + p_srvc_cb->free_byte -= sizeof(tBTA_GATTC_CACHE); + + +#if 0 +//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); +#endif + return status; +} +/******************************************************************************* +** +** Function bta_gattc_add_attr_to_cache +** +** Description Add an attribute into database cache buffer. +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 handle, + tBT_UUID *p_uuid, + UINT8 property, + tBTA_GATTC_ATTR_TYPE type) +{ + tBTA_GATTC_CACHE_ATTR *p_attr; + tBTA_GATT_STATUS status = BTA_GATT_OK; + UINT16 len = sizeof(tBTA_GATTC_CACHE_ATTR) + p_uuid->len; + UINT8 *pp; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG1("bta_gattc_add_attr_to_cache: Add a [%s] into Service", bta_gattc_attr_type[type]); + APPL_TRACE_DEBUG4("handle=%d uuid16=0x%x property=0x%x type=%d", handle, p_uuid->uu.uuid16, property, type); + APPL_TRACE_DEBUG2("free byte = %d, req %d bytes.", p_srvc_cb->free_byte, len); +#endif + + if (p_srvc_cb->free_byte < len) + { + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + return GATT_NO_RESOURCES; + } + + p_attr = (tBTA_GATTC_CACHE_ATTR *)p_srvc_cb->p_free; + + p_attr->attr_handle = handle; + p_attr->attr_type = type; + p_attr->property = property; + p_attr->uuid_len = p_uuid->len; + p_attr->p_uuid = (tBTA_GATTC_UUID *)(p_attr + 1); + p_attr->p_next = NULL; + + pp = (UINT8 *)p_attr->p_uuid; + + if (p_uuid->len == LEN_UUID_16) + { + UINT16_TO_STREAM(pp, p_uuid->uu.uuid16); + } + else if (p_uuid->len == LEN_UUID_128) + { + memcpy(pp, p_uuid->uu.uuid128, LEN_UUID_128); + } + + if (type == BTA_GATTC_ATTR_TYPE_CHAR) + p_attr->inst_id = bta_gattc_get_char_inst_id(p_srvc_cb->p_cur_srvc, *p_uuid); + /* else: char descriptor, no instance ID needed */ + else /* TODO: --->> temp treat included service same as char descriptor */ + p_attr->inst_id = 0; + + /* update service information */ + p_srvc_cb->p_free += len; + p_srvc_cb->free_byte -= len; + + /* first attribute within the service, update the attribute pointer */ + if (p_srvc_cb->p_cur_srvc->p_attr == NULL) + { + p_srvc_cb->p_cur_srvc->p_attr = p_attr; + } + if (p_srvc_cb->p_cur_srvc->p_last_attr != NULL) + p_srvc_cb->p_cur_srvc->p_last_attr->p_next = p_attr; + + p_srvc_cb->p_cur_srvc->p_last_attr = p_attr; + +#if 0 +//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); +#endif + return status; +} + +/******************************************************************************* +** +** Function bta_gattc_get_disc_range +** +** Description get discovery stating and ending handle range. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_get_disc_range(tBTA_GATTC_SERV *p_srvc_cb, UINT16 *p_s_hdl, UINT16 *p_e_hdl, BOOLEAN is_srvc) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + + if (is_srvc) + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx; + *p_s_hdl = p_rec->s_handle; + } + else + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx; + *p_s_hdl = p_rec->s_handle + 1; + } + + *p_e_hdl = p_rec->e_handle; +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG2("discover range [%d ~ %d]",p_rec->s_handle, p_rec->e_handle); +#endif + return; +} +/******************************************************************************* +** +** Function bta_gattc_discover_pri_service +** +** Description Start primary service discovery +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type) +{ +#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) + tBT_DEVICE_TYPE dev_type; + tBLE_ADDR_TYPE addr_type; + + BTM_ReadDevInfo(p_server_cb->server_bda, &dev_type, &addr_type); + if (dev_type == BT_DEVICE_TYPE_BLE) + return bta_gattc_discover_procedure(conn_id, p_server_cb, disc_type); + else + return bta_gattc_sdp_service_disc(conn_id, p_server_cb); +#endif + return BTA_GATT_ERROR; + +} +/******************************************************************************* +** +** Function bta_gattc_discover_procedure +** +** Description Start a particular type of discovery procedure on server. +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type) +{ + tGATT_DISC_PARAM param; + BOOLEAN is_service = TRUE; + + memset(¶m, 0, sizeof(tGATT_DISC_PARAM)); + + if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID) + { + param.s_handle = 1; + param.e_handle = 0xFFFF; + } + else + { + if (disc_type == GATT_DISC_CHAR_DSCPT) + is_service = FALSE; + + bta_gattc_get_disc_range(p_server_cb, ¶m.s_handle, ¶m.e_handle, is_service); + + if (param.s_handle > param.e_handle) + { + APPL_TRACE_ERROR2("discover range invalid: [0x%04x ~ 0x%04x]", param.s_handle, param.e_handle); + + return GATT_ERROR; + } + } + return GATTC_Discover (conn_id, disc_type, ¶m); + +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_include_srvc +** +** Description Start discovery for included service +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_start_disc_include_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + APPL_TRACE_DEBUG0("starting discovery included service"); + + return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_INC_SRVC); +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_char +** +** Description Start discovery for characteristic +** +** Returns status of the operation. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_start_disc_char(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + p_srvc_cb->total_char = 0; + + APPL_TRACE_DEBUG0("starting discover characteristics"); + + return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR); +} +/******************************************************************************* +** +** Function bta_gattc_start_disc_char_dscp +** +** Description Start discovery for characteristic descriptor +** +** Returns none. +** +*******************************************************************************/ +void bta_gattc_start_disc_char_dscp(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + APPL_TRACE_DEBUG0("starting discover characteristics descriptor"); + + if (bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR_DSCPT) != 0) + bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb); + +} +/******************************************************************************* +** +** Function bta_gattc_explore_srvc +** +** Description process the service discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_explore_srvc(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx; + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + APPL_TRACE_DEBUG1("Start service discovery: srvc_idx = %d", p_srvc_cb->cur_srvc_idx); + + p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc; + + if (p_clcb == NULL) + { + APPL_TRACE_ERROR0("unknown connection ID"); + return; + } + /* start expore a service if there is service not been explored */ + if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc) + { + /* add the first service into cache */ + if (bta_gattc_add_srvc_to_cache (p_srvc_cb, + p_rec->s_handle, + p_rec->e_handle, + &p_rec->uuid, + p_rec->is_primary, + p_rec->srvc_inst_id) == 0) + { + /* start discovering included services */ + bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb); + return; + } + } + /* no service found at all, the end of server discovery*/ + APPL_TRACE_ERROR0("No More Service found"); + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache); +#endif + /* save cache to NV */ + p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE; + bta_gattc_co_cache_open(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_OPEN_EVT, + conn_id, TRUE); + //bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL); +} +/******************************************************************************* +** +** Function bta_gattc_incl_srvc_disc_cmpl +** +** Description process the relationship discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_incl_srvc_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + p_srvc_cb->cur_char_idx = p_srvc_cb->total_srvc; + + /* start discoverying characteristic */ + bta_gattc_start_disc_char(conn_id, p_srvc_cb); +} +/******************************************************************************* +** +** Function bta_gattc_char_disc_cmpl +** +** Description process the characteristic discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_char_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx; + + APPL_TRACE_DEBUG1("Total %d Char found ", p_srvc_cb->total_char); + + /* if there are characteristic needs to be explored */ + if (p_srvc_cb->total_char > 0) + { + /* add the first characteristic into cache */ + bta_gattc_add_attr_to_cache (p_srvc_cb, + p_rec->s_handle, + &p_rec->uuid, + p_rec->property, + BTA_GATTC_ATTR_TYPE_CHAR); + + /* start discoverying characteristic descriptor , if failed, disc for next char*/ + bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb); + } + else /* otherwise start with next service */ + { + p_srvc_cb->cur_srvc_idx ++; + + bta_gattc_explore_srvc (conn_id, p_srvc_cb); + } +} +/******************************************************************************* +** +** Function bta_gattc_char_dscpt_disc_cmpl +** +** Description process the char descriptor discovery complete event +** +** Returns status +** +*******************************************************************************/ +static void bta_gattc_char_dscpt_disc_cmpl(UINT16 conn_id, tBTA_GATTC_SERV *p_srvc_cb) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + + if (-- p_srvc_cb->total_char > 0) + { + p_rec = p_srvc_cb->p_srvc_list + (++ p_srvc_cb->cur_char_idx); + /* add the next characteristic into cache */ + bta_gattc_add_attr_to_cache (p_srvc_cb, + p_rec->s_handle, + &p_rec->uuid, + p_rec->property, + BTA_GATTC_ATTR_TYPE_CHAR); + + /* start discoverying next characteristic for char descriptor */ + bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb); + } + else + /* all characteristic has been explored, start with next service if any */ + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_ERROR0("all char has been explored"); +#endif + p_srvc_cb->cur_srvc_idx ++; + bta_gattc_explore_srvc (conn_id, p_srvc_cb); + } + +} +static BOOLEAN bta_gattc_srvc_in_list(tBTA_GATTC_SERV *p_srvc_cb, UINT16 s_handle, + UINT16 e_handle, tBT_UUID uuid) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + UINT8 i; + BOOLEAN exist_srvc = FALSE; + + if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle)) + { + APPL_TRACE_ERROR2("invalid included service handle: [0x%04x ~ 0x%04x]", s_handle, e_handle); + exist_srvc = TRUE; + } + else + { + for (i = 0; i < p_srvc_cb->next_avail_idx; i ++) + { + p_rec = p_srvc_cb->p_srvc_list + i; + + /* a new service should not have any overlap with other service handle range */ + if (p_rec->s_handle == s_handle || p_rec->e_handle == e_handle) + { + exist_srvc = TRUE; + break; + } + } + } + return exist_srvc; +} +/******************************************************************************* +** +** Function bta_gattc_add_srvc_to_list +** +** Description Add a service into explore pending list +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_srvc_to_list(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 s_handle, UINT16 e_handle, + tBT_UUID uuid, BOOLEAN is_primary) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) + { + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx; + + p_srvc_cb->total_srvc ++; + + APPL_TRACE_DEBUG2("bta_gattc_add_srvc_to_list handle = %d, service type = 0x%04x", + s_handle, uuid.uu.uuid16); + + p_rec->s_handle = s_handle; + p_rec->e_handle = e_handle; + p_rec->is_primary = is_primary; + p_rec->srvc_inst_id = bta_gattc_get_srvc_inst_id(p_srvc_cb, uuid); + memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID)); + + p_srvc_cb->next_avail_idx ++; + + } + else + { /* allocate bigger buffer ?? */ + status = GATT_DB_FULL; + + APPL_TRACE_ERROR0("char not added, no resources"); + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_add_char_to_list +** +** Description Add a characteristic into explore pending list +** +** Returns status +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_add_char_to_list(tBTA_GATTC_SERV *p_srvc_cb, + UINT16 decl_handle, UINT16 value_handle, + tBT_UUID uuid, UINT8 property) +{ + tBTA_GATTC_ATTR_REC *p_rec = NULL; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + if (p_srvc_cb->p_srvc_list == NULL) + { + APPL_TRACE_ERROR0("No service available, unexpected char discovery result"); + status = BTA_GATT_INTERNAL_ERROR; + } + else if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) + { + + p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx; + + p_srvc_cb->total_char ++; + + p_rec->s_handle = value_handle; + p_rec->property = property; + p_rec->e_handle = (p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx)->e_handle; + memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID)); + + /* update the endind handle of pervious characteristic if available */ + if (p_srvc_cb->total_char > 1) + { + p_rec -= 1; + p_rec->e_handle = decl_handle - 1; + } + p_srvc_cb->next_avail_idx ++; + } + else + { + APPL_TRACE_ERROR0("char not added, no resources"); + /* allocate bigger buffer ?? */ + status = BTA_GATT_DB_FULL; + } + return status; + +} +/******************************************************************************* +** +** Function bta_gattc_sdp_callback +** +** Description Process the discovery result from sdp +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_sdp_callback (UINT16 sdp_status) +{ + tSDP_DISC_REC *p_sdp_rec = NULL; + tBT_UUID service_uuid; + tSDP_PROTOCOL_ELEM pe; + UINT16 start_handle = 0, end_handle = 0; + tBTA_GATTC_SERV *p_srvc_cb = bta_gattc_find_scb_by_cid(bta_gattc_cb.sdp_conn_id); + + if(((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) && p_srvc_cb != NULL) + { + do + { + /* find a service record, report it */ + p_sdp_rec = SDP_FindServiceInDb(bta_gattc_cb.p_sdp_db, + 0, p_sdp_rec); + if (p_sdp_rec) + { + if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) + { + + if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT, &pe)) + { + start_handle = (UINT16) pe.params[0]; + end_handle = (UINT16) pe.params[1]; + +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_EVENT3("Found ATT service [0x%04x] handle[0x%04x ~ 0x%04x]", + service_uuid.uu.uuid16, start_handle, end_handle); +#endif + + if (GATT_HANDLE_IS_VALID(start_handle) && GATT_HANDLE_IS_VALID(end_handle) && + p_srvc_cb != NULL) + { + /* discover services result, add services into a service list */ + bta_gattc_add_srvc_to_list(p_srvc_cb, + start_handle, + end_handle, + service_uuid, + TRUE); + } + else + { + APPL_TRACE_ERROR2("invalid start_handle = %d end_handle = %d", start_handle, end_handle); + } + } + + + } + } + } while (p_sdp_rec); + } + + if ( p_srvc_cb != NULL) + /* start discover primary service */ + bta_gattc_explore_srvc(bta_gattc_cb.sdp_conn_id, p_srvc_cb); + else + { + APPL_TRACE_ERROR0("GATT service discovery is done on unknown connection"); + } + + GKI_freebuf(bta_gattc_cb.p_sdp_db); + bta_gattc_cb.p_sdp_db = NULL; + bta_gattc_cb.sdp_conn_id = 0; +} +/******************************************************************************* +** +** Function bta_gattc_sdp_service_disc +** +** Description Start DSP Service Discovert +** +** Returns void +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb) +{ + tSDP_UUID uuid; + UINT16 num_attrs = 2; + UINT16 attr_list[2]; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + + memset (&uuid, 0, sizeof(tSDP_UUID)); + + uuid.len = LEN_UUID_16; + uuid.uu.uuid16 = UUID_PROTOCOL_ATT; + + if((bta_gattc_cb.p_sdp_db = (tSDP_DISCOVERY_DB *)GKI_getbuf(BTA_GATT_SDP_DB_SIZE)) != NULL) + { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + + SDP_InitDiscoveryDb (bta_gattc_cb.p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, &uuid, num_attrs, attr_list); + + if(!SDP_ServiceSearchAttributeRequest (p_server_cb->server_bda, bta_gattc_cb.p_sdp_db, &bta_gattc_sdp_callback)) + { + GKI_freebuf(bta_gattc_cb.p_sdp_db); + bta_gattc_cb.p_sdp_db = NULL; + } + else + { + bta_gattc_cb.sdp_conn_id = conn_id; + status = BTA_GATT_OK; + } + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_disc_res_cback +** bta_gattc_disc_cmpl_cback +** +** Description callback functions to GATT client stack. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data) +{ + tBTA_GATTC_SERV * p_srvc_cb = NULL; + BOOLEAN pri_srvc; + + p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id); + + if (p_srvc_cb != NULL) + { + switch (disc_type) + { + case GATT_DISC_SRVC_ALL: + /* discover services result, add services into a service list */ + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->handle, + p_data->value.group_value.e_handle, + p_data->value.group_value.service_type, + TRUE); + + break; + case GATT_DISC_SRVC_BY_UUID: + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->handle, + p_data->value.handle, + p_data->type, + TRUE); + break; + + case GATT_DISC_INC_SRVC: + /* add included service into service list if it's secondary or it never showed up + in the primary service search */ + pri_srvc = bta_gattc_srvc_in_list(p_srvc_cb, + p_data->value.incl_service.s_handle, + p_data->value.incl_service.e_handle, + p_data->value.incl_service.service_type); + + if (!pri_srvc) + bta_gattc_add_srvc_to_list(p_srvc_cb, + p_data->value.incl_service.s_handle, + p_data->value.incl_service.e_handle, + p_data->value.incl_service.service_type, + FALSE); + /* add into database */ + bta_gattc_add_attr_to_cache(p_srvc_cb, + p_data->handle, + &p_data->value.incl_service.service_type, + pri_srvc, + BTA_GATTC_ATTR_TYPE_INCL_SRVC); + break; + + case GATT_DISC_CHAR: + /* add char value into database */ + bta_gattc_add_char_to_list(p_srvc_cb, + p_data->handle, + p_data->value.dclr_value.val_handle, + p_data->value.dclr_value.char_uuid, + p_data->value.dclr_value.char_prop); + break; + + case GATT_DISC_CHAR_DSCPT: + bta_gattc_add_attr_to_cache(p_srvc_cb, p_data->handle, &p_data->type, 0, BTA_GATTC_ATTR_TYPE_CHAR_DESCR); + break; + } + } +} +void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status) +{ + tBTA_GATTC_SERV * p_srvc_cb; + + p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id); + + if (p_srvc_cb != NULL) + { + switch (disc_type) + { + case GATT_DISC_SRVC_ALL: +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx); +#endif + bta_gattc_explore_srvc(conn_id, p_srvc_cb); + break; + + case GATT_DISC_INC_SRVC: + bta_gattc_incl_srvc_disc_cmpl(conn_id, p_srvc_cb); + + break; + + case GATT_DISC_CHAR: +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list, p_srvc_cb->next_avail_idx); +#endif + bta_gattc_char_disc_cmpl(conn_id, p_srvc_cb); + break; + + case GATT_DISC_CHAR_DSCPT: + bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb); + break; + } + } +} +/******************************************************************************* +** +** Function bta_gattc_id2handle +** +** Description map GATT ID to handle in a given cache. +** +** Returns the handle mapped. 0 if not found. +** +*******************************************************************************/ +UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_char_id, tBT_UUID descr_uuid) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC_CACHE_ATTR *p_attr; + UINT8 j; + UINT16 handle = 0; + tBT_UUID attr_uuid; + BOOLEAN char_map = FALSE, done = FALSE; + + while (p_cache && !done) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG3("Service: handle[%d] uuid[0x%04x] inst[%d]", + p_cache->s_handle, p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + p_attr = p_cache->p_attr; + + if (bta_gattc_uuid_compare(p_service_id->id.uuid, p_cache->service_uuid.id.uuid, TRUE) && + p_service_id->id.inst_id == p_cache->service_uuid.id.inst_id && + p_cache->service_uuid.is_primary == p_service_id->is_primary) + { + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG5("\t Attr[0x%04x] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, p_attr->attr_type); +#endif + bta_gattc_pack_attr_uuid(p_attr, &attr_uuid); + + if (bta_gattc_uuid_compare(p_char_id->uuid, attr_uuid, TRUE) && + p_char_id->inst_id == p_attr->inst_id) + { + if (descr_uuid.len == 0) + { + handle = p_attr->attr_handle; + done = TRUE; + break; + } + else + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("found matching characteristic for the descriptor"); +#endif + char_map = TRUE; + } + } + else if (char_map == TRUE) + { + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + + if (bta_gattc_uuid_compare(descr_uuid, attr_uuid, TRUE)) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("found descripotor!!"); +#endif + handle = p_attr->attr_handle; + done = TRUE; + break; + } + else + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("descriptor UUID not matching"); +#endif + } + } + else /* another char */ + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG0("no matching descriptor found!! start of next characteristic"); +#endif + char_map = FALSE; + done = TRUE; + break; + } + } + p_attr = p_attr->p_next; + } + } + p_cache = p_cache->p_next; + } + + return handle; +} +/******************************************************************************* +** +** Function bta_gattc_handle2id +** +** Description map a handle to GATT ID in a given cache. +** +** Returns FALSE if map can not be found. +** +*******************************************************************************/ + +BOOLEAN bta_gattc_handle2id(tBTA_GATTC_SERV *p_srcb, UINT16 handle, tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_char_id, tBT_UUID *p_descr_type) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC_CACHE_ATTR *p_attr, *p_char = NULL; + UINT8 j; + + memset(p_service_id, 0, sizeof(tBTA_GATT_SRVC_ID)); + memset(p_char_id, 0, sizeof(tBTA_GATT_ID)); + memset(p_descr_type, 0, sizeof(tBT_UUID)); + + while (p_cache) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG3("Service: handle[%d] uuid[0x%04x] inst[%d]", + p_cache->s_handle, p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + /* a service found */ + if (p_cache->s_handle == handle) + { + memcpy(p_service_id, &p_cache->service_uuid, sizeof(tBTA_GATT_SRVC_ID)); + + return TRUE; + } + else /* start looking for attributes within the service */ + { + p_attr = p_cache->p_attr; + + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG5("\t Attr[0x%04x] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, p_attr->p_uuid->uuid16, p_attr->inst_id, p_attr->attr_type); +#endif + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR) + p_char = p_attr; + + if (handle == p_attr->attr_handle) + { + memcpy(p_service_id, &p_cache->service_uuid, sizeof(tBTA_GATT_SRVC_ID)); + + if (p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + bta_gattc_pack_attr_uuid(p_attr, p_descr_type); + + if (p_char != NULL) + { + bta_gattc_pack_attr_uuid(p_char, &p_char_id->uuid); + p_char_id->inst_id = p_char->inst_id; + } + else + { + APPL_TRACE_ERROR0("descriptor does not belong to any chracteristic, error"); + } + } + else + /* is a characterisitc value or included service */ + { + bta_gattc_pack_attr_uuid(p_attr, &p_char_id->uuid); + p_char_id->inst_id =p_attr->inst_id; + } + return TRUE; + } + p_attr = p_attr->p_next; + } + } + p_cache = p_cache->p_next; + } + + return FALSE; +} + +/******************************************************************************* +** +** Function bta_gattc_search_service +** +** Description search local cache for matching service record. +** +** Returns FALSE if map can not be found. +** +*******************************************************************************/ +void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID uuid) +{ + tBTA_GATTC_SERV *p_srcb = p_clcb->p_srcb; + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATTC cb_data; + + while (p_cache) + { + if (bta_gattc_uuid_compare(uuid, p_cache->service_uuid.id.uuid, FALSE)) + { +//#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG3("found service [0x%04x], inst[%d] handle [%d]", + p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id, + p_cache->s_handle); +//#endif + if (p_clcb->p_rcb->p_cback) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + cb_data.srvc_res.conn_id = p_clcb->bta_conn_id; + memcpy(&cb_data.srvc_res.service_uuid, &p_cache->service_uuid ,sizeof(tBTA_GATT_SRVC_ID)); + + (* p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_RES_EVT, &cb_data); + //todo (tBTA_GATTC *)&p_cache->service_uuid); + } + } + p_cache = p_cache->p_next; + } +} +/******************************************************************************* +** +** Function bta_gattc_find_record +** +** Description search local cache for matching attribute record. +** +** Parameter p_result: output parameter to store the characteristic/ +** included service GATT ID. +** +** Returns GATT_ERROR is no recording found. BTA_GATT_OK if record found. +** +*******************************************************************************/ +static tBTA_GATT_STATUS bta_gattc_find_record(tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_ATTR_TYPE attr_type, + tBTA_GATT_SRVC_ID *p_service_id, + tBTA_GATT_ID *p_start_rec, + tBT_UUID * p_uuid_cond, + tBTA_GATT_ID *p_result, + void *p_param) +{ + tBTA_GATTC_CACHE *p_cache = p_srcb->p_srvc_cache; + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + tBT_UUID uuid_cond = {0}, start_descr = {0}; + UINT8 i, j; + tBTA_GATTC_CACHE_ATTR *p_attr; + BOOLEAN char_found = FALSE, descr_found = FALSE; + + if (p_uuid_cond) + memcpy(&uuid_cond, p_uuid_cond, sizeof(tBT_UUID)); + + for (i = 0; p_cache <= p_srcb->p_cur_srvc && p_cache && status != BTA_GATT_OK; i ++) + { + if (bta_gattc_uuid_compare(p_service_id->id.uuid, p_cache->service_uuid.id.uuid, FALSE) && + p_service_id->id.inst_id == p_cache->service_uuid.id.inst_id && + p_service_id->is_primary == p_cache->service_uuid.is_primary) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG2("found matching service [0x%04x], inst[%d]", + p_cache->service_uuid.id.uuid.uu.uuid16, + p_cache->service_uuid.id.inst_id); +#endif + p_attr = p_cache->p_attr; + + for (j = 0; p_attr; j ++) + { +#if (defined BTA_GATT_DEBUG && BTA_GATT_DEBUG == TRUE) + APPL_TRACE_DEBUG5("\t Attr[%d] handle[0x%04x] uuid[0x%04x] inst[%d] type[%d]", + j + 1, p_attr->attr_handle, + p_attr->p_uuid->uuid16, + p_attr->inst_id, + p_attr->attr_type); +#endif + bta_gattc_pack_attr_uuid(p_attr, &p_result->uuid); + + if (p_start_rec != NULL && char_found == FALSE) + { + /* find the starting record first */ + if (bta_gattc_uuid_compare(p_start_rec->uuid, p_result->uuid, FALSE) && + p_start_rec->inst_id == p_attr->inst_id && + (attr_type == p_attr->attr_type || + /* find descriptor would look for characteristic first */ + (attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR && p_attr->attr_type == BTA_GATTC_ATTR_TYPE_CHAR))) + { + char_found = TRUE; + } + } + else + { + /* if looking for descriptor, here is the where the descrptor to be found */ + if (attr_type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + /* starting descriptor UUID */ + if (p_param != NULL) + memcpy(&start_descr, p_param, sizeof(tBT_UUID)); + /* next characeteristic already, return error */ + if (p_attr->attr_type != BTA_GATTC_ATTR_TYPE_CHAR_DESCR) + { + break; + } + else + { + if (start_descr.len != 0 && !descr_found) + { + if (bta_gattc_uuid_compare(start_descr, p_result->uuid, FALSE)) + { + descr_found = TRUE; + } + } + else + { + /* with matching descriptor */ + if (bta_gattc_uuid_compare(uuid_cond, p_result->uuid, FALSE)) + { + status = BTA_GATT_OK; + break; + } + } + } + } + else + { + if (bta_gattc_uuid_compare(uuid_cond, p_result->uuid, FALSE) && + attr_type == p_attr->attr_type) + { + + APPL_TRACE_DEBUG0("found char handle mapping characteristic"); + p_result->inst_id = p_attr->inst_id; + + if (p_param != NULL) + { + if (attr_type == BTA_GATTC_ATTR_TYPE_CHAR || + attr_type == BTA_GATTC_ATTR_TYPE_INCL_SRVC) + { + *(tBTA_GATT_CHAR_PROP *)p_param = p_attr->property; + } + } + + status = BTA_GATT_OK; + break; + } + } + } + p_attr = p_attr->p_next; + } + if (status) + { + APPL_TRACE_ERROR0("In the given service, can not find matching record"); + } + break; + } + + p_cache = p_cache->p_next; + } + return status; + +} + +/******************************************************************************* +** +** Function bta_gattc_query_cache +** +** Description search local cache for matching attribute record. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** *p_start_rec: start the search from the next record +** after the one identified by *p_start_rec. +** p_uuid_cond: UUID, if NULL find the first available +** characteristic/included service. +** p_output: output parameter which will store the GATT ID +** of the characteristic /included service found. +** +** Returns BTA_GATT_ERROR is no recording found. BTA_GATT_OK if record found. +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id, + tBTA_GATTC_ATTR_TYPE query_type, + tBTA_GATT_SRVC_ID *p_srvc_id, + tBTA_GATT_ID *p_start_rec, + tBT_UUID *p_uuid_cond, + tBTA_GATT_ID *p_output, + void *p_param) +{ + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER; + + /* lock other GKI task */ + GKI_sched_lock(); + + APPL_TRACE_DEBUG0("bta_gattc_query_cache"); + + if (p_clcb != NULL ) + { + if (p_clcb->state == BTA_GATTC_CONN_ST) + { + if (p_clcb->p_srcb && + !p_clcb->p_srcb->p_srvc_list && /* no active discovery */ + p_clcb->p_srcb->p_srvc_cache) + { + status = bta_gattc_find_record(p_clcb->p_srcb, + query_type, + p_srvc_id, + p_start_rec, + p_uuid_cond, + p_output, + p_param); + } + else + { + status = BTA_GATT_ERROR; + APPL_TRACE_ERROR0("No server cache available"); + } + } + else + { + APPL_TRACE_ERROR1("server cache not available, CLCB state = %d", p_clcb->state); + + status = (p_clcb->state == BTA_GATTC_DISCOVER_ST) ? BTA_GATT_BUSY : BTA_GATT_ERROR; + } + } + else + { + APPL_TRACE_ERROR1("Unknown conn ID: %d", conn_id); + } + GKI_sched_unlock(); + + return status; +} + +/******************************************************************************* +** +** Function bta_gattc_rebuild_cache +** +** Description rebuild server cache from NV cache. +** +** Parameters +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srvc_cb, UINT16 num_attr, + tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index) +{ + /* first attribute loading, initialize buffer */ + APPL_TRACE_ERROR0("bta_gattc_rebuild_cache"); + if (attr_index == 0) + { + while (p_srvc_cb->cache_buffer.p_first) + GKI_freebuf (GKI_dequeue (&p_srvc_cb->cache_buffer)); + + if (bta_gattc_alloc_cache_buf(p_srvc_cb) == NULL) + { + APPL_TRACE_ERROR0("allocate cache buffer failed, no resources"); + } + else + { + p_srvc_cb->p_cur_srvc = p_srvc_cb->p_srvc_cache = NULL; + } + } + + while (num_attr > 0 && p_attr != NULL) + { + switch (p_attr->attr_type) + { + case BTA_GATTC_ATTR_TYPE_SRVC: + bta_gattc_add_srvc_to_cache(p_srvc_cb, + p_attr->s_handle, + p_attr->e_handle, + &p_attr->uuid, + p_attr->is_primary, + p_attr->id); + break; + + case BTA_GATTC_ATTR_TYPE_CHAR: + case BTA_GATTC_ATTR_TYPE_CHAR_DESCR: + case BTA_GATTC_ATTR_TYPE_INCL_SRVC: + bta_gattc_add_attr_to_cache(p_srvc_cb, + p_attr->s_handle, + &p_attr->uuid, + p_attr->prop, + p_attr->attr_type); + break; + } + p_attr ++; + num_attr --; + } +} + +/******************************************************************************* +** +** Function bta_gattc_fill_nv_attr +** +** Description fill a NV attribute entry value +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_fill_nv_attr(tBTA_GATTC_NV_ATTR *p_attr, UINT8 type, UINT16 s_handle, + UINT16 e_handle, UINT8 id, tBT_UUID uuid, UINT8 prop, BOOLEAN is_primary) +{ + p_attr->s_handle = s_handle; + p_attr->e_handle = e_handle; + p_attr->attr_type = type; + p_attr->is_primary = is_primary; + p_attr->id = id; + p_attr->prop = prop; + + memcpy(&p_attr->uuid, &uuid, sizeof(tBT_UUID)); +} +/******************************************************************************* +** +** Function bta_gattc_cache_save +** +** Description save the server cache into NV +** +** Returns None. +** +*******************************************************************************/ +BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id) +{ + tBTA_GATTC_CACHE *p_cur_srvc = p_srvc_cb->p_srvc_cache; + UINT8 i = 0; + UINT16 offset = 0; + tBTA_GATTC_NV_ATTR nv_attr[BTA_GATTC_NV_LOAD_MAX]; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBT_UUID uuid; + + while (p_cur_srvc && i < BTA_GATTC_NV_LOAD_MAX) + { + if (offset ++ >= p_srvc_cb->attr_index) + { + bta_gattc_fill_nv_attr(&nv_attr[i++], + BTA_GATTC_ATTR_TYPE_SRVC, + p_cur_srvc->s_handle, + p_cur_srvc->e_handle, + p_cur_srvc->service_uuid.id.inst_id, + p_cur_srvc->service_uuid.id.uuid, + 0, + p_cur_srvc->service_uuid.is_primary); + } + + p_attr = p_cur_srvc->p_attr; + + for (; p_attr && i < BTA_GATTC_NV_LOAD_MAX ; offset ++, p_attr = p_attr->p_next) + { + if (offset >= p_srvc_cb->attr_index) + { + if ((uuid.len = p_attr->uuid_len) == LEN_UUID_16) + { + uuid.uu.uuid16 = p_attr->p_uuid->uuid16; + } + else + { + memcpy(uuid.uu.uuid128, p_attr->p_uuid->uuid128, LEN_UUID_128); + } + + bta_gattc_fill_nv_attr(&nv_attr[i++], + p_attr->attr_type, + p_attr->attr_handle, + 0, + p_attr->inst_id, + uuid, + p_attr->property, + FALSE); + } + } + p_cur_srvc = p_cur_srvc->p_next; + } + + if (i > 0) + { + bta_gattc_co_cache_save(p_srvc_cb->server_bda, BTA_GATTC_CI_CACHE_SAVE_EVT, i, + nv_attr, p_srvc_cb->attr_index, conn_id); + + p_srvc_cb->attr_index += i; + + return TRUE; + } + else + { + return FALSE; + } +} +#endif /* BTA_GATT_INCLUDED */ + diff --git a/bta/gatt/bta_gattc_ci.c b/bta/gatt/bta_gattc_ci.c new file mode 100644 index 0000000..212126f --- /dev/null +++ b/bta/gatt/bta_gattc_ci.c @@ -0,0 +1,137 @@ +/****************************************************************************** + * + * Copyright (C) 2010-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 GATT call-in functions. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_gattc_ci.h" +#include "gki.h" +#include "bd.h" + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_open +** +** Description This function sends an event to indicate server cache open +** completed. +** +** Parameters server_bda - server BDA of this cache. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_open(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_EVT *p_evt; + + if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_load +** +** Description This function sends an event to BTA indicating the phone has +** load the servere cache and ready to send it to the stack. +** +** Parameters server_bda - server BDA of this cache. +** num_bytes_read - number of bytes read into the buffer +** specified in the read callout-function. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_load(BD_ADDR server_bda, UINT16 evt, UINT16 num_attr, + tBTA_GATTC_NV_ATTR *p_attr, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_LOAD *p_evt; + + if ((p_evt = (tBTA_GATTC_CI_LOAD *) GKI_getbuf(sizeof(tBTA_GATTC_CI_LOAD))) != NULL) + { + memset(p_evt, 0, sizeof(tBTA_GATTC_CI_LOAD)); + + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + p_evt->num_attr = (num_attr > BTA_GATTC_NV_LOAD_MAX) ? BTA_GATTC_NV_LOAD_MAX : num_attr; + + if (p_evt->num_attr > 0 && p_attr != NULL) + { + memcpy(p_evt->attr, p_attr, p_evt->num_attr * sizeof(tBTA_GATTC_NV_ATTR)); + } + + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_save +** +** Description This function sends an event to BTA indicating the phone has +** save the servere cache. +** +** Parameters server_bda - server BDA of this cache. +** evt - callin event code. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_ERROR if an error has occurred. +*8 conn_id - for this NV operation for. +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_ci_cache_save(BD_ADDR server_bda, UINT16 evt, tBTA_GATT_STATUS status, + UINT16 conn_id) +{ + tBTA_GATTC_CI_EVT *p_evt; + + if ((p_evt = (tBTA_GATTC_CI_EVT *) GKI_getbuf(sizeof(tBTA_GATTC_CI_EVT))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->hdr.layer_specific = conn_id; + + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h new file mode 100644 index 0000000..407e5d8 --- /dev/null +++ b/bta/gatt/bta_gattc_int.h @@ -0,0 +1,464 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 private file for the file transfer client (FTC). + * + ******************************************************************************/ +#ifndef BTA_GATTC_INT_H +#define BTA_GATTC_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gattc_ci.h" +#include "bta_gattc_co.h" + +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +enum +{ + BTA_GATTC_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_GATTC), + BTA_GATTC_INT_OPEN_FAIL_EVT, + BTA_GATTC_API_CANCEL_OPEN_EVT, + BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, + + BTA_GATTC_API_READ_EVT, + BTA_GATTC_API_WRITE_EVT, + BTA_GATTC_API_EXEC_EVT, + + BTA_GATTC_API_CLOSE_EVT, + + BTA_GATTC_API_SEARCH_EVT, + BTA_GATTC_API_CONFIRM_EVT, + BTA_GATTC_API_READ_MULTI_EVT, + + BTA_GATTC_INT_CONN_EVT, + BTA_GATTC_INT_DISCOVER_EVT, + BTA_GATTC_DISCOVER_CMPL_EVT, + BTA_GATTC_OP_CMPL_EVT, + BTA_GATTC_INT_DISCONN_EVT, + + /* for cache loading/saving */ + BTA_GATTC_START_CACHE_EVT, + BTA_GATTC_CI_CACHE_OPEN_EVT, + BTA_GATTC_CI_CACHE_LOAD_EVT, + BTA_GATTC_CI_CACHE_SAVE_EVT, + + BTA_GATTC_INT_START_IF_EVT, + BTA_GATTC_API_REG_EVT, + BTA_GATTC_API_DEREG_EVT, + BTA_GATTC_INT_DEREG_EVT + +}; +typedef UINT16 tBTA_GATTC_INT_EVT; + +/* max client application GATTC can support */ +#ifndef BTA_GATTC_CL_MAX +#define BTA_GATTC_CL_MAX 4 +#endif + +/* max known devices GATTC can support */ +#ifndef BTA_GATTC_KNOWN_SR_MAX +#define BTA_GATTC_KNOWN_SR_MAX 4 +#endif + +#ifndef BTA_GATTC_CLCB_MAX + #define BTA_GATTC_CLCB_MAX GATT_CL_MAX_LCB +#endif + +#define BTA_GATTC_WRITE_PREPARE GATT_WRITE_PREPARE + +/* internal strucutre for GATTC register API */ +typedef struct +{ + BT_HDR hdr; + tBT_UUID app_uuid; + tBTA_GATTC_CBACK *p_cback; +}tBTA_GATTC_API_REG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTC_IF client_if; +}tBTA_GATTC_INT_START_IF; + +typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_API_DEREG; +typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_INT_DEREG; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + tBTA_GATTC_IF client_if; + BOOLEAN is_direct; +} tBTA_GATTC_API_OPEN; + +typedef tBTA_GATTC_API_OPEN tBTA_GATTC_API_CANCEL_OPEN; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBT_UUID descr_type; +} tBTA_GATTC_API_READ; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBT_UUID descr_type; + tBTA_GATTC_WRITE_TYPE write_type; + UINT16 offset; + UINT16 len; + UINT8 *p_value; +}tBTA_GATTC_API_WRITE; + +typedef struct +{ + BT_HDR hdr; + BOOLEAN is_execute; +}tBTA_GATTC_API_EXEC; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; +} tBTA_GATTC_API_CONFIRM; + +typedef tGATT_CL_COMPLETE tBTA_GATTC_CMPL; + +typedef struct +{ + BT_HDR hdr; + UINT8 op_code; + tGATT_STATUS status; + tBTA_GATTC_CMPL *p_cmpl; +}tBTA_GATTC_OP_CMPL; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID srvc_uuid; +}tBTA_GATTC_API_SEARCH; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_AUTH_REQ auth_req; + UINT8 num_attr; + tBTA_GATTC_ATTR_ID *p_id_list; +}tBTA_GATTC_API_READ_MULTI; + +typedef union +{ + BT_HDR hdr; + tBTA_GATTC_API_REG api_reg; + tBTA_GATTC_API_DEREG api_dereg; + tBTA_GATTC_API_OPEN api_conn; + tBTA_GATTC_API_CANCEL_OPEN api_cancel_conn; + tBTA_GATTC_API_READ api_read; + tBTA_GATTC_API_SEARCH api_search; + tBTA_GATTC_API_WRITE api_write; + tBTA_GATTC_API_CONFIRM api_confirm; + tBTA_GATTC_API_EXEC api_exec; + tBTA_GATTC_API_READ_MULTI api_read_multi; + tBTA_GATTC_OP_CMPL op_cmpl; + tBTA_GATTC_CI_EVT ci_open; + tBTA_GATTC_CI_EVT ci_save; + tBTA_GATTC_CI_LOAD ci_load; + + tBTA_GATTC_INT_START_IF int_start_if; + tBTA_GATTC_INT_DEREG int_dereg; + +} tBTA_GATTC_DATA; + + +/* GATT server cache on the client */ +typedef union +{ + UINT8 uuid128[LEN_UUID_128]; + UINT16 uuid16; +}tBTA_GATTC_UUID; + +typedef struct gattc_attr_cache +{ + tBTA_GATTC_UUID *p_uuid; + struct gattc_attr_cache *p_next; + UINT16 uuid_len; + UINT16 attr_handle; + UINT8 inst_id; + tBTA_GATT_CHAR_PROP property; /* if characteristic, it is char property; + if included service, flag primary, + if descriptor, not used */ + tBTA_GATTC_ATTR_TYPE attr_type; +// btla-specific ++ +} __attribute__((packed)) tBTA_GATTC_CACHE_ATTR; +// btla-specific -- + +typedef struct gattc_svc_cache +{ + tBTA_GATT_SRVC_ID service_uuid; + tBTA_GATTC_CACHE_ATTR *p_attr; + tBTA_GATTC_CACHE_ATTR *p_last_attr; + UINT16 s_handle; + UINT16 e_handle; + struct gattc_svc_cache *p_next; +// btla-specific ++ +} __attribute__((packed)) tBTA_GATTC_CACHE; +// btla-specific -- + +typedef struct +{ + tBT_UUID uuid; + UINT16 s_handle; + UINT16 e_handle; + BOOLEAN is_primary; + UINT8 srvc_inst_id; + tBTA_GATT_CHAR_PROP property; +}tBTA_GATTC_ATTR_REC; + + +#define BTA_GATTC_MAX_CACHE_CHAR 40 +#define BTA_GATTC_ATTR_LIST_SIZE (BTA_GATTC_MAX_CACHE_CHAR * sizeof(tBTA_GATTC_ATTR_REC)) + +#ifndef BTA_GATTC_CACHE_SRVR_SIZE + #define BTA_GATTC_CACHE_SRVR_SIZE 600 +#endif + +enum +{ + BTA_GATTC_IDLE_ST = 0, /* Idle */ + BTA_GATTC_W4_CONN_ST, /* Wait for connection - (optional) */ + BTA_GATTC_CONN_ST, /* connected state */ + BTA_GATTC_DISCOVER_ST /* discover is in progress */ +}; +typedef UINT8 tBTA_GATTC_STATE; + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR server_bda; + BOOLEAN connected; + +#define BTA_GATTC_SERV_IDLE 0 +#define BTA_GATTC_SERV_LOAD 1 +#define BTA_GATTC_SERV_SAVE 2 + + UINT8 state; + + tBTA_GATTC_CACHE *p_srvc_cache; + tBTA_GATTC_CACHE *p_cur_srvc; + BUFFER_Q cache_buffer; /* buffer queue used for storing the cache data */ + UINT8 *p_free; /* starting point to next available byte */ + UINT16 free_byte; /* number of available bytes in server cache buffer */ + UINT8 update_count; /* indication received */ + UINT8 num_clcb; /* number of associated CLCB */ + + + tBTA_GATTC_ATTR_REC *p_srvc_list; + UINT8 cur_srvc_idx; + UINT8 cur_char_idx; + UINT8 next_avail_idx; + UINT8 total_srvc; + UINT8 total_char; + + UINT8 srvc_hdl_chg; /* service handle change indication pending */ + UINT16 attr_index; /* cahce NV saving/loading attribute index */ + +} tBTA_GATTC_SERV; + +#ifndef BTA_GATTC_NOTIF_REG_MAX +#define BTA_GATTC_NOTIF_REG_MAX 4 +#endif + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR remote_bda; + tBTA_GATTC_CHAR_ID char_id; +}tBTA_GATTC_NOTIF_REG; + +typedef struct +{ + tBTA_GATTC_CBACK *p_cback; + BOOLEAN in_use; + tBTA_GATTC_IF client_if; /* client interface with BTE stack for this application */ + UINT8 num_clcb; /* number of associated CLCB */ + BOOLEAN dereg_pending; + tBT_UUID app_uuid; + tBTA_GATTC_NOTIF_REG notif_reg[BTA_GATTC_NOTIF_REG_MAX]; +}tBTA_GATTC_RCB; + +/* client channel is a mapping between a BTA client(cl_id) and a remote BD address */ +typedef struct +{ + UINT16 bta_conn_id; /* client channel ID, unique for clcb */ + BD_ADDR bda; + tBTA_GATTC_RCB *p_rcb; /* pointer to the registration CB */ + tBTA_GATTC_SERV *p_srcb; /* server cache CB */ + tBTA_GATTC_DATA *p_q_cmd; /* command in queue waiting for execution */ + +#define BTA_GATTC_NO_SCHEDULE 0 +#define BTA_GATTC_DISC_WAITING 0x01 +#define BTA_GATTC_REQ_WAITING 0x10 + + UINT8 auto_update; /* auto update is waiting */ + BOOLEAN in_use; + tBTA_GATTC_STATE state; + tBTA_GATT_STATUS status; + UINT16 reason; +} tBTA_GATTC_CLCB; + +/* back ground connection tracking information */ +#if GATT_MAX_APPS <= 8 +typedef UINT8 tBTA_GATTC_CIF_MASK ; +#elif GATT_MAX_APPS <= 16 +typedef UINT16 tBTA_GATTC_CIF_MASK; +#elif GATT_MAX_APPS <= 32 +typedef UINT32 tBTA_GATTC_CIF_MASK; +#endif + +typedef struct +{ + BOOLEAN in_use; + BD_ADDR remote_bda; + tBTA_GATTC_CIF_MASK cif_mask; + +}tBTA_GATTC_BG_TCK; + +typedef struct +{ + tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX]; + tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX]; + + tBTA_GATTC_CLCB clcb[BTA_GATTC_CLCB_MAX]; + tBTA_GATTC_SERV known_server[BTA_GATTC_KNOWN_SR_MAX]; + + tSDP_DISCOVERY_DB *p_sdp_db; + UINT16 sdp_conn_id; +}tBTA_GATTC_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_GATTC_CB bta_gattc_cb; +#else +extern tBTA_GATTC_CB *bta_gattc_cb_ptr; +#define bta_gattc_cb (*bta_gattc_cb_ptr) +#endif + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg); +extern void bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data); + +/* function processed outside SM */ +extern void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_start_if(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_process_api_open_cancel (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg); +extern void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_int_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data); + +/* function within state machine */ +extern void bta_gattc_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_open_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_cancel_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_conn(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_close_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern void bta_gattc_start_discover(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_read(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_search(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_confirm(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_execute(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_read_multi(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_load(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ci_save(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_cache_open(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); +extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg); +extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN *p_data); +extern void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status, + BD_ADDR remote_bda, UINT16 conn_id); + +/* utility functions */ +extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda); //todo +extern tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id); +extern tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda); +extern void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb); +extern tBTA_GATTC_CLCB * bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remote_bda); +extern tBTA_GATTC_RCB * bta_gattc_cl_get_regcb(UINT8 client_if); +extern tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda); +extern tBTA_GATTC_SERV * bta_gattc_srcb_alloc(BD_ADDR bda); +extern tBTA_GATTC_SERV * bta_gattc_find_scb_by_cid (UINT16 conn_id); +extern BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +extern UINT16 bta_gattc_id2handle(tBTA_GATTC_SERV *p_srcb, tBTA_GATT_SRVC_ID *p_service_id, tBTA_GATT_ID *p_char_id, tBT_UUID descr_uuid); +extern BOOLEAN bta_gattc_handle2id(tBTA_GATTC_SERV *p_srcb, UINT16 handle, tBTA_GATT_SRVC_ID *service_id, tBTA_GATT_ID *char_id, tBT_UUID *p_type); +extern BOOLEAN bta_gattc_uuid_compare (tBT_UUID src, tBT_UUID tar, BOOLEAN is_precise); +extern void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid); +extern BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb, tBTA_GATTC_NOTIFY *p_notify); +extern tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID descr_uuid, tGATT_VALUE *p_attr, tBTA_GATT_READ_VAL *p_value); +extern BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN add); +extern BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda); +extern UINT8 bta_gattc_num_reg_app(void); +extern void bta_gattc_clear_notif_registration(UINT16 conn_id); + +/* discovery functions */ +extern void bta_gattc_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data); +extern void bta_gattc_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status); +extern tBTA_GATT_STATUS bta_gattc_discover_procedure(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type); +extern tBTA_GATT_STATUS bta_gattc_discover_pri_service(UINT16 conn_id, tBTA_GATTC_SERV *p_server_cb, UINT8 disc_type); +extern void bta_gattc_search_service(tBTA_GATTC_CLCB *p_clcb, tBT_UUID uuid); +extern tBTA_GATT_STATUS bta_gattc_query_cache(UINT16 conn_id, UINT8 query_type, tBTA_GATT_SRVC_ID *p_srvc_id, + tBTA_GATT_ID *p_start_rec,tBT_UUID *p_uuid_cond, + tBTA_GATT_ID *p_output, void *p_property); +extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV *p_srvc_cb); +extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV *p_srcv, UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_attr, UINT16 attr_index); +extern BOOLEAN bta_gattc_cache_save(tBTA_GATTC_SERV *p_srvc_cb, UINT16 conn_id); + +#endif /* BTA_GATTC_INT_H */ diff --git a/bta/gatt/bta_gattc_main.c b/bta/gatt/bta_gattc_main.c new file mode 100644 index 0000000..a1fb536 --- /dev/null +++ b/bta/gatt/bta_gattc_main.c @@ -0,0 +1,486 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the GATT client main functions and state machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> + +#include "bta_gattc_int.h" +#include "gki.h" + + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + + +/* state machine action enumeration list */ +enum +{ + BTA_GATTC_OPEN, + BTA_GATTC_OPEN_FAIL, + //BTA_GATTC_OPEN_FAIL_IN_CONN, //<--- need to remove this? + BTA_GATTC_OPEN_ERROR, + BTA_GATTC_CANCEL_OPEN, + BTA_GATTC_CANCEL_OPEN_OK, + BTA_GATTC_CANCEL_OPEN_ERROR, + BTA_GATTC_CONN, + BTA_GATTC_START_DISCOVER, + BTA_GATTC_DISC_CMPL, + + BTA_GATTC_Q_CMD, + BTA_GATTC_CLOSE, + BTA_GATTC_CLOSE_FAIL, + BTA_GATTC_READ, + BTA_GATTC_WRITE, + + BTA_GATTC_OP_CMPL, + BTA_GATTC_SEARCH, + BTA_GATTC_FAIL, + BTA_GATTC_CONFIRM, + BTA_GATTC_EXEC, + BTA_GATTC_READ_MULTI, + BTA_GATTC_CI_OPEN, + BTA_GATTC_CI_LOAD, + BTA_GATTC_CI_SAVE, + BTA_GATTC_CACHE_OPEN, + BTA_GATTC_IGNORE_OP_CMPL, + + BTA_GATTC_IGNORE +}; +/* type for action functions */ +typedef void (*tBTA_GATTC_ACTION)(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data); + +/* action function list */ +const tBTA_GATTC_ACTION bta_gattc_action[] = +{ + bta_gattc_open, + bta_gattc_open_fail, + //bta_gattc_open_fail_in_conn, //<--- need to remove this? + bta_gattc_open_error, + bta_gattc_cancel_open, + bta_gattc_cancel_open_ok, + bta_gattc_cancel_open_error, + bta_gattc_conn, + bta_gattc_start_discover, + bta_gattc_disc_cmpl, + + bta_gattc_q_cmd, + bta_gattc_close, + bta_gattc_close_fail, + bta_gattc_read, + bta_gattc_write, + + bta_gattc_op_cmpl, + bta_gattc_search, + bta_gattc_fail, + bta_gattc_confirm, + bta_gattc_execute, + bta_gattc_read_multi, + bta_gattc_ci_open, + bta_gattc_ci_load, + bta_gattc_ci_save, + bta_gattc_cache_open, + bta_gattc_ignore_op_cmpl +}; + + +/* state table information */ +#define BTA_GATTC_ACTIONS 1 /* number of actions */ +#define BTA_GATTC_NEXT_STATE 1 /* position of next state */ +#define BTA_GATTC_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for idle state */ +static const UINT8 bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE_FAIL, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, + + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST} +}; + +/* state table for wait for open state */ +static const UINT8 bta_gattc_st_w4_conn[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_OPEN_FAIL, BTA_GATTC_IDLE_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_CANCEL_OPEN_OK, BTA_GATTC_IDLE_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE_FAIL, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_W4_CONN_ST}, + +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_W4_CONN_ST} +}; + +/* state table for open state */ +static const UINT8 bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN_ERROR, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_READ, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_WRITE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_EXEC, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, //BTA_GATTC_CLOSING_ST + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_SEARCH, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_READ_MULTI, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_OP_CMPL, BTA_GATTC_CONN_ST}, + +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_CACHE_OPEN, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_CONN_ST} +}; + +/* state table for discover state */ +static const UINT8 bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN_ERROR, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_DISCOVER_ST}, + +/* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, + +/* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST }, //BTA_GATTC_CLOSING_ST + +/* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_Q_CMD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_DISC_CMPL, BTA_GATTC_CONN_ST}, +/* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE_OP_CMPL, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST}, + +/* ===> for cache loading, saving */ +/* BTA_GATTC_START_CACHE_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_OPEN_EVT */ {BTA_GATTC_CI_OPEN, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_LOAD_EVT */ {BTA_GATTC_CI_LOAD, BTA_GATTC_DISCOVER_ST}, +/* BTA_GATTC_CI_CACHE_SAVE_EVT */ {BTA_GATTC_CI_SAVE, BTA_GATTC_DISCOVER_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_GATTC_ST_TBL)[BTA_GATTC_NUM_COLS]; + +/* state table */ +const tBTA_GATTC_ST_TBL bta_gattc_st_tbl[] = +{ + bta_gattc_st_idle, + bta_gattc_st_w4_conn, + bta_gattc_st_connected, + bta_gattc_st_discover +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_GATTC_CB bta_gattc_cb; +#endif + +#if BTA_GATT_DEBUG == TRUE +static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code); +static char *gattc_state_code(tBTA_GATTC_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_gattc_sm_execute +** +** Description State machine event handling function for GATTC +** +** +** Returns void +** +*******************************************************************************/ +void bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data) +{ + tBTA_GATTC_ST_TBL state_table; + UINT8 action; + int i; +#if BTA_GATT_DEBUG == TRUE + tBTA_GATTC_STATE in_state = p_clcb->state; + UINT16 in_event = event; + APPL_TRACE_DEBUG4("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state, + gattc_state_code(in_state), + in_event, + gattc_evt_code(in_event)); +#endif + + + /* look up the state table for the current state */ + state_table = bta_gattc_st_tbl[p_clcb->state]; + + event &= 0x00FF; + + /* set next state */ + p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_GATTC_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_GATTC_IGNORE) + { + (*bta_gattc_action[action])(p_clcb, p_data); + } + else + { + break; + } + } + +#if BTA_GATT_DEBUG == TRUE + if (in_state != p_clcb->state) + { + APPL_TRACE_DEBUG3("GATTC State Change: [%s] -> [%s] after Event [%s]", + gattc_state_code(in_state), + gattc_state_code(p_clcb->state), + gattc_evt_code(in_event)); + } +#endif +} + +/******************************************************************************* +** +** Function bta_gattc_hdl_event +** +** Description GATT client main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg) +{ + tBTA_GATTC_CB *p_cb = &bta_gattc_cb; + tBTA_GATTC_CLCB *p_clcb = NULL; + +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event)); +#endif + switch (p_msg->event) + { + case BTA_GATTC_API_REG_EVT: + bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_INT_START_IF_EVT: + bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_DEREG_EVT: + bta_gattc_deregister(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_INT_DEREG_EVT: + bta_gattc_int_deregister(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_OPEN_EVT: + bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + case BTA_GATTC_API_CANCEL_OPEN_EVT: + bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg); + break; + + default: + if ((p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific)) + != NULL) + { + bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg); + } + else + { + APPL_TRACE_ERROR1("Unknown conn ID: %d", p_msg->layer_specific); + } + + break; + } + + + return(TRUE); +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_GATT_DEBUG == TRUE + +/******************************************************************************* +** +** Function gattc_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) +{ + switch (evt_code) + { + case BTA_GATTC_API_OPEN_EVT: + return "BTA_GATTC_API_OPEN_EVT"; + case BTA_GATTC_INT_OPEN_FAIL_EVT: + return "BTA_GATTC_INT_OPEN_FAIL_EVT"; + case BTA_GATTC_API_CANCEL_OPEN_EVT: + return "BTA_GATTC_API_CANCEL_OPEN_EVT"; + case BTA_GATTC_INT_CANCEL_OPEN_OK_EVT: + return "BTA_GATTC_INT_CANCEL_OPEN_OK_EVT"; + case BTA_GATTC_API_READ_EVT: + return "BTA_GATTC_API_READ_EVT"; + case BTA_GATTC_API_WRITE_EVT: + return "BTA_GATTC_API_WRITE_EVT"; + case BTA_GATTC_API_EXEC_EVT: + return "BTA_GATTC_API_EXEC_EVT"; + case BTA_GATTC_API_CLOSE_EVT: + return "BTA_GATTC_API_CLOSE_EVT"; + case BTA_GATTC_API_SEARCH_EVT: + return "BTA_GATTC_API_SEARCH_EVT"; + case BTA_GATTC_API_CONFIRM_EVT: + return "BTA_GATTC_API_CONFIRM_EVT"; + case BTA_GATTC_API_READ_MULTI_EVT: + return "BTA_GATTC_API_READ_MULTI_EVT"; + case BTA_GATTC_INT_CONN_EVT: + return "BTA_GATTC_INT_CONN_EVT"; + case BTA_GATTC_INT_DISCOVER_EVT: + return "BTA_GATTC_INT_DISCOVER_EVT"; + case BTA_GATTC_DISCOVER_CMPL_EVT: + return "BTA_GATTC_DISCOVER_CMPL_EVT"; + case BTA_GATTC_OP_CMPL_EVT: + return "BTA_GATTC_OP_CMPL_EVT"; + case BTA_GATTC_INT_DISCONN_EVT: + return "BTA_GATTC_INT_DISCONN_EVT"; + case BTA_GATTC_START_CACHE_EVT: + return "BTA_GATTC_START_CACHE_EVT"; + case BTA_GATTC_CI_CACHE_OPEN_EVT: + return "BTA_GATTC_CI_CACHE_OPEN_EVT"; + case BTA_GATTC_CI_CACHE_LOAD_EVT: + return "BTA_GATTC_CI_CACHE_LOAD_EVT"; + case BTA_GATTC_CI_CACHE_SAVE_EVT: + return "BTA_GATTC_CI_CACHE_SAVE_EVT"; + case BTA_GATTC_INT_START_IF_EVT: + return "BTA_GATTC_INT_START_IF_EVT"; + case BTA_GATTC_API_REG_EVT: + return "BTA_GATTC_API_REG_EVT"; + case BTA_GATTC_API_DEREG_EVT: + return "BTA_GATTC_API_DEREG_EVT"; + + default: + return "unknown GATTC event code"; + } +} + +/******************************************************************************* +** +** Function gattc_state_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *gattc_state_code(tBTA_GATTC_STATE state_code) +{ + switch (state_code) + { + case BTA_GATTC_IDLE_ST: + return "GATTC_IDLE_ST"; + case BTA_GATTC_W4_CONN_ST: + return "GATTC_W4_CONN_ST"; + case BTA_GATTC_CONN_ST: + return "GATTC_CONN_ST"; + case BTA_GATTC_DISCOVER_ST: + return "GATTC_DISCOVER_ST"; + default: + return "unknown GATTC state code"; + } +} + +#endif /* Debug Functions */ +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gattc_utils.c b/bta/gatt/bta_gattc_utils.c new file mode 100644 index 0000000..a36e26c --- /dev/null +++ b/bta/gatt/bta_gattc_utils.c @@ -0,0 +1,664 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the GATT client utility function. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_gattc_int.h" +#include "bd.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + + +static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/******************************************************************************* +** +** Function bta_gatt_convert_uuid16_to_uuid128 +** +** Description Convert a 16 bits UUID to be an standard 128 bits one. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16) +{ + UINT8 *p = &uuid_128[LEN_UUID_128 - 4]; + + memcpy (uuid_128, base_uuid, LEN_UUID_128); + + UINT16_TO_STREAM(p, uuid_16); +} +/******************************************************************************* +** +** Function bta_gattc_uuid_compare +** +** Description Compare two UUID to see if they are the same. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_uuid_compare (tBT_UUID src, tBT_UUID tar, BOOLEAN is_precise) +{ + UINT8 su[LEN_UUID_128], tu[LEN_UUID_128]; + UINT8 *ps, *pt; + + /* any of the UUID is unspecified */ + if (src.len == 0 || tar.len == 0) + { + if (is_precise) + return FALSE; + else + return TRUE; + } + + /* If both are 16-bit, we can do a simple compare */ + if (src.len == 2 && tar.len == 2) + { + return src.uu.uuid16 == tar.uu.uuid16; + } + + /* One or both of the UUIDs is 128-bit */ + if (src.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16); + ps = su; + } + else + ps = src.uu.uuid128; + + if (tar.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16); + pt = tu; + } + else + pt = tar.uu.uuid128; + + return(memcmp(ps, pt, LEN_UUID_128) == 0); +} + +/******************************************************************************* +** +** Function bta_gattc_cl_get_regcb +** +** Description get registration control block by client interface. +** +** Returns pointer to the regcb +** +*******************************************************************************/ +tBTA_GATTC_RCB * bta_gattc_cl_get_regcb(UINT8 client_if) +{ + UINT8 i = 0; + tBTA_GATTC_RCB *p_clrcb = &bta_gattc_cb.cl_rcb[0]; + + for (i = 0; i < BTA_GATTC_CL_MAX; i ++, p_clrcb ++) + { + if (p_clrcb->in_use && + p_clrcb->client_if == client_if) + return p_clrcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_num_reg_app +** +** Description find the number of registered application. +** +** Returns pointer to the regcb +** +*******************************************************************************/ +UINT8 bta_gattc_num_reg_app(void) +{ + UINT8 i = 0, j = 0; + + for (i = 0; i < BTA_GATTC_CL_MAX; i ++) + { + if (bta_gattc_cb.cl_rcb[i].in_use) + j ++; + } + return j; +} +/******************************************************************************* +** +** Function bta_gattc_find_clcb_by_cif +** +** Description get clcb by client interface and remote bd adddress +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_cif (UINT8 client_if, BD_ADDR remote_bda) +{ + tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) + { + if (p_clcb->in_use && + p_clcb->p_rcb->client_if == client_if && + p_clcb->p_srcb && + bdcmp(p_clcb->p_srcb->server_bda, remote_bda) == 0) + return p_clcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_find_clcb_by_conn_id +** +** Description get clcb by connection ID +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_find_clcb_by_conn_id (UINT16 conn_id) +{ + tBTA_GATTC_CLCB *p_clcb = &bta_gattc_cb.clcb[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_CLCB_MAX; i ++, p_clcb ++) + { + if (p_clcb->in_use && + p_clcb->bta_conn_id == conn_id) + return p_clcb; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gattc_clcb_alloc +** +** Description allocate CLCB +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB * bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if, BD_ADDR remote_bda) +{ + UINT8 i_clcb = 0; + tBTA_GATTC_CLCB *p_clcb = NULL; + + for (i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) + { + if (!bta_gattc_cb.clcb[i_clcb].in_use) + { +#if BTA_GATT_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_gattc_clcb_alloc: found clcb[%d] available",i_clcb); +#endif + p_clcb = &bta_gattc_cb.clcb[i_clcb]; + p_clcb->in_use = TRUE; + bdcpy(p_clcb->bda, remote_bda); + + p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if); + + if ((p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda)) == NULL) + p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda); + + if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) + { + p_clcb->p_srcb->num_clcb ++; + p_clcb->p_rcb->num_clcb ++; + } + else + { + /* release this clcb if clcb or srcb allocation failed */ + p_clcb->in_use = FALSE; + p_clcb = NULL; + } + break; + } + } + return p_clcb; +} +/******************************************************************************* +** +** Function bta_gattc_find_alloc_clcb +** +** Description find or allocate CLCB if not found. +** +** Returns pointer to the clcb +** +*******************************************************************************/ +tBTA_GATTC_CLCB *bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if, BD_ADDR remote_bda) +{ + tBTA_GATTC_CLCB *p_clcb ; + + if ((p_clcb = bta_gattc_find_clcb_by_cif(client_if, remote_bda)) == NULL) + { + p_clcb = bta_gattc_clcb_alloc(client_if, remote_bda); + } + return p_clcb; +} + +/******************************************************************************* +** +** Function bta_gattc_clcb_dealloc +** +** Description Deallocte a clcb +** +** Returns pointer to the clcb +** +*******************************************************************************/ +void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb) +{ + + if (p_clcb) + { + if (p_clcb->p_srcb->num_clcb) + p_clcb->p_srcb->num_clcb --; + + if (p_clcb->p_rcb->num_clcb) + p_clcb->p_rcb->num_clcb --; + + utl_freebuf((void **)&p_clcb->p_q_cmd); + + APPL_TRACE_ERROR2("bta_gattc_clcb_dealloc in_use=%d conn_id=%d",p_clcb->in_use, p_clcb->bta_conn_id); + memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB)); + } + else + { + APPL_TRACE_ERROR0("bta_gattc_clcb_dealloc p_clcb=NULL"); + } +} + +/******************************************************************************* +** +** Function bta_gattc_find_srcb +** +** Description find server cache by remote bd address +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_find_srcb(BD_ADDR bda) +{ + tBTA_GATTC_SERV *p_srcb = &bta_gattc_cb.known_server[0]; + UINT8 i; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_srcb ++) + { + if (p_srcb->in_use && bdcmp(p_srcb->server_bda, bda) == 0) + return p_srcb; + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_find_scb_by_cid +** +** Description find server control block by connection ID +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_find_scb_by_cid (UINT16 conn_id) +{ + tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); + + if (p_clcb) + return p_clcb->p_srcb; + else + return NULL; +} +/******************************************************************************* +** +** Function bta_gattc_srcb_alloc +** +** Description allocate server cache control block +** +** Returns pointer to the server cache. +** +*******************************************************************************/ +tBTA_GATTC_SERV * bta_gattc_srcb_alloc(BD_ADDR bda) +{ + tBTA_GATTC_SERV *p_tcb = &bta_gattc_cb.known_server[0], + *p_recycle = NULL; + BOOLEAN found = FALSE; + UINT8 i; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_tcb ++) + { + if (!p_tcb->in_use) + { + found = TRUE; + break; + } + else if (!p_tcb->connected) + { + p_recycle = p_tcb; + } + } + + /* if not found, try to recycle one known device */ + if (!found && !p_recycle) + p_tcb = NULL; + else if (p_recycle) + p_tcb = p_recycle; + + if (p_tcb != NULL) + { + while (p_tcb->cache_buffer.p_first) + GKI_freebuf (GKI_dequeue (&p_tcb->cache_buffer)); + + utl_freebuf((void **)&p_tcb->p_srvc_list); + memset(p_tcb, 0 , sizeof(tBTA_GATTC_SERV)); + + p_tcb->in_use = TRUE; + bdcpy(p_tcb->server_bda, bda); + } + return p_tcb; +} +/******************************************************************************* +** +** Function bta_gattc_enqueue +** +** Description enqueue a client request in clcb. +** +** Returns success or failure. +** +*******************************************************************************/ +BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) +{ + BOOLEAN in_q = FALSE; + + if (p_clcb->p_q_cmd == NULL) + { + p_clcb->p_q_cmd = (tBTA_GATTC_DATA *)GKI_getbuf(sizeof(tBTA_GATTC_DATA)); + + if (p_data) + memcpy(p_clcb->p_q_cmd, p_data, sizeof(tBTA_GATTC_DATA)); + + in_q = TRUE; + } + else + { + APPL_TRACE_ERROR0("already has a pending command!!"); + /* skip the callback now. ----- need to send callback ? */ + } + return in_q; +} +/******************************************************************************* +** +** Function bta_gattc_pack_attr_uuid +** +** Description pack UUID into a stream. +** +** Returns +** +*******************************************************************************/ +void bta_gattc_pack_attr_uuid(tBTA_GATTC_CACHE_ATTR *p_attr, tBT_UUID *p_uuid) +{ + UINT8 *pp = (UINT8 *)p_attr->p_uuid; + + memset(p_uuid, 0, sizeof(tBT_UUID)); + + p_uuid->len = p_attr->uuid_len; + + if (p_attr->uuid_len == LEN_UUID_16) + { + STREAM_TO_UINT16(p_uuid->uu.uuid16, pp); + } + else + { + memcpy(p_uuid->uu.uuid128, pp, LEN_UUID_128); + } + + return; +} +/******************************************************************************* +** +** Function bta_gattc_check_notif_registry +** +** Description check if the service notificaition has been registered. +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_gattc_check_notif_registry(tBTA_GATTC_RCB *p_clreg, tBTA_GATTC_SERV *p_srcb, + tBTA_GATTC_NOTIFY *p_notify) +{ + UINT8 i; + + for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clreg->notif_reg[i].in_use && + bdcmp(p_clreg->notif_reg[i].remote_bda, p_srcb->server_bda) == 0 && + (bta_gattc_uuid_compare(p_clreg->notif_reg[i].char_id.srvc_id.id.uuid, p_notify->char_id.srvc_id.id.uuid, FALSE) && + p_clreg->notif_reg[i].char_id.srvc_id.id.inst_id == p_notify->char_id.srvc_id.id.inst_id && + p_clreg->notif_reg[i].char_id.srvc_id.is_primary == p_notify->char_id.srvc_id.is_primary && + bta_gattc_uuid_compare(p_clreg->notif_reg[i].char_id.char_id.uuid, p_notify->char_id.char_id.uuid, FALSE) && + p_clreg->notif_reg[i].char_id.char_id.inst_id == p_notify->char_id.char_id.inst_id) + ) + { + APPL_TRACE_DEBUG0("Notification registered!"); + return TRUE; + } + } + return FALSE; + +} +/******************************************************************************* +** +** Function bta_gattc_clear_notif_registration +** +** Description clear up the notification registration information by BD_ADDR. +** +** Returns None. +** +*******************************************************************************/ +void bta_gattc_clear_notif_registration(UINT16 conn_id) +{ + BD_ADDR remote_bda; + tBTA_GATTC_IF gatt_if; + tBTA_GATTC_RCB *p_clrcb ; + UINT8 i; + + if (GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda)) + { + if ((p_clrcb = bta_gattc_cl_get_regcb(gatt_if)) != NULL) + { + for (i = 0 ; i < BTA_GATTC_NOTIF_REG_MAX; i ++) + { + if (p_clrcb->notif_reg[i].in_use && !bdcmp(p_clrcb->notif_reg[i].remote_bda, remote_bda)) + memset(&p_clrcb->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG)); + } + } + } + else + { + APPL_TRACE_ERROR0("can not clear indication/notif registration for unknown app"); + } + return; +} + +/******************************************************************************* +** +** Function bta_gattc_pack_cb_data +** +** Description pack the data from read response into callback data structure. +** +** Returns +** +*******************************************************************************/ +tBTA_GATT_STATUS bta_gattc_pack_read_cb_data(tBTA_GATTC_SERV *p_srcb, tBT_UUID descr_uuid, + tGATT_VALUE *p_attr, tBTA_GATT_READ_VAL *p_value) +{ + UINT8 i = 0, *pp = p_attr->value; + tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_AGG_FORMAT}}; + UINT16 handle; + tBTA_GATT_STATUS status = BTA_GATT_OK; + + /* GATT_UUID_CHAR_AGG_FORMAT */ + if (bta_gattc_uuid_compare (uuid, descr_uuid, TRUE)) + { + while (p_attr->len >= 2 && i < BTA_GATTC_MULTI_MAX) + { + STREAM_TO_UINT16(handle, pp); + + if (bta_gattc_handle2id(p_srcb, + handle, + &p_value->aggre_value.pre_format[i].char_id.srvc_id, + &p_value->aggre_value.pre_format[i].char_id.char_id, + &p_value->aggre_value.pre_format[i].descr_type) == FALSE) + { + status = BTA_GATT_INTERNAL_ERROR; + APPL_TRACE_ERROR1("can not map to GATT ID. handle = 0x%04x", handle); + break; + } + i ++; + p_attr->len -= 2; + } + p_value->aggre_value.num_pres_fmt = i; + } + else + { + /* all others, take as raw format */ + p_value->unformat.len = p_attr->len; + p_value->unformat.p_value = p_attr->value; + } + return status; +} +/******************************************************************************* +** +** Function bta_gattc_mark_bg_conn +** +** Description mark background connection status when a bg connection is initiated +** or terminated. +** +** Returns TRUE if success; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_mark_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN add) +{ + tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0]; + UINT8 i = 0; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + { + if (p_bg_tck->in_use && + bdcmp(p_bg_tck->remote_bda, remote_bda) == 0) + { + if (add) + /* mask on the cif bit */ + p_bg_tck->cif_mask |= (1 <<(client_if - 1)); + else + p_bg_tck->cif_mask &= (~(1 <<(client_if - 1))); + + return TRUE; + } + } + if (!add) + { + APPL_TRACE_ERROR0("Do not find the bg connection mask for the remote device"); + return FALSE; + } + else /* adding a new device mask */ + { + for (i = 0, p_bg_tck = &bta_gattc_cb.bg_track[0]; + i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + { + if (!p_bg_tck->in_use) + { + p_bg_tck->in_use = TRUE; + bdcpy(p_bg_tck->remote_bda, remote_bda); + p_bg_tck->cif_mask = (1 <<(client_if - 1)); + return TRUE; + } + } + APPL_TRACE_ERROR0("no available space to mark the bg connection status"); + return FALSE; + } +} +/******************************************************************************* +** +** Function bta_gattc_check_bg_conn +** +** Description check if this is a background connection background connection. +** +** Returns TRUE if success; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gattc_check_bg_conn (tBTA_GATTC_IF client_if, BD_ADDR remote_bda) +{ + tBTA_GATTC_BG_TCK *p_bg_tck = &bta_gattc_cb.bg_track[0]; + UINT8 i = 0; + BOOLEAN is_bg_conn = FALSE; + + for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i ++, p_bg_tck ++) + { + if (p_bg_tck->in_use && + bdcmp(p_bg_tck->remote_bda, remote_bda) == 0) + { + if ((p_bg_tck->cif_mask &(1 <<(client_if - 1))) != 0) + is_bg_conn = TRUE; + break; + } + } + return is_bg_conn; +} +/******************************************************************************* +** +** Function bta_gattc_send_open_cback +** +** Description send open callback +** +** Returns +** +*******************************************************************************/ +void bta_gattc_send_open_cback( tBTA_GATTC_RCB *p_clreg, tBTA_GATT_STATUS status, + BD_ADDR remote_bda, UINT16 conn_id) +{ + tBTA_GATTC cb_data; + + if (p_clreg->p_cback) + { + memset(&cb_data, 0, sizeof(tBTA_GATTC)); + + cb_data.open.status = status; + cb_data.open.client_if = p_clreg->client_if; + cb_data.open.conn_id = conn_id; + bdcpy(cb_data.open.remote_bda, remote_bda); + + (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data); + } +} + + + + + +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_act.c b/bta/gatt/bta_gatts_act.c new file mode 100644 index 0000000..1b47598 --- /dev/null +++ b/bta/gatt/bta_gatts_act.c @@ -0,0 +1,798 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the GATT Server action functions for the state + * machine. + * + ******************************************************************************/ + + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatts_int.h" +#include "bta_gatts_co.h" + +#include <string.h> + +static void bta_gatts_nv_save_cback(BOOLEAN is_saved, tGATTS_HNDL_RANGE *p_hndl_range); +static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, tGATTS_SRV_CHG_RSP *p_rsp); + +static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason); +static void bta_gatts_send_request_cback (UINT16 conn_id, + UINT32 trans_id, + tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data); +static tGATT_CBACK bta_gatts_cback = +{ + bta_gatts_conn_cback, + NULL, + NULL, + NULL, + bta_gatts_send_request_cback +}; + +tGATT_APPL_INFO bta_gatts_nv_cback = +{ + bta_gatts_nv_save_cback, + bta_gatts_nv_srv_chg_cback +}; + +/******************************************************************************* +** +** Function bta_gatts_nv_save_cback +** +** Description NV save callback function. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_nv_save_cback(BOOLEAN is_add, tGATTS_HNDL_RANGE *p_hndl_range) +{ + bta_gatts_co_update_handle_range(is_add, (tBTA_GATTS_HNDL_RANGE *)p_hndl_range); +} + + +/******************************************************************************* +** +** Function bta_gatts_nv_srv_chg_cback +** +** Description NV save callback function. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** Returns none. +** +*******************************************************************************/ +static BOOLEAN bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd, tGATTS_SRV_CHG_REQ *p_req, tGATTS_SRV_CHG_RSP *p_rsp) +{ + return bta_gatts_co_srv_chg((tBTA_GATTS_SRV_CHG_CMD) cmd, + (tBTA_GATTS_SRV_CHG_REQ *) p_req, + (tBTA_GATTS_SRV_CHG_RSP *) p_rsp); +} + + +/******************************************************************************* +** +** Function bta_gatts_enable +** +** Description enable BTA GATTS module. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_enable(tBTA_GATTS_CB *p_cb) +{ + UINT8 index=0; + tBTA_GATTS_HNDL_RANGE handle_range; + + p_cb->enabled = TRUE; + + APPL_TRACE_DEBUG0("bta_gatts_enable"); + while ( bta_gatts_co_load_handle_range(index, &handle_range)) + { + GATTS_AddHandleRange((tGATTS_HNDL_RANGE *)&handle_range); + memset(&handle_range, 0, sizeof(tGATTS_HNDL_RANGE)); + index++; + } + + APPL_TRACE_DEBUG1("bta_gatts_enable: num of handle range added=%d", index); + + if (!GATTS_NVRegister(&bta_gatts_nv_cback)) + { + APPL_TRACE_ERROR0("BTA GATTS NV register failed."); + } +} +/******************************************************************************* +** +** Function bta_gatts_register +** +** Description register an application. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + tBTA_GATTS_INT_START_IF *p_buf; + tBTA_GATTS cb_data; + tBTA_GATT_STATUS status = BTA_GATT_OK; + UINT8 i, first_unuse = 0xff; + + if (!p_cb->enabled) + bta_gatts_enable(p_cb); + + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use) + { + if (bta_gatts_uuid_compare(p_cb->rcb[i].app_uuid, p_msg->api_reg.app_uuid)) + { + APPL_TRACE_ERROR0("application already registered."); + status = BTA_GATT_DUP_REG; + break; + } + } + } + + if (status == BTA_GATT_OK) + { + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (first_unuse == 0xff && !p_cb->rcb[i].in_use) + { + first_unuse = i; + break; + } + } + + cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF; +// btla-specific ++ + memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID)); +// btla-specific -- + if (first_unuse != 0xff) + { + APPL_TRACE_ERROR1("register application first_unuse rcb_idx = %d", first_unuse); + + p_cb->rcb[first_unuse].in_use = TRUE; + p_cb->rcb[first_unuse].p_cback = p_msg->api_reg.p_cback; + memcpy(&p_cb->rcb[first_unuse].app_uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID)); + cb_data.reg_oper.server_if = + p_cb->rcb[first_unuse].gatt_if = GATT_Register(&p_msg->api_reg.app_uuid, &bta_gatts_cback); + if ( !p_cb->rcb[first_unuse].gatt_if) + { + status = BTA_GATT_NO_RESOURCES; + } + else + { + if ((p_buf = (tBTA_GATTS_INT_START_IF *) GKI_getbuf(sizeof(tBTA_GATTS_INT_START_IF))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_INT_START_IF_EVT; + p_buf->server_if = p_cb->rcb[first_unuse].gatt_if; + + bta_sys_sendmsg(p_buf); + } + else + { + status = BTA_GATT_NO_RESOURCES; + memset( &p_cb->rcb[first_unuse], 0 , sizeof(tBTA_GATTS_RCB)); + } + } + } + else + { + status = BTA_GATT_NO_RESOURCES; + } + + } + cb_data.reg_oper.status = status; + if (p_msg->api_reg.p_cback) + (*p_msg->api_reg.p_cback)(BTA_GATTS_REG_EVT, &cb_data); +} + + +/******************************************************************************* +** +** Function bta_gatts_start_if +** +** Description start an application interface. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_start_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + if (bta_gatts_find_app_rcb_by_app_if(p_msg->int_start_if.server_if)) + { + GATT_StartIf(p_msg->int_start_if.server_if); + } + else + { + APPL_TRACE_ERROR1("Unable to start app.: Unknown interface =%d",p_msg->int_start_if.server_if ); + } +} +/******************************************************************************* +** +** Function bta_gatts_deregister +** +** Description deregister an application. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg) +{ + tBTA_GATT_STATUS status = BTA_GATT_ERROR; + tBTA_GATTS_CBACK *p_cback = NULL; + UINT8 i; + tBTA_GATTS cb_data; + + cb_data.reg_oper.server_if = p_msg->api_dereg.server_if; + cb_data.reg_oper.status = status; + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == p_msg->api_dereg.server_if) + { + p_cback = p_cb->rcb[i].p_cback; + status = BTA_GATT_OK; + + /* deregister the app */ + GATT_Deregister(p_cb->rcb[i].gatt_if); + + /* reset cb */ + memset(&p_cb->rcb[i], 0, sizeof(tBTA_GATTS_RCB)); + cb_data.reg_oper.status = status; + break; + } + } + + if (p_cback) + { + (*p_cback)(BTA_GATTS_DEREG_EVT, &cb_data); + } + else + { + APPL_TRACE_ERROR0("application not registered."); + } +} +/******************************************************************************* +** +** Function bta_gatts_create_srvc +** +** Description action function to create a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + UINT8 rcb_idx; + tBTA_GATTS cb_data; + UINT8 srvc_idx; + UINT16 service_id = 0; + //tBTA_GATTS_HNDL_RANGE handle_range; + + cb_data.create.status = BTA_GATT_ERROR; + + rcb_idx = bta_gatts_find_app_rcb_idx_by_app_if(p_cb, p_msg->api_create_svc.server_if); + + APPL_TRACE_ERROR1("create service rcb_idx = %d", rcb_idx); + + if (rcb_idx != BTA_GATTS_INVALID_APP) + { + if ((srvc_idx = bta_gatts_alloc_srvc_cb(p_cb, rcb_idx)) != BTA_GATTS_INVALID_APP) + { + /* create the service now */ + service_id = GATTS_CreateService (p_cb->rcb[rcb_idx].gatt_if, + &p_msg->api_create_svc.service_uuid, + p_msg->api_create_svc.inst, + p_msg->api_create_svc.num_handle, + p_msg->api_create_svc.is_pri); + + if (service_id != 0) + { + memcpy(&p_cb->srvc_cb[srvc_idx].service_uuid, &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID)); + p_cb->srvc_cb[srvc_idx].service_id = service_id; + p_cb->srvc_cb[srvc_idx].inst_num = p_msg->api_create_svc.inst; + p_cb->srvc_cb[srvc_idx].idx = srvc_idx; + + cb_data.create.status = BTA_GATT_OK; + cb_data.create.service_id = service_id; +// btla-specific ++ + cb_data.create.is_primary = p_msg->api_create_svc.is_pri; +// btla-specific -- + cb_data.create.server_if = p_cb->rcb[rcb_idx].gatt_if; + } + else + { + cb_data.status = BTA_GATT_ERROR; + memset(&p_cb->srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB)); + APPL_TRACE_ERROR0("service creation failed."); + } +// btla-specific ++ + memcpy(&cb_data.create.uuid, &p_msg->api_create_svc.service_uuid, sizeof(tBT_UUID)); + cb_data.create.svc_instance= p_msg->api_create_svc.inst; +// btla-specific -- + } + if (p_cb->rcb[rcb_idx].p_cback) + (* p_cb->rcb[rcb_idx].p_cback)(BTA_GATTS_CREATE_EVT, &cb_data); + } + else /* application not registered */ + { + APPL_TRACE_ERROR0("Application not registered"); + } +} +/******************************************************************************* +** +** Function bta_gatts_add_include_srvc +** +** Description action function to add an included service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb,tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddIncludeService(p_msg->api_add_incl_srvc.hdr.layer_specific, + p_msg->api_add_incl_srvc.included_service_id); + + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_INCL_SRVC_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gatts_add_char +** +** Description action function to add characteristic. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddCharacteristic(p_msg->api_add_char.hdr.layer_specific, + &p_msg->api_add_char.char_uuid, + p_msg->api_add_char.perm, + p_msg->api_add_char.property); + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; +// btla-specific ++ + memcpy(&cb_data.add_result.char_uuid, &p_msg->api_add_char.char_uuid, sizeof(tBT_UUID)); +// btla-specific -- + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_EVT, &cb_data); +} +/******************************************************************************* +** +** Function bta_gatts_add_char_descr +** +** Description action function to add characteristic descriptor. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + UINT16 attr_id = 0; + tBTA_GATTS cb_data; + + attr_id = GATTS_AddCharDescriptor(p_msg->api_add_char_descr.hdr.layer_specific, + p_msg->api_add_char_descr.perm, + &p_msg->api_add_char_descr.descr_uuid); + + cb_data.add_result.server_if = p_rcb->gatt_if; + cb_data.add_result.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + cb_data.add_result.attr_id = attr_id; +// btla-specific ++ + memcpy(&cb_data.add_result.char_uuid, &p_msg->api_add_char_descr.descr_uuid, sizeof(tBT_UUID)); +// btla-specific -- + + if (attr_id) + { + cb_data.add_result.status = BTA_GATT_OK; + } + else + { + cb_data.add_result.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_ADD_CHAR_DESCR_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_delete_service +** +** Description action function to delete a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + + if (GATTS_DeleteService(p_rcb->gatt_if, + &p_srvc_cb->service_uuid, + p_srvc_cb->inst_num)) + { + cb_data.srvc_oper.status = BTA_GATT_OK; + memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB)); + } + else + { + cb_data.srvc_oper.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_DELELTE_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_start_service +** +** Description action function to start a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific; + + if (GATTS_StartService(p_rcb->gatt_if, + p_srvc_cb->service_id, + p_msg->api_start.transport) == GATT_SUCCESS) + { + APPL_TRACE_DEBUG1("bta_gatts_start_service service_id= %d", p_srvc_cb->service_id); + cb_data.srvc_oper.status = BTA_GATT_OK; + } + else + { + cb_data.srvc_oper.status = BTA_GATT_ERROR; + } + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_START_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_stop_service +** +** Description action function to stop a service. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx]; + tBTA_GATTS cb_data; + + GATTS_StopService(p_srvc_cb->service_id); + cb_data.srvc_oper.server_if = p_rcb->gatt_if; + cb_data.srvc_oper.service_id = p_srvc_cb->service_id; + cb_data.srvc_oper.status = BTA_GATT_OK; + APPL_TRACE_ERROR1("bta_gatts_stop_service service_id= %d", p_srvc_cb->service_id); + + if (p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_STOP_EVT, &cb_data); + +} +/******************************************************************************* +** +** Function bta_gatts_send_rsp +** +** Description GATTS send response. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_send_rsp (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + + if (GATTS_SendRsp (p_msg->api_rsp.hdr.layer_specific, + p_msg->api_rsp.trans_id, + p_msg->api_rsp.status, + (tGATTS_RSP *)p_msg->api_rsp.p_rsp) != GATT_SUCCESS) + { + APPL_TRACE_ERROR0("Sending response failed"); + } + +} +/******************************************************************************* +** +** Function bta_gatts_send_rsp +** +** Description GATTS send response. +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_SRVC_CB *p_srvc_cb; + tBTA_GATT_STATUS status; + + + p_srvc_cb = bta_gatts_find_srvc_cb_by_attr_id (p_cb, p_msg->api_indicate.attr_id); + + if (p_srvc_cb ) + { + if (p_msg->api_indicate.need_confirm) + + status = GATTS_HandleValueIndication (p_msg->api_indicate.hdr.layer_specific, + p_msg->api_indicate.attr_id, + p_msg->api_indicate.len, + p_msg->api_indicate.value); + else + status = GATTS_HandleValueNotification (p_msg->api_indicate.hdr.layer_specific, + p_msg->api_indicate.attr_id, + p_msg->api_indicate.len, + p_msg->api_indicate.value); + + if (status != GATT_SUCCESS && + p_msg->api_indicate.need_confirm && + p_cb->rcb[p_srvc_cb->rcb_idx].p_cback) + { + (*p_cb->rcb[p_srvc_cb->rcb_idx].p_cback)(BTA_GATTS_CONF_EVT, (tBTA_GATTS *)&status); + } + } + else + { + APPL_TRACE_ERROR1("Not an registered servce attribute ID: 0x%04x", p_msg->api_indicate.attr_id); + } +} + + +/******************************************************************************* +** +** Function bta_gatts_open +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb=NULL; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + + + if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if)) != NULL) + { + if (GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda, p_msg->api_open.is_direct)) + { + status = BTA_GATT_OK; + } + } + else + { + APPL_TRACE_ERROR1("Inavlide server_if=%d", p_msg->api_open.server_if); + } + + if (p_rcb && p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_OPEN_EVT, (tBTA_GATTS *)&status); + +} +/******************************************************************************* +** +** Function bta_gatts_cancel_open +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + + if ((p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_cancel_open.server_if)) != NULL) + { + if (!GATT_CancelConnect(p_rcb->gatt_if, p_msg->api_cancel_open.remote_bda, p_msg->api_cancel_open.is_direct)) + { + APPL_TRACE_ERROR0("bta_gatts_cancel_open failed for open request"); + } + else + { + status= BTA_GATT_OK; + } + } + else + { + APPL_TRACE_ERROR1("Inavlide server_if=%d", p_msg->api_cancel_open.server_if); + } + + if (p_rcb && p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_CANCEL_OPEN_EVT, (tBTA_GATTS *)&status); +} +/******************************************************************************* +** +** Function bta_gatts_close +** +** Description +** +** Returns none. +** +*******************************************************************************/ +void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg) +{ + tBTA_GATTS_RCB *p_rcb; + tBTA_GATT_STATUS status= BTA_GATT_ERROR; + tGATT_IF gatt_if; + BD_ADDR remote_bda; + + if (GATT_GetConnectionInfor(p_msg->hdr.layer_specific, &gatt_if, remote_bda)) + { + if (GATT_Disconnect(p_msg->hdr.layer_specific) != GATT_SUCCESS) + { + APPL_TRACE_ERROR1("bta_gatts_close fail conn_id=%d", p_msg->hdr.layer_specific); + } + else + { + status= BTA_GATT_OK; + } + + p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + if (p_rcb && p_rcb->p_cback) + (*p_rcb->p_cback)(BTA_GATTS_CLOSE_EVT, (tBTA_GATTS *)&status); + } + else + { + APPL_TRACE_ERROR1("Unknown connection ID: %d", p_msg->hdr.layer_specific); + } + +} + + +/******************************************************************************* +** +** Function bta_gatts_request_cback +** +** Description GATTS attribute request callback. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_send_request_cback (UINT16 conn_id, + UINT32 trans_id, + tGATTS_REQ_TYPE req_type, tGATTS_DATA *p_data) +{ + tBTA_GATTS cb_data; + tBTA_GATTS_RCB *p_rcb; + tGATT_IF gatt_if; + + memset(&cb_data, 0 , sizeof(tBTA_GATTS)); + + if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda)) + { + p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + APPL_TRACE_DEBUG3 ("bta_gatts_send_request_cback conn_id=%d trans_id=%d req_type=%d", conn_id, trans_id, req_type); + + if (p_rcb && p_rcb->p_cback) + { + cb_data.req_data.conn_id = conn_id; + cb_data.req_data.trans_id = trans_id; + cb_data.req_data.p_data = (tBTA_GATTS_REQ_DATA *)p_data; + + (*p_rcb->p_cback)(req_type, &cb_data); + } + else + { + APPL_TRACE_ERROR1("connection request on gatt_if[%d] is not interested", gatt_if); + } + } + else + { + APPL_TRACE_ERROR1("request received on unknown connectino ID: %d", conn_id); + } +} + +/******************************************************************************* +** +** Function bta_gatts_conn_cback +** +** Description connection callback. +** +** Returns none. +** +*******************************************************************************/ +static void bta_gatts_conn_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, + BOOLEAN connected, tGATT_DISCONN_REASON reason) +{ + tBTA_GATTS cb_data; + UINT8 evt = connected ? BTA_GATTS_CONNECT_EVT: BTA_GATTS_DISCONNECT_EVT; + tBTA_GATTS_RCB *p_reg; + + APPL_TRACE_DEBUG4 ("bta_gatts_conn_cback gatt_if=%d conn_id=%d connected=%d reason = 0x%04d", + gatt_if, conn_id, connected, reason); + APPL_TRACE_DEBUG6("bta_gatts_conn_cback bda :%02x-%02x-%02x-%02x-%02x-%02x ", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + + p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if); + + if (p_reg && p_reg->p_cback) + { + cb_data.conn.conn_id = conn_id; + cb_data.conn.server_if = gatt_if; + cb_data.conn.reason = reason; + memcpy(cb_data.conn.remote_bda, bda, BD_ADDR_LEN); + (*p_reg->p_cback)(evt, &cb_data); + } + else + { + APPL_TRACE_ERROR1("bta_gatts_conn_cback server_if=%d not found",gatt_if); + } +} +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_api.c b/bta/gatt/bta_gatts_api.c new file mode 100644 index 0000000..65df0a6 --- /dev/null +++ b/bta/gatt/bta_gatts_api.c @@ -0,0 +1,512 @@ +/****************************************************************************** + * + * Copyright (C) 2010-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 of the API for GATT server of BTA. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "bta_gatts_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_gatts_reg = +{ + bta_gatts_hdl_event, + NULL /* need a disable functino to be called when BT is disabled */ +}; + +/******************************************************************************* +** +** Function BTA_GATTS_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTS module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_cback - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback) +{ + tBTA_GATTS_API_REG *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + if (!bta_gatts_cb.enabled) + { + bta_sys_register(BTA_ID_GATTS, &bta_gatts_reg); + } + GKI_sched_unlock(); + + if ((p_buf = (tBTA_GATTS_API_REG *) GKI_getbuf(sizeof(tBTA_GATTS_API_REG))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_REG_EVT; + + if (p_app_uuid != NULL) + memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID)); + p_buf->p_cback = p_cback; + + bta_sys_sendmsg(p_buf); + } + return; +} + + + +/******************************************************************************* +** +** Function BTA_GATTS_AppDeregister +** +** Description De-register with GATT Server. +** +** Parameters app_id: applicatino ID. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if) +{ + tBTA_GATTS_API_DEREG *p_buf; + + if ((p_buf = (tBTA_GATTS_API_DEREG *) GKI_getbuf(sizeof(tBTA_GATTS_API_DEREG))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_DEREG_EVT; + p_buf->server_if = server_if; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_CreateService +** +** Description Create a service. When service creation is done, a callback +** event BTA_GATTS_CREATE_SRVC_EVT is called to report status +** and service ID to the profile. The service ID obtained in +** the callback function needs to be used when adding included +** service and characteristics/descriptors into the service. +** +** Parameters app_id: Profile ID this service is belonged to. +** p_service_uuid: service UUID. +** inst: instance ID number of this service. +** num_handle: numble of handle requessted for this service. +** is_primary: is this service a primary one or not. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid, UINT8 inst, + UINT16 num_handle, BOOLEAN is_primary) +{ + tBTA_GATTS_API_CREATE_SRVC *p_buf; + + if ((p_buf = (tBTA_GATTS_API_CREATE_SRVC *) GKI_getbuf(sizeof(tBTA_GATTS_API_CREATE_SRVC))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_CREATE_SRVC_EVT; + + p_buf->server_if = server_if; + p_buf->inst = inst; + memcpy(&p_buf->service_uuid, p_service_uuid, sizeof(tBT_UUID)); + p_buf->num_handle = num_handle; + p_buf->is_pri = is_primary; + + bta_sys_sendmsg(p_buf); + } + return; +} +/******************************************************************************* +** +** Function BTA_GATTS_AddIncludeService +** +** Description This function is called to add an included service. After included +** service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT +** is reported the included service ID. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** included_service_id: the service ID to be included. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_service_id) +{ + tBTA_GATTS_API_ADD_INCL_SRVC *p_buf; + + if ((p_buf = + (tBTA_GATTS_API_ADD_INCL_SRVC *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_INCL_SRVC))) + != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_ADD_INCL_SRVC_EVT; + + p_buf->hdr.layer_specific = service_id; + p_buf->included_service_id = included_service_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTS_AddCharacteristic +** +** Description This function is called to add a characteristic into a service. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** p_char_uuid : Characteristic UUID. +** perm : Characteristic value declaration attribute permission. +** property : Characteristic Properties +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid, + tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property) +{ + tBTA_GATTS_API_ADD_CHAR *p_buf; + + if ((p_buf = (tBTA_GATTS_API_ADD_CHAR *) GKI_getbuf(sizeof(tBTA_GATTS_API_ADD_CHAR))) != NULL) + { + memset(p_buf, 0, sizeof(tBTA_GATTS_API_ADD_CHAR)); + + p_buf->hdr.event = BTA_GATTS_API_ADD_CHAR_EVT; + p_buf->hdr.layer_specific = service_id; + p_buf->perm = perm; + p_buf->property = property; + + if (p_char_uuid) + { + memcpy(&p_buf->char_uuid, p_char_uuid, sizeof(tBT_UUID)); + } + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_AddCharDescriptor +** +** Description This function is called to add characteristic descriptor. When +** it's done, a callback event BTA_GATTS_ADD_DESCR_EVT is called +** to report the status and an ID number for this descriptor. +** +** Parameters service_id: service ID to which this charatceristic descriptor is to +** be added. +** perm: descriptor access permission. +** p_descr_uuid: descriptor UUID. +** +** Returns returns status. +** +*******************************************************************************/ +void BTA_GATTS_AddCharDescriptor (UINT16 service_id, + tBTA_GATT_PERM perm, + tBT_UUID * p_descr_uuid) +{ + tBTA_GATTS_API_ADD_DESCR *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_ADD_DESCR); + + + if ((p_buf = (tBTA_GATTS_API_ADD_DESCR *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_ADD_DESCR_EVT; + p_buf->hdr.layer_specific = service_id; + p_buf->perm = perm; + + if (p_descr_uuid) + { + memcpy(&p_buf->descr_uuid, p_descr_uuid, sizeof(tBT_UUID)); + } + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTS_DeleteService +** +** Description This function is called to delete a service. When this is done, +** a callback event BTA_GATTS_DELETE_EVT is report with the status. +** +** Parameters service_id: service_id to be deleted. +** +** Returns returns none. +** +*******************************************************************************/ +void BTA_GATTS_DeleteService(UINT16 service_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_DEL_SRVC_EVT; + + p_buf->layer_specific = service_id; + + bta_sys_sendmsg(p_buf); + } + return; + +} + +/******************************************************************************* +** +** Function BTA_GATTS_StartService +** +** Description This function is called to start a service. +** +** Parameters service_id: the service ID to be started. +** sup_transport: supported trasnport. +** +** Returns None. +** +*******************************************************************************/ +void BTA_GATTS_StartService(UINT16 service_id, tBTA_GATT_TRANSPORT sup_transport) +{ + tBTA_GATTS_API_START *p_buf; + + if ((p_buf = (tBTA_GATTS_API_START *) GKI_getbuf(sizeof(tBTA_GATTS_API_START))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_START_SRVC_EVT; + + p_buf->hdr.layer_specific = service_id; + p_buf->transport = sup_transport; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_StopService +** +** Description This function is called to stop a service. +** +** Parameters service_id - service to be topped. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_StopService(UINT16 service_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_STOP_SRVC_EVT; + + p_buf->layer_specific = service_id; + + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_HandleValueIndication +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters bda - remote device bd address to indicate. +** attr_id - attribute ID to indicate. +** data_len - indicate data length. +** p_data: data to indicate. +** need_confirm - if this indication expects a confirmation or not. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id, UINT16 data_len, + UINT8 *p_data, BOOLEAN need_confirm) +{ + tBTA_GATTS_API_INDICATION *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_INDICATION); + + if ((p_buf = (tBTA_GATTS_API_INDICATION *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_INDICATION_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->attr_id = attr_id; + p_buf->need_confirm = need_confirm; + + if (data_len > 0 && p_data != NULL) + { + p_buf->len = data_len; + memcpy(p_buf->value, p_data, data_len); + + } + bta_sys_sendmsg(p_buf); + } + return; + +} +/******************************************************************************* +** +** Function BTA_GATTS_SendRsp +** +** Description This function is called to send a response to a request. +** +** Parameters conn_id - connection identifier. +** trans_id - transaction ID. +** status - response status +** p_msg - response data. +** +** Returns None +** +*******************************************************************************/ +void BTA_GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, + tBTA_GATT_STATUS status, tBTA_GATTS_RSP *p_msg) +{ + tBTA_GATTS_API_RSP *p_buf; + UINT16 len = sizeof(tBTA_GATTS_API_RSP) + sizeof(tBTA_GATTS_RSP); + + if ((p_buf = (tBTA_GATTS_API_RSP *) GKI_getbuf(len)) != NULL) + { + memset(p_buf, 0, len); + + p_buf->hdr.event = BTA_GATTS_API_RSP_EVT; + p_buf->hdr.layer_specific = conn_id; + p_buf->trans_id = trans_id; + p_buf->status = status; + + if (p_msg != NULL) + { + p_buf->p_rsp = (tBTA_GATTS_RSP *)(p_buf + 1); + memcpy(p_buf->p_rsp, p_msg, sizeof(tBTA_GATTS_RSP)); + } + + bta_sys_sendmsg(p_buf); + } + return; + +} + + + +/******************************************************************************* +** +** Function BTA_GATTS_Open +** +** Description Open a direct open connection or add a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTS_API_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTS_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTS_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_OPEN_EVT; + p_buf->server_if = server_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + + bta_sys_sendmsg(p_buf); + } + return; +} + + +/******************************************************************************* +** +** Function BTA_GATTS_CancelOpen +** +** Description Cancel a direct open connection or remove a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct) +{ + tBTA_GATTS_API_CANCEL_OPEN *p_buf; + + if ((p_buf = (tBTA_GATTS_API_CANCEL_OPEN *) GKI_getbuf(sizeof(tBTA_GATTS_API_CANCEL_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_GATTS_API_CANCEL_OPEN_EVT; + p_buf->server_if = server_if; + p_buf->is_direct = is_direct; + memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); + bta_sys_sendmsg(p_buf); + } + return; +} + +/******************************************************************************* +** +** Function BTA_GATTS_Close +** +** Description Close a connection a remote device. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_GATTS_Close(UINT16 conn_id) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_GATTS_API_CLOSE_EVT; + p_buf->layer_specific = conn_id; + bta_sys_sendmsg(p_buf); + } + return; + +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_int.h b/bta/gatt/bta_gatts_int.h new file mode 100644 index 0000000..4810c05 --- /dev/null +++ b/bta/gatt/bta_gatts_int.h @@ -0,0 +1,246 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 private file for the BTA GATT server. + * + ******************************************************************************/ +#ifndef BTA_GATTS_INT_H +#define BTA_GATTS_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "bta_gatt_api.h" +#include "gatt_api.h" +//#include "bta_gatts_co.h" + +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +enum +{ + BTA_GATTS_API_REG_EVT = BTA_SYS_EVT_START(BTA_ID_GATTS), + BTA_GATTS_INT_START_IF_EVT, + BTA_GATTS_API_DEREG_EVT, + BTA_GATTS_API_CREATE_SRVC_EVT, + BTA_GATTS_API_INDICATION_EVT, + + BTA_GATTS_API_ADD_INCL_SRVC_EVT, + BTA_GATTS_API_ADD_CHAR_EVT, + BTA_GATTS_API_ADD_DESCR_EVT, + BTA_GATTS_API_DEL_SRVC_EVT, + BTA_GATTS_API_START_SRVC_EVT, + BTA_GATTS_API_STOP_SRVC_EVT, + BTA_GATTS_API_RSP_EVT, + BTA_GATTS_API_OPEN_EVT, + BTA_GATTS_API_CANCEL_OPEN_EVT, + BTA_GATTS_API_CLOSE_EVT + +}; +typedef UINT16 tBTA_GATTS_INT_EVT; + +/* max number of application allowed on device */ +#define BTA_GATTS_MAX_APP_NUM GATT_MAX_SR_PROFILES + +/* max number of services allowed in the device */ +#define BTA_GATTS_MAX_SRVC_NUM GATT_MAX_SR_PROFILES + +/* internal strucutre for GATTC register API */ +typedef struct +{ + BT_HDR hdr; + tBT_UUID app_uuid; + tBTA_GATTS_CBACK *p_cback; +}tBTA_GATTS_API_REG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTS_IF server_if; +}tBTA_GATTS_INT_START_IF; + +typedef tBTA_GATTS_INT_START_IF tBTA_GATTS_API_DEREG; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATTS_IF server_if; + tBT_UUID service_uuid; + UINT16 num_handle; + UINT8 inst; + BOOLEAN is_pri; + +} tBTA_GATTS_API_CREATE_SRVC; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID char_uuid; + tBTA_GATT_PERM perm; + tBTA_GATT_CHAR_PROP property; + +}tBTA_GATTS_API_ADD_CHAR; + +typedef struct +{ + BT_HDR hdr; + UINT16 included_service_id; + +}tBTA_GATTS_API_ADD_INCL_SRVC; + +typedef struct +{ + BT_HDR hdr; + tBT_UUID descr_uuid; + tBTA_GATT_PERM perm; +}tBTA_GATTS_API_ADD_DESCR; + +typedef struct +{ + BT_HDR hdr; + //todo BD_ADDR bd_addr; + UINT16 attr_id; + UINT16 len; + BOOLEAN need_confirm; + UINT8 value[BTA_GATT_MAX_ATTR_LEN]; +}tBTA_GATTS_API_INDICATION; + +typedef struct +{ + BT_HDR hdr; + UINT32 trans_id; + tBTA_GATT_STATUS status; + tBTA_GATTS_RSP *p_rsp; +}tBTA_GATTS_API_RSP; + +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_TRANSPORT transport; +}tBTA_GATTS_API_START; + + +typedef struct +{ + BT_HDR hdr; + BD_ADDR remote_bda; + tBTA_GATTS_IF server_if; + BOOLEAN is_direct; +}tBTA_GATTS_API_OPEN; + +typedef tBTA_GATTS_API_OPEN tBTA_GATTS_API_CANCEL_OPEN; + +typedef union +{ + BT_HDR hdr; + tBTA_GATTS_API_REG api_reg; + tBTA_GATTS_API_DEREG api_dereg; + tBTA_GATTS_API_CREATE_SRVC api_create_svc; + tBTA_GATTS_API_ADD_INCL_SRVC api_add_incl_srvc; + tBTA_GATTS_API_ADD_CHAR api_add_char; + tBTA_GATTS_API_ADD_DESCR api_add_char_descr; + tBTA_GATTS_API_START api_start; + tBTA_GATTS_API_INDICATION api_indicate; + tBTA_GATTS_API_RSP api_rsp; + tBTA_GATTS_API_OPEN api_open; + tBTA_GATTS_API_CANCEL_OPEN api_cancel_open; + + tBTA_GATTS_INT_START_IF int_start_if; +} tBTA_GATTS_DATA; + +/* application registration control block */ +typedef struct +{ + BOOLEAN in_use; + tBT_UUID app_uuid; + tBTA_GATTS_CBACK *p_cback; + tBTA_GATTS_IF gatt_if; //todo cahneg to server_if +}tBTA_GATTS_RCB; + +/* service registration control block */ +typedef struct +{ + tBT_UUID service_uuid; /* service UUID */ + UINT16 service_id; /* service handle */ + UINT8 inst_num; /* instance ID */ + UINT8 rcb_idx; + UINT8 idx; /* self index of serviec CB */ + BOOLEAN in_use; + +}tBTA_GATTS_SRVC_CB; + + +/* GATT server control block */ +typedef struct +{ + BOOLEAN enabled; + tBTA_GATTS_RCB rcb[BTA_GATTS_MAX_APP_NUM]; + tBTA_GATTS_SRVC_CB srvc_cb[BTA_GATTS_MAX_SRVC_NUM]; +}tBTA_GATTS_CB; + + + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* GATTC control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_GATTS_CB bta_gatts_cb; +#else +extern tBTA_GATTS_CB *bta_gatts_cb_ptr; + #define bta_gatts_cb (*bta_gatts_cb_ptr) +#endif + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg); + +extern void bta_gatts_register(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_start_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_deregister(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg); +extern void bta_gatts_create_srvc(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_include_srvc(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_char(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_add_char_descr(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_start_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB *p_srvc_cb, tBTA_GATTS_DATA * p_msg); + +extern void bta_gatts_send_rsp(tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); + + +extern void bta_gatts_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_cancel_open (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); +extern void bta_gatts_close (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA * p_msg); + +extern BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src); +extern tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if); +extern UINT8 bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_IF server_if); +extern UINT8 bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB *p_cb, UINT8 rcb_idx); +extern tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB *p_cb, UINT16 service_id); +extern tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB *p_cb, UINT16 attr_id); + + +#endif /* BTA_GATTS_INT_H */ + diff --git a/bta/gatt/bta_gatts_main.c b/bta/gatt/bta_gatts_main.c new file mode 100644 index 0000000..e2b2494 --- /dev/null +++ b/bta/gatt/bta_gatts_main.c @@ -0,0 +1,134 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the GATT server main functions and state machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> + +#include "bta_gatts_int.h" +#include "gki.h" + +/* type for service building action functions */ +typedef void (*tBTA_GATTS_SRVC_ACT)(tBTA_GATTS_SRVC_CB *p_rcb, tBTA_GATTS_DATA *p_data); + +/* service building action function list */ +const tBTA_GATTS_SRVC_ACT bta_gatts_srvc_build_act[] = +{ + bta_gatts_add_include_srvc, + bta_gatts_add_char, + bta_gatts_add_char_descr, + bta_gatts_delete_service, + bta_gatts_start_service, + bta_gatts_stop_service, +}; + +/* GATTS control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_GATTS_CB bta_gatts_cb; +#endif + +/******************************************************************************* +** +** Function bta_gatts_hdl_event +** +** Description BTA GATT server main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_gatts_hdl_event(BT_HDR *p_msg) +{ + tBTA_GATTS_CB *p_cb = &bta_gatts_cb; + tBTA_GATTS_SRVC_CB *p_srvc_cb = NULL; + + switch (p_msg->event) + { + case BTA_GATTS_API_REG_EVT: + bta_gatts_register(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_INT_START_IF_EVT: + bta_gatts_start_if(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_DEREG_EVT: + bta_gatts_deregister(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CREATE_SRVC_EVT: + bta_gatts_create_srvc(p_cb, (tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_INDICATION_EVT: + bta_gatts_indicate_handle(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_OPEN_EVT: + bta_gatts_open(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CANCEL_OPEN_EVT: + bta_gatts_cancel_open(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_CLOSE_EVT: + bta_gatts_close(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_RSP_EVT: + bta_gatts_send_rsp(p_cb,(tBTA_GATTS_DATA *) p_msg); + break; + + case BTA_GATTS_API_ADD_INCL_SRVC_EVT: + case BTA_GATTS_API_ADD_CHAR_EVT: + case BTA_GATTS_API_ADD_DESCR_EVT: + case BTA_GATTS_API_DEL_SRVC_EVT: + case BTA_GATTS_API_START_SRVC_EVT: + case BTA_GATTS_API_STOP_SRVC_EVT: + + p_srvc_cb = bta_gatts_find_srvc_cb_by_srvc_id(p_cb, + ((tBTA_GATTS_DATA *)p_msg)->api_add_incl_srvc.hdr.layer_specific); + + if (p_srvc_cb != NULL) + { + bta_gatts_srvc_build_act[p_msg->event - BTA_GATTS_API_ADD_INCL_SRVC_EVT](p_srvc_cb, (tBTA_GATTS_DATA *) p_msg); + } + else + { + APPL_TRACE_ERROR0("service not created"); + } + break; + + default: + break; + } + + + return (TRUE); +} + +#endif /* BTA_GATT_INCLUDED */ diff --git a/bta/gatt/bta_gatts_utils.c b/bta/gatt/bta_gatts_utils.c new file mode 100644 index 0000000..5145c95 --- /dev/null +++ b/bta/gatt/bta_gatts_utils.c @@ -0,0 +1,235 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the GATT client utility function. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) + +#include <string.h> +#include "utl.h" +#include "gki.h" +#include "bta_sys.h" +#include "bta_gatts_int.h" +#include "bd.h" + +static const UINT8 base_uuid[LEN_UUID_128] = {0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/******************************************************************************* +** +** Function bta_gatt_convert_uuid16_to_uuid128 +** +** Description Convert a 16 bits UUID to be an standard 128 bits one. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +static void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UINT16 uuid_16) +{ + UINT8 *p = &uuid_128[LEN_UUID_128 - 4]; + + memcpy (uuid_128, base_uuid, LEN_UUID_128); + + UINT16_TO_STREAM(p, uuid_16); +} +/******************************************************************************* +** +** Function bta_gatts_alloc_srvc_cb +** +** Description allocate a service control block. +** +** Returns pointer to the control block, or otherwise NULL when failed. +** +*******************************************************************************/ +UINT8 bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB *p_cb, UINT8 rcb_idx) +{ + UINT8 i; + + for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i ++) + { + if (!p_cb->srvc_cb[i].in_use) + { + p_cb->srvc_cb[i].in_use = TRUE; + p_cb->srvc_cb[i].rcb_idx = rcb_idx; + return i; + } + } + return BTA_GATTS_INVALID_APP; +} + +/******************************************************************************* +** +** Function bta_gatts_find_app_rcb_by_app_if +** +** Description find the index of the application control block by app ID. +** +** Returns pointer to the control block if success, otherwise NULL +** +*******************************************************************************/ +tBTA_GATTS_RCB *bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if) +{ + UINT8 i; + tBTA_GATTS_RCB *p_reg; + + for (i = 0, p_reg = bta_gatts_cb.rcb; i < BTA_GATTS_MAX_APP_NUM; i ++, p_reg++) + { + if (p_reg->in_use && p_reg->gatt_if == server_if) + return p_reg; + } + return NULL; +} + +/******************************************************************************* +** +** Function bta_gatts_find_app_rcb_idx_by_app_if +** +** Description find the index of the application control block by app ID. +** +** Returns index of the control block, or BTA_GATTS_INVALID_APP if failed. +** +*******************************************************************************/ + +UINT8 bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB *p_cb, tBTA_GATTS_IF server_if) +{ + UINT8 i; + + for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i ++) + { + if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == server_if) + return i; + } + return BTA_GATTS_INVALID_APP; +} +/******************************************************************************* +** +** Function bta_gatts_find_srvc_cb_by_srvc_id +** +** Description find the service control block by service ID. +** +** Returns pointer to the rcb. +** +*******************************************************************************/ +tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB *p_cb, UINT16 service_id) +{ + UINT8 i; + APPL_TRACE_DEBUG1("bta_gatts_find_srvc_cb_by_srvc_id service_id=%d", service_id); + for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i ++) + { + if (p_cb->srvc_cb[i].in_use && + p_cb->srvc_cb[i].service_id == service_id) + { + APPL_TRACE_DEBUG1("bta_gatts_find_srvc_cb_by_srvc_id found service cb index =%d", i); + return &p_cb->srvc_cb[i]; + } + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gatts_find_srvc_cb_by_attr_id +** +** Description find the service control block by attribute ID. +** +** Returns pointer to the rcb. +** +*******************************************************************************/ +tBTA_GATTS_SRVC_CB * bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB *p_cb, UINT16 attr_id) +{ + UINT8 i; + + for (i = 0; i < (BTA_GATTS_MAX_SRVC_NUM); i ++) + { + if (/* middle service */ + (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && + p_cb->srvc_cb[i].in_use && + p_cb->srvc_cb[i + 1].in_use && + attr_id >= p_cb->srvc_cb[i].service_id && + attr_id < p_cb->srvc_cb[i + 1].service_id) || + /* last active service */ + (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && + p_cb->srvc_cb[i].in_use && + !p_cb->srvc_cb[i + 1].in_use && + attr_id >= p_cb->srvc_cb[i].service_id) || + /* last service incb */ + (i == (BTA_GATTS_MAX_SRVC_NUM - 1) && + attr_id >= p_cb->srvc_cb[i].service_id) + ) + { + return &p_cb->srvc_cb[i]; + } + } + return NULL; +} +/******************************************************************************* +** +** Function bta_gatts_uuid_compare +** +** Description Compare two UUID to see if they are the same. +** +** Returns TRUE if two uuid match; FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src) +{ + UINT8 su[LEN_UUID_128], tu[LEN_UUID_128]; + UINT8 *ps, *pt; + + /* any of the UUID is unspecified */ + if (src.len == 0 || tar.len == 0) + { + return TRUE; + } + + /* If both are 16-bit, we can do a simple compare */ + if (src.len == 2 && tar.len == 2) + { + return src.uu.uuid16 == tar.uu.uuid16; + } + + /* One or both of the UUIDs is 128-bit */ + if (src.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16); + ps = su; + } + else + ps = src.uu.uuid128; + + if (tar.len == LEN_UUID_16) + { + /* convert a 16 bits UUID to 128 bits value */ + bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16); + pt = tu; + } + else + pt = tar.uu.uuid128; + + return(memcmp(ps, pt, LEN_UUID_128) == 0); +} + + + + +#endif diff --git a/bta/hh/bta_hh_act.c b/bta/hh/bta_hh_act.c new file mode 100644 index 0000000..de08096 --- /dev/null +++ b/bta/hh/bta_hh_act.c @@ -0,0 +1,1197 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the HID host action functions. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE) + +#include <string.h> + +#include "bta_sys.h" +#include "btm_api.h" +#include "l2c_api.h" +#include "bta_hh_int.h" +#include "bta_hh_co.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + + +/***************************************************************************** +** Local Function prototypes +*****************************************************************************/ +static void bta_hh_cback (UINT8 dev_handle, UINT8 event, UINT32 data, + BT_HDR *pdata); +static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result); + +#if BTA_HH_DEBUG +static char* bta_hh_get_w4_event(UINT16 event); +static char * bta_hh_hid_event_name(UINT16 event); +#endif + +/***************************************************************************** +** Action Functions +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_hh_api_enable +** +** Description Perform necessary operations to enable HID host. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_api_enable(tBTA_HH_DATA *p_data) +{ + tBTA_HH_STATUS status = BTA_HH_ERR; + UINT8 xx; + + /* initialize BTE HID */ + HID_HostInit(); + + memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB)); + + HID_HostSetSecurityLevel("", p_data->api_enable.sec_mask); + + /* Register with L2CAP */ + if ( HID_HostRegister (bta_hh_cback) == HID_SUCCESS) + { + /* store parameters */ + bta_hh_cb.p_cback = p_data->api_enable.p_cback; + + status = BTA_HH_OK; + /* initialize device CB */ + for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++) + { + bta_hh_cb.kdev[xx].state = BTA_HH_IDLE_ST; + bta_hh_cb.kdev[xx].hid_handle = BTA_HH_INVALID_HANDLE; + bta_hh_cb.kdev[xx].index = xx; + /* initialize control block map */ + bta_hh_cb.cb_index[xx] = BTA_HH_MAX_KNOWN; + } + } + + /* signal BTA call back event */ + (* bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH *)&status); +} +/******************************************************************************* +** +** Function bta_hh_api_disable +** +** Description Perform necessary operations to disable HID host. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_api_disable(void) +{ + UINT8 xx; + + /* service is not enabled */ + if (bta_hh_cb.p_cback == NULL) + return; + + /* no live connection, signal DISC_CMPL_EVT directly */ + if (!bta_hh_cb.cnt_num) + { + bta_hh_disc_cmpl(); + } + else /* otherwise, disconnect all live connections */ + { + bta_hh_cb.w4_disable = TRUE; + + for(xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++) + { + /* send API_CLOSE event to every connected device */ + if ( bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST ) + { + /* disconnect all connected devices */ + bta_hh_sm_execute(&bta_hh_cb.kdev[xx], + BTA_HH_API_CLOSE_EVT, + NULL); + } + } + } + + return; +} + +/******************************************************************************* +** +** Function bta_hh_disc_cmpl +** +** Description All connections have been closed, disable service. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_disc_cmpl(void) +{ + UINT8 xx; + tBTA_HH_STATUS status = BTA_HH_OK; + + /* Deregister with lower layer */ + if (HID_HostDeregister()!= HID_SUCCESS) + status = BTA_HH_ERR; + + /* free buffer in CB holding report descriptors */ + for(xx = 0; xx < BTA_HH_MAX_KNOWN; xx ++) + { + utl_freebuf((void **)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list); + } + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + + (* bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH *)&status); + /* all connections are down, no waiting for diconnect */ + memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB)); +} +/******************************************************************************* +** +** Function bta_hh_sdp_cback +** +** Description SDP callback function. +** +** Returns void +** +*******************************************************************************/ +static void bta_hh_sdp_cback(UINT16 result, UINT16 attr_mask, + tHID_DEV_SDP_INFO *sdp_rec ) +{ + tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur; + UINT8 hdl; + tBTA_HH_STATUS status = BTA_HH_ERR_SDP; + + if (result == SDP_SUCCESS) + { + /* security is required for the connection, add attr_mask bit*/ + if (p_cb->sec_mask) + attr_mask |= HID_SEC_REQUIRED; + +#if BTA_HH_DEBUG + APPL_TRACE_EVENT3("bta_hh_sdp_cback: p_cb: %d result 0x%02x, \ + attr_mask 0x%02x", \ + p_cb, result, attr_mask); +#endif + + /* check to see type of device is supported , and should not been added before */ + if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class)) + { + /* if not added before */ + if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) + { + /* add device/update attr_mask information */ + if(HID_HostAddDev (p_cb->addr, attr_mask, &hdl) == HID_SUCCESS) + { + status = BTA_HH_OK; + /* update cb_index[] map */ + bta_hh_cb.cb_index[hdl] = p_cb->index; + } + else + { + p_cb->app_id = 0; + } + } + /* else : incoming connection after SDP should update the SDP information as well */ + + if (p_cb->app_id != 0) + { + /* update cb information with attr_mask, dscp_info etc. */ + bta_hh_add_device_to_list(p_cb, hdl, attr_mask, + &sdp_rec->dscp_info, + sdp_rec->sub_class, + sdp_rec->ssr_max_latency, + sdp_rec->ssr_min_tout, + p_cb->app_id); + + p_cb->dscp_info.ctry_code = sdp_rec->ctry_code; + + status = BTA_HH_OK; + } + + } + else /* type of device is not supported */ + status = BTA_HH_ERR_TOD_UNSPT; + } + + /* free disc_db when SDP is completed */ + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + + + /* send SDP_CMPL_EVT into state machine */ + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + + return; +} +/******************************************************************************* +** +** Function bta_hh_di_sdp_cback +** +** Description SDP DI callback function. +** +** Returns void +** +*******************************************************************************/ +static void bta_hh_di_sdp_cback(UINT16 result) +{ + tBTA_HH_DEV_CB *p_cb = bta_hh_cb.p_cur; + tBTA_HH_STATUS status = BTA_HH_ERR_SDP; + tSDP_DI_GET_RECORD di_rec; + tHID_STATUS ret; +#if BTA_HH_DEBUG + APPL_TRACE_EVENT2("bta_hh_di_sdp_cback: p_cb: %d result 0x%02x", p_cb, result); +#endif + /* if DI record does not exist on remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be + * set to 0xffff and we will allow the connection to go through. Spec mandates that DI + * record be set, but many HID devices do not set this. So for IOP purposes, we allow the + * connection to go through and update the DI record to invalid DI entry.*/ + if ((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) + { + if(result == SDP_SUCCESS && SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) + { + /* always update information with primary DI record */ + if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS) + { + bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product, di_rec.rec.version); + } + + } + else /* no DI recrod available */ + { + bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0); + } + + if ((ret = HID_HostGetSDPRecord(p_cb->addr, + bta_hh_cb.p_disc_db, + p_bta_hh_cfg->sdp_db_size, + bta_hh_sdp_cback)) == HID_SUCCESS) + { + status = BTA_HH_OK; + } + else + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1 ("bta_hh_di_sdp_cback: HID_HostGetSDPRecord failed: Status 0x%2x", + ret); +#endif + } + } + + + if (status != BTA_HH_OK) + { + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + /* send SDP_CMPL_EVT into state machine */ + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + } + return; + +} + + +/******************************************************************************* +** +** Function bta_hh_start_sdp +** +** Description Start SDP service search, and obtain necessary SDP records. +** Only one SDP service search request is allowed at the same +** time. For every BTA_HhOpen API call, do SDP first unless SDP +** has been done previously. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_STATUS status = BTA_HH_ERR_SDP; + UINT8 hdl; + + p_cb->sec_mask = p_data->api_conn.sec_mask; + p_cb->mode = p_data->api_conn.mode; + + /* if previously virtually cabled device, skip SDP */ + if (p_cb->app_id) + { + status = BTA_HH_OK; +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG0("bta_hh_start_sdp:: skip SDP for known devices"); +#endif + if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) + { + if ((HID_HostAddDev (p_cb->addr, p_cb->attr_mask, &hdl)) \ + == HID_SUCCESS) + { + /* update device CB with newly register device handle */ + bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, NULL, + p_cb->sub_class, + p_cb->dscp_info.ssr_max_latency, + p_cb->dscp_info.ssr_min_tout, + p_cb->app_id); + /* update cb_index[] map */ + bta_hh_cb.cb_index[hdl] = p_cb->index; + } + else + { + status = BTA_HH_ERR_SDP; + } + } + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + + return; + } + /* GetSDPRecord. at one time only one SDP precedure can be active */ + else if (!bta_hh_cb.p_disc_db) + { + bta_hh_cb.p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(p_bta_hh_cfg->sdp_db_size); + + if (bta_hh_cb.p_disc_db == NULL) + { + status = BTA_HH_ERR_NO_RES; + } + else + { + bta_hh_cb.p_cur = p_cb; + /* do DI discovery first */ + if (SDP_DiDiscover(p_data->api_conn.bd_addr, + bta_hh_cb.p_disc_db, + p_bta_hh_cfg->sdp_db_size, + bta_hh_di_sdp_cback) != SDP_SUCCESS) + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1 ("bta_hh_start_sdp: SDP_DiDiscover failed: \ + Status 0x%2X",status); +#endif + status = BTA_HH_ERR_SDP; + utl_freebuf((void **)&bta_hh_cb.p_disc_db); + } + else + status = BTA_HH_OK; + } + } + + if (status != BTA_HH_OK) + bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA *)&status); + + return; + +} +/******************************************************************************* +** +** Function bta_hh_sdp_cmpl +** +** Description When SDP completed, initiate a connection or report error depend +** on SDP result. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CONN conn_dat; + tBTA_HH_STATUS status = p_data->status; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1 ("bta_hh_sdp_cmpl: status 0x%2X",p_data->status); +#endif + + /* initialize call back data */ + memset((void *)&conn_dat, 0, sizeof(tBTA_HH_CONN)); + conn_dat.handle = p_cb->hid_handle; + bdcpy(conn_dat.bda, p_cb->addr); + + /* if SDP compl success */ + if ( status == BTA_HH_OK) + { + /* not incoming connection doing SDP, initiate a HID connection */ + if (!p_cb->incoming_conn) + { + tHID_STATUS ret; + /* set security level */ + HID_HostSetSecurityLevel("", p_cb->sec_mask); + + /* open HID connection */ + if ((ret = HID_HostOpenDev (p_cb->hid_handle)) != HID_SUCCESS) + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1 ("bta_hh_sdp_cmpl: HID_HostOpenDev failed: \ + Status 0x%2X",ret); +#endif + /* open fail, remove device from management device list */ + HID_HostRemoveDev( p_cb->hid_handle); + status = BTA_HH_ERR; + } + else + { + status = BTA_HH_OK; + } + } + else /* incoming connection SDP finish */ + { + bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL); + } + } + + if (status != BTA_HH_OK) + { + conn_dat.status = status; + + (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat); + + /* move state machine W4_CONN ->IDLE */ + bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL); + + /* if this is an outgoing connection to an unknown device, clean up cb */ + if (p_cb->app_id == 0 && !p_cb->incoming_conn) + { + /* clean up device control block */ + bta_hh_clean_up_kdev(p_cb); + } + +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + } + + return; +} + +/******************************************************************************* +** +** Function bta_hh_api_disc_act +** +** Description HID Host initiate a disconnection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CBDATA disc_dat; + tHID_STATUS status; + + /* found an active connection */ + disc_dat.handle = p_data ?(UINT8)p_data->hdr.layer_specific :p_cb->hid_handle; + disc_dat.status = BTA_HH_ERR; + + status = HID_HostCloseDev(disc_dat.handle); + + if (status) + (* bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat); + + return; +} +/******************************************************************************* +** +** Function bta_hh_open_cmpl_act +** +** Description HID host connection completed +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CONN conn ; + UINT8 dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \ + p_cb->hid_handle; + + memset((void *)&conn, 0, sizeof (tBTA_HH_CONN)); + conn.handle = dev_handle; + bdcpy(conn.bda, p_cb->addr); + + /* increase connection number */ + bta_hh_cb.cnt_num ++; + + /* initialize device driver */ + bta_hh_co_open(p_cb->hid_handle, p_cb->sub_class, + p_cb->attr_mask, p_cb->app_id); + + /* update SSR settings */ + bta_sys_chg_ssr_config(BTA_ID_HH ,p_cb->app_id, p_cb->dscp_info.ssr_max_latency, p_cb->dscp_info.ssr_min_tout); + /* inform role manager */ + bta_sys_conn_open( BTA_ID_HH ,p_cb->app_id, p_cb->addr); + + /* set protocol mode when not default report mode */ + if (p_cb->mode != BTA_HH_PROTO_RPT_MODE) + { + if ((HID_HostWriteDev(dev_handle, + HID_TRANS_SET_PROTOCOL, HID_PAR_PROTOCOL_BOOT_MODE, + 0, + 0, NULL)) != HID_SUCCESS) + { + /* HID connection is up, while SET_PROTO fail */ + conn.status = BTA_HH_ERR_PROTO; + (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn); + } + else + { + conn.status = BTA_HH_OK; + p_cb->w4_evt = BTA_HH_OPEN_EVT; + } + } + else + (* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn); + + p_cb->incoming_conn = FALSE; + +} +/******************************************************************************* +** +** Function bta_hh_open_act +** +** Description HID host receive HID_OPEN_EVT . +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_API_CONN conn_data; + +#if BTA_HH_DEBUG + UINT8 dev_handle = p_data ? (UINT8)p_data->hid_cback.hdr.layer_specific : \ + p_cb->hid_handle; + + APPL_TRACE_EVENT1 ("bta_hh_open_act: Device[%d] connected", dev_handle); +#endif + + /* SDP has been done */ + if (p_cb->app_id != 0) + { + bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data); + } + else + /* app_id == 0 indicates an incoming conenction request arrives without SDP + performed, do it first */ + { + p_cb->incoming_conn = TRUE; + + memset(&conn_data, 0, sizeof(tBTA_HH_API_CONN)); + bdcpy(conn_data.bd_addr, p_cb->addr); + bta_hh_start_sdp(p_cb, (tBTA_HH_DATA *)&conn_data); + } + + return; +} + + +/******************************************************************************* +** +** Function bta_hh_data_act +** +** Description HID Host process a data report +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data) +{ + BT_HDR *pdata = p_data->hid_cback.p_data; + UINT8 *p_rpt = (UINT8 *)(pdata + 1) + pdata->offset; + + bta_hh_co_data((UINT8)p_data->hid_cback.hdr.layer_specific, p_rpt, pdata->len, + p_cb->mode, p_cb->sub_class, p_cb->dscp_info.ctry_code, p_cb->addr, p_cb->app_id); + + utl_freebuf((void **)&pdata); +} + + +/******************************************************************************* +** +** Function bta_hh_handsk_act +** +** Description HID Host process a handshake acknoledgement. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data) +{ + tBTA_HH_CBDATA cback_data ; + tBTA_HH_HSDATA hs_data; + tBTA_HH_CONN conn ; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG2("HANDSHAKE received for: event = %s data= %d", + bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data); +#endif + + memset(&hs_data, 0, sizeof(tBTA_HH_HSDATA)); + + switch (p_cb->w4_evt) + { + /* GET_ transsaction, handshake indicate unsupported request */ + case BTA_HH_GET_PROTO_EVT: + hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN; + /* fall through */ + case BTA_HH_GET_RPT_EVT: + case BTA_HH_GET_IDLE_EVT : + hs_data.handle = p_cb->hid_handle; + /* if handshake gives an OK code for these transaction, fill in UNSUPT */ + if ((hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data)) == BTA_HH_OK) + hs_data.status = BTA_HH_HS_TRANS_NOT_SPT; + + (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data); + p_cb->w4_evt = 0; + break; + + /* acknoledgement from HID device for SET_ transaction */ + case BTA_HH_SET_RPT_EVT: + case BTA_HH_SET_PROTO_EVT: + case BTA_HH_SET_IDLE_EVT : + cback_data.handle = p_cb->hid_handle; + cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data); + (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&cback_data); + p_cb->w4_evt = 0; + break; + + /* SET_PROTOCOL when open connection */ + case BTA_HH_OPEN_EVT: + conn.status =p_data->hid_cback.data ? BTA_HH_ERR_PROTO: BTA_HH_OK; + conn.handle = p_cb->hid_handle; + bdcpy(conn.bda, p_cb->addr); + (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&conn); +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + p_cb->w4_evt = 0; + break; + + default: + /* unknow transaction handshake response */ + APPL_TRACE_DEBUG0("unknown transaction type"); + break; + } + + /* transaction achknoledgement received, inform PM for mode change */ + bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr); + return; +} +/******************************************************************************* +** +** Function bta_hh_ctrl_dat_act +** +** Description HID Host process a data report from control channel. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data) +{ + BT_HDR *pdata = p_data->hid_cback.p_data; + UINT8 *data = (UINT8 *)(pdata + 1) + pdata->offset; + tBTA_HH_HSDATA hs_data; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1("Ctrl DATA received w4: event[%s]", + bta_hh_get_w4_event(p_cb->w4_evt)); +#endif + hs_data.status = BTA_HH_OK; + hs_data.handle = p_cb->hid_handle; + + switch (p_cb->w4_evt) + { + case BTA_HH_GET_IDLE_EVT: + hs_data.rsp_data.idle_rate = *data; + break; + case BTA_HH_GET_RPT_EVT: + hs_data.rsp_data.p_rpt_data = pdata; + break; + case BTA_HH_GET_PROTO_EVT: + /* match up BTE/BTA report/boot mode def*/ + hs_data.rsp_data.proto_mode = ((*data) == HID_PAR_PROTOCOL_REPORT)? \ + BTA_HH_PROTO_RPT_MODE : BTA_HH_PROTO_BOOT_MODE; +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1("GET_PROTOCOL Mode = [%s]", + (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)? "Report" : "Boot"); +#endif + break; + /* should not expect control DATA for SET_ transaction */ + case BTA_HH_SET_PROTO_EVT: + /* fall through */ + case BTA_HH_SET_RPT_EVT: + /* fall through */ + case BTA_HH_SET_IDLE_EVT : + /* fall through */ + default: +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1("invalid transaction type for DATA payload: 4_evt[%s]", + bta_hh_get_w4_event(p_cb->w4_evt)); +#endif + break; + } + + /* inform PM for mode change */ + bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr); + bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr); + + (* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&hs_data); + + p_cb->w4_evt = 0; + utl_freebuf((void **)&pdata); + +} + +/******************************************************************************* +** +** Function bta_hh_close_act +** +** Description HID Host process a close event +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CONN conn_dat ; + tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0}; + UINT32 reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */ + + /* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */ + UINT16 event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT; + + disc_dat.handle = p_cb->hid_handle; + disc_dat.status = p_data->hid_cback.data; + + /* Check reason for closing */ + if ((reason & (HID_L2CAP_CONN_FAIL|HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection (page timeout or l2cap error) */ + (reason == HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */ + (reason == HID_ERR_L2CAP_FAILED)) /* Failure creating l2cap connection */ + { + /* Failure in opening connection */ + conn_dat.handle = p_cb->hid_handle; + conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR; + bdcpy(conn_dat.bda, p_cb->addr); + HID_HostCloseDev(p_cb->hid_handle); + + /* Report OPEN fail event */ + (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat); + +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + return; + } + /* otherwise report CLOSE/VC_UNPLUG event */ + else + { + /* finaliza device driver */ + bta_hh_co_close(p_cb->hid_handle, p_cb->app_id); + /* inform role manager */ + bta_sys_conn_close( BTA_ID_HH ,p_cb->app_id, p_cb->addr); + /* update total conn number */ + bta_hh_cb.cnt_num --; + + if (disc_dat.status) + disc_dat.status = BTA_HH_ERR; + + (*bta_hh_cb.p_cback)(event, (tBTA_HH *)&disc_dat); + + /* if virtually unplug, remove device */ + if (p_cb->vp ) + { + HID_HostRemoveDev( p_cb->hid_handle); + bta_hh_clean_up_kdev(p_cb); + } + +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + } + + /* clean up control block, but retain SDP info and device handle */ + p_cb->vp = FALSE; + p_cb->w4_evt = 0; + + /* if no connection is active and HH disable is signaled, disable service */ + if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) + { + bta_hh_disc_cmpl(); + } + + return; +} + +/******************************************************************************* +** +** Function bta_hh_get_dscp_act +** +** Description Get device report descriptor +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH *)&p_cb->dscp_info); +} + +/******************************************************************************* +** +** Function bta_hh_maint_dev_act +** +** Description HID Host maintain device list. +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_MAINT_DEV *p_dev_info = &p_data->api_maintdev; + tBTA_HH_DEV_INFO dev_info ; + UINT8 dev_handle; + + dev_info.status = BTA_HH_ERR; + dev_info.handle = BTA_HH_INVALID_HANDLE; + + switch (p_dev_info->sub_event) + { + case BTA_HH_ADD_DEV_EVT: /* add a device */ + bdcpy(dev_info.bda, p_dev_info->bda); + /* initialize callback data */ + if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) + { + if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask, &dev_handle)\ + == HID_SUCCESS) + { + dev_info.handle = dev_handle; + dev_info.status = BTA_HH_OK; + + /* update DI information */ + bta_hh_update_di_info(p_cb, + p_dev_info->dscp_info.vendor_id, + p_dev_info->dscp_info.product_id, + p_dev_info->dscp_info.version); + + /* add to BTA device list */ + bta_hh_add_device_to_list(p_cb, dev_handle, + p_dev_info->attr_mask, + &p_dev_info->dscp_info.descriptor, + p_dev_info->sub_class, + p_dev_info->dscp_info.ssr_max_latency, + p_dev_info->dscp_info.ssr_min_tout, + p_dev_info->app_id); + /* update cb_index[] map */ + bta_hh_cb.cb_index[dev_handle] = p_cb->index; + } + } + else /* device already been added */ + { + dev_info.handle = p_cb->hid_handle; + dev_info.status = BTA_HH_OK; + } +#if BTA_HH_DEBUG + bta_hh_trace_dev_db(); +#endif + break; + + case BTA_HH_RMV_DEV_EVT: /* remove device */ + dev_info.handle = (UINT8)p_dev_info->hdr.layer_specific; + + bdcpy(dev_info.bda, p_cb->addr); + if (p_cb->state != BTA_HH_CONN_ST ) + { + if(HID_HostRemoveDev( dev_info.handle ) == HID_SUCCESS) + { + dev_info.status = BTA_HH_OK; + + /* remove from known device list in BTA */ + bta_hh_clean_up_kdev(p_cb); + } + } + break; + + default: + APPL_TRACE_DEBUG0("invalid command"); + break; + } + + (* bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH *)&dev_info); +} +/******************************************************************************* +** +** Function bta_hh_write_dev_act +** +** Description Write device action. can be SET/GET/DATA transaction. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) +{ + tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0}; + UINT16 event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) + + BTA_HH_FST_TRANS_CB_EVT; + + cbdata.handle = p_cb->hid_handle; + + /* match up BTE/BTA report/boot mode def */ + if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) + { + p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ?\ + HID_PAR_PROTOCOL_REPORT :HID_PAR_PROTOCOL_BOOT_MODE; + } + + if (HID_HostWriteDev (p_cb->hid_handle, + p_data->api_sndcmd.t_type, + p_data->api_sndcmd.param, + p_data->api_sndcmd.data, + p_data->api_sndcmd.rpt_id, + p_data->api_sndcmd.p_data) != HID_SUCCESS) + { + APPL_TRACE_ERROR0("HID_HostWriteDev Error "); + cbdata.status = BTA_HH_ERR; + + if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL && + p_data->api_sndcmd.t_type != HID_TRANS_DATA) + (* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata); + else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) + (* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata); + } + else + { + + switch(p_data->api_sndcmd.t_type) + { + case HID_TRANS_SET_PROTOCOL: + /* fall through */ + case HID_TRANS_GET_REPORT: + /* fall through */ + case HID_TRANS_SET_REPORT: + /* fall through */ + case HID_TRANS_GET_PROTOCOL: + /* fall through */ + case HID_TRANS_GET_IDLE: + /* fall through */ + case HID_TRANS_SET_IDLE:/* set w4_handsk event name for callback function use */ + p_cb->w4_evt = event; + break; + case HID_TRANS_DATA: /* output report */ + /* fall through */ + case HID_TRANS_CONTROL: + /* no handshake event will be generated */ + /* if VC_UNPLUG is issued, set flag */ + if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) + p_cb->vp = TRUE; + + break; + /* currently not expected */ + case HID_TRANS_DATAC: + default: + APPL_TRACE_DEBUG1("bta_hh_write_dev_act:: cmd type = %d", + p_data->api_sndcmd.t_type); + break; + } + + /* if not control type transaction, notify PM for energy control */ + if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) + { + /* inform PM for mode change */ + bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr); + bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr); + } + else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND) + { + bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr); + } + else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) + { + bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr); + } + } + + + return; +} + +/***************************************************************************** +** Static Function +*****************************************************************************/ +/******************************************************************************* +** +** Function bta_hh_cback +** +** Description BTA HH callback function. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_hh_cback (UINT8 dev_handle, UINT8 event, UINT32 data, + BT_HDR *pdata) +{ + tBTA_HH_CBACK_DATA *p_buf = NULL; + UINT16 sm_event = BTA_HH_INVALID_EVT; + UINT8 xx = 0; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1("bta_hh_cback::HID_event [%s]", bta_hh_hid_event_name(event)); +#endif + + switch (event) + { + case HID_HDEV_EVT_OPEN: + sm_event = BTA_HH_INT_OPEN_EVT; + break; + case HID_HDEV_EVT_CLOSE: + sm_event = BTA_HH_INT_CLOSE_EVT; + break; + case HID_HDEV_EVT_INTR_DATA: + sm_event = BTA_HH_INT_DATA_EVT; + break; + case HID_HDEV_EVT_HANDSHAKE: + sm_event = BTA_HH_INT_HANDSK_EVT; + break; + case HID_HDEV_EVT_CTRL_DATA: + sm_event = BTA_HH_INT_CTRL_DATA; + break; + case HID_HDEV_EVT_RETRYING: + break; + case HID_HDEV_EVT_INTR_DATC: + case HID_HDEV_EVT_CTRL_DATC: + /* Unhandled events: Free buffer for DATAC */ + utl_freebuf((void **)&pdata); + break; + case HID_HDEV_EVT_VC_UNPLUG: + for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++) + { + if (bta_hh_cb.kdev[xx].hid_handle == dev_handle) + { + bta_hh_cb.kdev[xx].vp = TRUE; + break; + } + } + break; + } + + if (sm_event != BTA_HH_INVALID_EVT && + (p_buf = (tBTA_HH_CBACK_DATA *)GKI_getbuf(sizeof(tBTA_HH_CBACK_DATA) + + sizeof(BT_HDR))) != NULL) + { + p_buf->hdr.event = sm_event; + p_buf->hdr.layer_specific = (UINT16)dev_handle; + p_buf->data = data; + p_buf->p_data = pdata; + + bta_sys_sendmsg(p_buf); + } + +} +/******************************************************************************* +** +** Function bta_hh_get_trans_status +** +** Description translate a handshake result code into BTA HH +** status code +** +*******************************************************************************/ +static tBTA_HH_STATUS bta_hh_get_trans_status(UINT32 result) +{ + switch(result) + { + case HID_PAR_HANDSHAKE_RSP_SUCCESS : /* (0) */ + return BTA_HH_OK; + case HID_PAR_HANDSHAKE_RSP_NOT_READY : /* (1) */ + case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID: /* (2) */ + case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ : /* (3) */ + case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM : /* (4) */ + return (tBTA_HH_STATUS)result; + case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN : /* (14) */ + case HID_PAR_HANDSHAKE_RSP_ERR_FATAL : /* (15) */ + default: + return BTA_HH_HS_ERROR; + break; + } +} +/***************************************************************************** +** Debug Functions +*****************************************************************************/ + +#if (defined BTA_HH_DEBUG && BTA_HH_DEBUG == TRUE) +static char* bta_hh_get_w4_event(UINT16 event) +{ + switch (event) + { + case BTA_HH_GET_RPT_EVT: + return "BTA_HH_GET_RPT_EVT"; + case BTA_HH_SET_RPT_EVT: + return "BTA_HH_SET_RPT_EVT"; + case BTA_HH_GET_PROTO_EVT: + return "BTA_HH_GET_PROTO_EVT"; + case BTA_HH_SET_PROTO_EVT: + return "BTA_HH_SET_PROTO_EVT"; + case BTA_HH_GET_IDLE_EVT: + return "BTA_HH_GET_IDLE_EVT"; + case BTA_HH_SET_IDLE_EVT: + return "BTA_HH_SET_IDLE_EVT"; + case BTA_HH_OPEN_EVT: + return "BTA_HH_OPEN_EVT"; + default: + return "Unknown event"; + } + +} + +static char * bta_hh_hid_event_name(UINT16 event) +{ + switch (event) + { + case HID_HDEV_EVT_OPEN: + return "HID_HDEV_EVT_OPEN"; + case HID_HDEV_EVT_CLOSE: + return "HID_HDEV_EVT_CLOSE"; + case HID_HDEV_EVT_RETRYING: + return "HID_HDEV_EVT_RETRYING"; + case HID_HDEV_EVT_INTR_DATA: + return "HID_HDEV_EVT_INTR_DATA"; + case HID_HDEV_EVT_INTR_DATC: + return "HID_HDEV_EVT_INTR_DATC"; + case HID_HDEV_EVT_CTRL_DATA: + return "HID_HDEV_EVT_CTRL_DATA"; + case HID_HDEV_EVT_CTRL_DATC: + return "HID_HDEV_EVT_CTRL_DATC"; + case HID_HDEV_EVT_HANDSHAKE: + return "HID_HDEV_EVT_HANDSHAKE"; + case HID_HDEV_EVT_VC_UNPLUG: + return "HID_HDEV_EVT_VC_UNPLUG"; + default: + return "Unknown HID event"; + } +} +#endif +#endif /* BTA_HH_INCLUDED */ + diff --git a/bta/hh/bta_hh_api.c b/bta/hh/bta_hh_api.c new file mode 100644 index 0000000..300fc6f --- /dev/null +++ b/bta/hh/bta_hh_api.c @@ -0,0 +1,447 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the HID HOST API in the subsystem of BTA. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE) + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "bta_hh_api.h" +#include "bta_hh_int.h" +#include "l2c_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_hh_reg = +{ + bta_hh_hdl_event, + BTA_HhDisable +}; + +/******************************************************************************* +** +** Function BTA_HhEnable +** +** Description Enable the HID host. This function must be called before +** any other functions in the HID host API are called. When the +** enable operation is complete the callback function will be +** called with BTA_HH_ENABLE_EVT. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HhEnable(tBTA_SEC sec_mask, BOOLEAN ucd_enabled, tBTA_HH_CBACK *p_cback) +{ + tBTA_HH_API_ENABLE *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_HH, &bta_hh_reg); + GKI_sched_unlock(); + + APPL_TRACE_ERROR0("Calling BTA_HhEnable"); + p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE)); + + if (p_buf != NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_API_ENABLE)); + + p_buf->hdr.event = BTA_HH_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + p_buf->sec_mask = sec_mask; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HhDisable +** +** Description Disable the HID host. If the server is currently +** connected, the connection will be closed. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_HH); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_HH_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HhClose +** +** Description Disconnect a connection. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhClose(UINT8 dev_handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(BT_HDR))) != NULL) + { + memset(p_buf, 0, sizeof(BT_HDR)); + p_buf->event = BTA_HH_API_CLOSE_EVT; + p_buf->layer_specific = (UINT16) dev_handle; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HhOpen +** +** Description Connect to a device of specified BD address in specified +** protocol mode and security level. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhOpen(BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode, tBTA_SEC sec_mask) +{ + tBTA_HH_API_CONN *p_buf; + + p_buf = (tBTA_HH_API_CONN *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_CONN)); + + if (p_buf!= NULL) + { + memset((void *)p_buf, 0, sizeof(tBTA_HH_API_CONN)); + + p_buf->hdr.event = BTA_HH_API_OPEN_EVT; + p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE; + p_buf->sec_mask = sec_mask; + p_buf->mode = mode; + bdcpy(p_buf->bd_addr, dev_bda); + + bta_sys_sendmsg((void *)p_buf); + } + else + { + APPL_TRACE_ERROR0("No resource to send HID host Connect request."); + } +} + +/******************************************************************************* +** +** Function bta_hh_snd_write_dev +** +*******************************************************************************/ +static void bta_hh_snd_write_dev(UINT8 dev_handle, UINT8 t_type, UINT8 param, + UINT16 data, UINT8 rpt_id, BT_HDR *p_data) +{ + tBTA_HH_CMD_DATA *p_buf; + UINT16 len = (UINT16) (sizeof(tBTA_HH_CMD_DATA) ); + + if ((p_buf = (tBTA_HH_CMD_DATA *)GKI_getbuf(len))!= NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_CMD_DATA)); + + p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT; + p_buf->hdr.layer_specific = (UINT16) dev_handle; + p_buf->t_type = t_type; + p_buf->data = data; + p_buf->param = param; + p_buf->p_data = p_data; + p_buf->rpt_id = rpt_id; + + bta_sys_sendmsg(p_buf); + } +} +/******************************************************************************* +** +** Function BTA_HhSetReport +** +** Description send SET_REPORT to device. +** +** Parameter dev_handle: device handle +** r_type: report type, could be BTA_HH_RPTT_OUTPUT or +** BTA_HH_RPTT_FEATURE. +** Returns void +** +*******************************************************************************/ +void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, BT_HDR *p_data) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0, p_data); +} +/******************************************************************************* +** +** Function BTA_HhGetReport +** +** Description Send a GET_REPORT to HID device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, UINT8 rpt_id, UINT16 buf_size) +{ + UINT8 param = (buf_size) ? (r_type | 0x08) : r_type; + + bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_REPORT, param, + buf_size, rpt_id, NULL); +} +/******************************************************************************* +** +** Function BTA_HhSetProtoMode +** +** Description This function set the protocol mode at specified HID handle +** +** Returns void +** +*******************************************************************************/ +void BTA_HhSetProtoMode(UINT8 dev_handle, tBTA_HH_PROTO_MODE p_type) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_PROTOCOL, (UINT8)p_type, + 0, 0, NULL); +} +/******************************************************************************* +** +** Function BTA_HhGetProtoMode +** +** Description This function get protocol mode information. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhGetProtoMode(UINT8 dev_handle) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_PROTOCOL, 0, 0, 0, NULL); +} +/******************************************************************************* +** +** Function BTA_HhSetIdle +** +** Description send SET_IDLE to device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_IDLE, 0, idle_rate, 0, NULL); +} + +/******************************************************************************* +** +** Function BTA_HhGetIdle +** +** Description Send a GET_IDLE from HID device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhGetIdle(UINT8 dev_handle) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_IDLE, 0, 0, 0, NULL); +} +/******************************************************************************* +** +** Function BTA_HhSendCtrl +** +** Description Send a control command to HID device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhSendCtrl(UINT8 dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_CONTROL, (UINT8)c_type, 0, 0, NULL); +} +/******************************************************************************* +** +** Function BTA_HhSendData +** +** Description This function send DATA transaction to HID device. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_data) +{ + bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, BTA_HH_RPTT_OUTPUT, 0, 0, p_data); +} + +/******************************************************************************* +** +** Function BTA_HhGetDscpInfo +** +** Description Get HID device report descriptor +** +** Returns void +** +*******************************************************************************/ +void BTA_HhGetDscpInfo(UINT8 dev_handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)sizeof(BT_HDR))) != NULL) + { + memset(p_buf, 0, sizeof(BT_HDR)); + p_buf->event = BTA_HH_API_GET_DSCP_EVT; + p_buf->layer_specific = (UINT16) dev_handle; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HhAddDev +** +** Description Add a virtually cabled device into HID-Host device list +** to manage and assign a device handle for future API call, +** host applciation call this API at start-up to initialize its +** virtually cabled devices. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, UINT8 sub_class, + UINT8 app_id, tBTA_HH_DEV_DSCP_INFO dscp_info) +{ + tBTA_HH_MAINT_DEV *p_buf; + UINT16 len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len; + + p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf(len); + + if (p_buf != NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV)); + + p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT; + p_buf->sub_event = BTA_HH_ADD_DEV_EVT; + p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE; + + p_buf->attr_mask = (UINT16) attr_mask; + p_buf->sub_class = sub_class; + p_buf->app_id = app_id; + bdcpy(p_buf->bda, bda); + + memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO)); + if ( dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list) + { + p_buf->dscp_info.descriptor.dl_len = dscp_info.descriptor.dl_len; + p_buf->dscp_info.descriptor.dsc_list = (UINT8 *)(p_buf + 1); + memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list, dscp_info.descriptor.dl_len); + } + else + { + p_buf->dscp_info.descriptor.dsc_list = NULL; + p_buf->dscp_info.descriptor.dl_len = 0; + } + + bta_sys_sendmsg(p_buf); + } +} +/******************************************************************************* +** +** Function BTA_HhRemoveDev +** +** Description Remove a device from the HID host devices list. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhRemoveDev(UINT8 dev_handle ) +{ + tBTA_HH_MAINT_DEV *p_buf; + + p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf((UINT16)sizeof(tBTA_HH_MAINT_DEV)); + + if (p_buf != NULL) + { + memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV)); + + p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT; + p_buf->sub_event = BTA_HH_RMV_DEV_EVT; + p_buf->hdr.layer_specific = (UINT16) dev_handle; + + bta_sys_sendmsg(p_buf); + } +} + +/*******************************************************************************/ +/* Utility Function */ +/*******************************************************************************/ + +/******************************************************************************* +** +** Function BTA_HhParseBootRpt +** +** Description This utility function parse a boot mode report. +** For keyboard report, report data will carry the keycode max +** up to 6 key press in one report. Application need to convert +** the keycode into keypress character according to keyboard +** language. +** +** Returns void +** +*******************************************************************************/ +void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report, + UINT16 report_len) +{ + p_data->dev_type = BTA_HH_DEVT_UNKNOWN; + + if (p_report) + { + /* first byte is report ID */ + switch (p_report[0]) + { + case BTA_HH_KEYBD_RPT_ID: /* key board report ID */ + p_data->dev_type = p_report[0]; + bta_hh_parse_keybd_rpt(p_data, p_report + 1, (UINT16)(report_len -1)); + break; + + case BTA_HH_MOUSE_RPT_ID: /* mouse report ID */ + p_data->dev_type = p_report[0]; + bta_hh_parse_mice_rpt(p_data, p_report + 1, (UINT16)(report_len - 1)); + break; + + default: + APPL_TRACE_DEBUG1("Unknown boot report: %d", p_report[0]);; + break; + } + } + + return; +} + +#endif /* BTA_HH_INCLUDED */ diff --git a/bta/hh/bta_hh_cfg.c b/bta/hh/bta_hh_cfg.c new file mode 100644 index 0000000..62a07ad --- /dev/null +++ b/bta/hh/bta_hh_cfg.c @@ -0,0 +1,65 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains compile-time configurable constants for the BTA Hid + * Host. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "bta_hh_api.h" + +/* max number of device types supported by BTA */ +#define BTA_HH_MAX_DEVT_SPT 7 + +/* size of database for service discovery */ +#ifndef BTA_HH_DISC_BUF_SIZE +#define BTA_HH_DISC_BUF_SIZE GKI_MAX_BUF_SIZE +#endif + +/* application ID(none-zero) for each type of device */ +#define BTA_HH_APP_ID_MI 1 +#define BTA_HH_APP_ID_KB 2 +#define BTA_HH_APP_ID_RMC 3 +#define BTA_HH_APP_ID_3DSG 4 + + +/* The type of devices supported by BTA HH and corresponding application ID */ +tBTA_HH_SPT_TOD p_devt_list[BTA_HH_MAX_DEVT_SPT] = +{ + {BTA_HH_DEVT_MIC, BTA_HH_APP_ID_MI}, + {BTA_HH_DEVT_KBD, BTA_HH_APP_ID_KB}, + {BTA_HH_DEVT_KBD|BTA_HH_DEVT_MIC, BTA_HH_APP_ID_KB}, + {BTA_HH_DEVT_RMC, BTA_HH_APP_ID_RMC}, + {BTA_HH_DEVT_RMC | BTA_HH_DEVT_KBD, BTA_HH_APP_ID_RMC}, + {BTA_HH_DEVT_MIC | BTA_HH_DEVT_DGT, BTA_HH_APP_ID_MI}, + {BTA_HH_DEVT_UNKNOWN, BTA_HH_APP_ID_3DSG} +}; + + +const tBTA_HH_CFG bta_hh_cfg = +{ + BTA_HH_MAX_DEVT_SPT, /* number of supported type of devices */ + p_devt_list, /* ToD & AppID list */ + BTA_HH_DISC_BUF_SIZE /* HH SDP discovery database size */ +}; + + +tBTA_HH_CFG *p_bta_hh_cfg = (tBTA_HH_CFG *)&bta_hh_cfg; diff --git a/bta/hh/bta_hh_int.h b/bta/hh/bta_hh_int.h new file mode 100644 index 0000000..f3a8e54 --- /dev/null +++ b/bta/hh/bta_hh_int.h @@ -0,0 +1,248 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains BTA HID Host internal definitions + * + ******************************************************************************/ + +#ifndef BTA_HH_INT_H +#define BTA_HH_INT_H + +#include "bta_sys.h" +#include "bd.h" +#include "utl.h" +#include "bta_hh_api.h" + +/* can be moved to bta_api.h */ +#define BTA_HH_MAX_RPT_CHARS 8 + + +/* state machine events, these events are handled by the state machine */ +enum +{ + BTA_HH_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HH), + BTA_HH_API_CLOSE_EVT, + BTA_HH_INT_OPEN_EVT, + BTA_HH_INT_CLOSE_EVT, + BTA_HH_INT_DATA_EVT, + BTA_HH_INT_CTRL_DATA, + BTA_HH_INT_HANDSK_EVT, + BTA_HH_SDP_CMPL_EVT, + BTA_HH_API_WRITE_DEV_EVT, + BTA_HH_API_GET_DSCP_EVT, + BTA_HH_API_MAINT_DEV_EVT, + BTA_HH_OPEN_CMPL_EVT, + + /* not handled by execute state machine */ + BTA_HH_API_ENABLE_EVT, + BTA_HH_API_DISABLE_EVT, + BTA_HH_DISC_CMPL_EVT +}; +typedef UINT16 tBTA_HH_INT_EVT; /* HID host internal events */ + +#define BTA_HH_INVALID_EVT (BTA_HH_DISC_CMPL_EVT + 1) + +/* event used to map between BTE event and BTA event */ +#define BTA_HH_FST_TRANS_CB_EVT BTA_HH_GET_RPT_EVT +#define BTA_HH_FST_BTE_TRANS_EVT HID_TRANS_GET_REPORT + +/* sub event code used for device maintainence API call */ +#define BTA_HH_ADD_DEV 0 +#define BTA_HH_REMOVE_DEV 1 + +/* state machine states */ +enum +{ + BTA_HH_NULL_ST, + BTA_HH_IDLE_ST, + BTA_HH_W4_CONN_ST, + BTA_HH_CONN_ST +}; +typedef UINT8 tBTA_HH_STATE; + +/* data structure used to send a command/data to HID device */ +typedef struct +{ + BT_HDR hdr; + UINT8 t_type; + UINT8 param; + UINT8 rpt_id; + UINT16 data; + BT_HDR *p_data; +}tBTA_HH_CMD_DATA; + +/* data type for BTA_HH_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 sec_mask; + UINT8 service_name[BTA_SERVICE_NAME_LEN+1]; + tBTA_HH_CBACK *p_cback; +} tBTA_HH_API_ENABLE; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + UINT8 sec_mask; + tBTA_HH_PROTO_MODE mode; +}tBTA_HH_API_CONN; + +/* internal event data from BTE HID callback */ +typedef struct +{ + BT_HDR hdr; + UINT32 data; + BT_HDR *p_data; +}tBTA_HH_CBACK_DATA; + +typedef struct +{ + BT_HDR hdr; + BD_ADDR bda; + UINT16 attr_mask; + UINT16 sub_event; + UINT8 sub_class; + UINT8 app_id; + tBTA_HH_DEV_DSCP_INFO dscp_info; +}tBTA_HH_MAINT_DEV; + +/* union of all event data types */ +typedef union +{ + BT_HDR hdr; + tBTA_HH_API_ENABLE api_enable; + tBTA_HH_API_CONN api_conn; + tBTA_HH_CMD_DATA api_sndcmd; + tBTA_HH_CBACK_DATA hid_cback; + tBTA_HH_STATUS status; + tBTA_HH_MAINT_DEV api_maintdev; +} tBTA_HH_DATA; + +/* device control block */ +typedef struct +{ + tBTA_HH_DEV_DSCP_INFO dscp_info; /* report descriptor and DI information */ + BD_ADDR addr; /* BD-Addr of the HID device */ + UINT16 attr_mask; /* attribute mask */ + UINT16 w4_evt; /* W4_handshake event name */ + UINT8 index; /* index number referenced to handle index */ + UINT8 sub_class; /* Cod sub class */ + UINT8 sec_mask; /* security mask */ + UINT8 app_id; /* application ID for this connection */ + UINT8 hid_handle; /* device handle */ + BOOLEAN vp; /* virtually unplug flag */ + BOOLEAN in_use; /* control block currently in use */ + BOOLEAN incoming_conn; /* is incoming connection? */ + BOOLEAN opened; /* TRUE if device successfully opened HID connection */ + tBTA_HH_PROTO_MODE mode; /* protocol mode */ + tBTA_HH_STATE state; /* CB state */ +} tBTA_HH_DEV_CB; + +/* key board parsing control block */ +typedef struct +{ + BOOLEAN mod_key[4]; /* ctrl, shift(upper), Alt, GUI */ + BOOLEAN num_lock; + BOOLEAN caps_lock; + UINT8 last_report[BTA_HH_MAX_RPT_CHARS]; +} tBTA_HH_KB_CB; + +/****************************************************************************** +** Main Control Block +*******************************************************************************/ +typedef struct +{ + tBTA_HH_KB_CB kb_cb; /* key board control block, + suppose BTA will connect + to only one keyboard at + the same time */ + tBTA_HH_DEV_CB kdev[BTA_HH_MAX_KNOWN]; /* device control block */ + tBTA_HH_DEV_CB* p_cur; /* current device control + block idx, used in sdp */ + UINT8 cb_index[BTA_HH_MAX_KNOWN]; /* maintain a CB index + map to dev handle */ + tBTA_HH_CBACK *p_cback; /* Application callbacks */ + tSDP_DISCOVERY_DB* p_disc_db; + UINT8 trace_level; /* tracing level */ + UINT8 cnt_num; /* connected device number */ + BOOLEAN w4_disable; /* w4 disable flag */ +} +tBTA_HH_CB; + +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_HH_CB bta_hh_cb; +#else +extern tBTA_HH_CB *bta_hh_cb_ptr; +#define bta_hh_cb (*bta_hh_cb_ptr) +#endif + +/* from bta_hh_cfg.c */ +extern tBTA_HH_CFG *p_bta_hh_cfg; + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg); +extern void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, + tBTA_HH_DATA *p_data); + +/* action functions */ +extern void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_close_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_data_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data); +extern void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA * p_data); +extern void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_get_dscp_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); +extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); + +/* utility functions */ +extern UINT8 bta_hh_find_cb(BD_ADDR bda); +extern void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data, + UINT8 *p_report, UINT16 report_len); +extern void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT *p_kb_data, + UINT8 *p_report, UINT16 report_len); +extern BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb,UINT8 sub_class); +extern void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb); + +extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle, + UINT16 attr_mask, + tHID_DEV_DSCP_INFO *p_dscp_info, + UINT8 sub_class, UINT16 max_latency, UINT16 min_tout, UINT8 app_id); +extern void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id, + UINT16 version); + +/* action functions used outside state machine */ +extern void bta_hh_api_enable(tBTA_HH_DATA *p_data); +extern void bta_hh_api_disable(void); +extern void bta_hh_disc_cmpl(void); + + +#if BTA_HH_DEBUG +extern void bta_hh_trace_dev_db(void); +#endif + +#endif + diff --git a/bta/hh/bta_hh_main.c b/bta/hh/bta_hh_main.c new file mode 100644 index 0000000..a1d0ad2 --- /dev/null +++ b/bta/hh/bta_hh_main.c @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the HID host main functions and state machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE) + +#include <string.h> + +#include "bta_hh_api.h" +#include "bta_hh_int.h" +#include "gki.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +/* state machine action enumeration list */ +enum +{ + BTA_HH_API_DISC_ACT, /* HID host process API close action */ + BTA_HH_OPEN_ACT, /* HID host process BTA_HH_EVT_OPEN */ + BTA_HH_CLOSE_ACT, /* HID host process BTA_HH_EVT_CLOSE */ + BTA_HH_DATA_ACT, /* HID host receive data report */ + BTA_HH_CTRL_DAT_ACT, + BTA_HH_HANDSK_ACT, + BTA_HH_START_SDP, /* HID host inquery */ + BTA_HH_SDP_CMPL, + BTA_HH_WRITE_DEV_ACT, + BTA_HH_GET_DSCP_ACT, + BTA_HH_MAINT_DEV_ACT, + BTA_HH_OPEN_CMPL_ACT, + BTA_HH_NUM_ACTIONS +}; + +#define BTA_HH_IGNORE BTA_HH_NUM_ACTIONS + +/* type for action functions */ +typedef void (*tBTA_HH_ACTION)(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data); + +/* action functions */ +const tBTA_HH_ACTION bta_hh_action[] = +{ + bta_hh_api_disc_act, + bta_hh_open_act, + bta_hh_close_act, + bta_hh_data_act, + bta_hh_ctrl_dat_act, + bta_hh_handsk_act, + bta_hh_start_sdp, + bta_hh_sdp_cmpl, + bta_hh_write_dev_act, + bta_hh_get_dscp_act, + bta_hh_maint_dev_act, + bta_hh_open_cmpl_act +}; + +/* state table information */ +#define BTA_HH_ACTION 0 /* position of action */ +#define BTA_HH_NEXT_STATE 1 /* position of next state */ +#define BTA_HH_NUM_COLS 2 /* number of columns */ + +/* state table for idle state */ +const UINT8 bta_hh_st_idle[][BTA_HH_NUM_COLS] = +{ +/* Event Action Next state */ +/* BTA_HH_API_OPEN_EVT */ {BTA_HH_START_SDP, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST }, +/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST } + +}; + + +const UINT8 bta_hh_st_w4_conn[][BTA_HH_NUM_COLS] = +{ +/* Event Action Next state */ +/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST }, +/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_SDP_CMPL, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE , BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST }, +/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST } +}; + + +const UINT8 bta_hh_st_connected[][BTA_HH_NUM_COLS] = +{ +/* Event Action Next state */ +/* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }, +/* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST }, +/* BTA_HH_INT_DATA_EVT */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_INT_CTRL_DATA */ {BTA_HH_CTRL_DAT_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_HANDSK_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }, +/* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_GET_DSCP_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST }, +/* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST } +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_HH_ST_TBL)[BTA_HH_NUM_COLS]; + +/* state table */ +const tBTA_HH_ST_TBL bta_hh_st_tbl[] = +{ + bta_hh_st_idle, + bta_hh_st_w4_conn, + bta_hh_st_connected +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_HH_CB bta_hh_cb; +#endif +/***************************************************************************** +** Static functions +*****************************************************************************/ +#if BTA_HH_DEBUG == TRUE +static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code); +static char *bta_hh_state_code(tBTA_HH_STATE state_code); +#endif + +/******************************************************************************* +** +** Function bta_hh_sm_execute +** +** Description State machine event handling function for HID Host +** +** +** Returns void +** +*******************************************************************************/ +void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data) +{ + tBTA_HH_ST_TBL state_table; + UINT8 action; + tBTA_HH cback_data; + tBTA_HH_EVT cback_event = 0; +#if BTA_HH_DEBUG == TRUE + tBTA_HH_STATE in_state ; + UINT16 debug_event = event; +#endif + + memset(&cback_data, 0, sizeof(tBTA_HH)); + + /* handle exception, no valid control block was found */ + if (!p_cb) + { + /* BTA HH enabled already? otherwise ignore the event although it's bad*/ + if (bta_hh_cb.p_cback != NULL) + { + switch (event) + { + /* no control block available for new connection */ + case BTA_HH_API_OPEN_EVT: + cback_event = BTA_HH_OPEN_EVT; + /* build cback data */ + bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr); + cback_data.conn.status = BTA_HH_ERR_DB_FULL; + cback_data.conn.handle = BTA_HH_INVALID_HANDLE; + break; + /* DB full, BTA_HhAddDev */ + case BTA_HH_API_MAINT_DEV_EVT: + cback_event = p_data->api_maintdev.sub_event; + + if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT) + { + bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda); + cback_data.dev_info.status = BTA_HH_ERR_DB_FULL; + cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE; + } + else + { + cback_data.dev_info.status = BTA_HH_ERR_HDL; + cback_data.dev_info.handle = (UINT8)p_data->api_maintdev.hdr.layer_specific; + } + break; + case BTA_HH_API_WRITE_DEV_EVT: + cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) + + BTA_HH_FST_TRANS_CB_EVT; + if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL || + p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT || + p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE) + { + cback_data.dev_status.status = BTA_HH_ERR_HDL; + cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific; + } + else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA && + p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) + { + cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific; + cback_data.hs_data.status = BTA_HH_ERR_HDL; + /* hs_data.rsp_data will be all zero, which is not valid value */ + } + break; + + case BTA_HH_API_CLOSE_EVT: + cback_event = BTA_HH_CLOSE_EVT; + + cback_data.dev_status.status = BTA_HH_ERR_HDL; + cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific; + break; + + default: + /* invalid handle, call bad API event */ + APPL_TRACE_ERROR1("wrong device handle: [%d]", p_data->hdr.layer_specific); + break; + } + if (cback_event) + (* bta_hh_cb.p_cback)(cback_event, &cback_data); + } + } + /* corresponding CB is found, go to state machine */ + else + { +#if BTA_HH_DEBUG == TRUE + in_state = p_cb->state; + APPL_TRACE_EVENT3("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]", + in_state, bta_hh_state_code(in_state), + bta_hh_evt_code(debug_event)); +#endif + + state_table = bta_hh_st_tbl[p_cb->state - 1]; + + event &= 0xff; + + p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ; + + if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE) + { + (*bta_hh_action[action])(p_cb, p_data); + } + +#if BTA_HH_DEBUG == TRUE + if (in_state != p_cb->state) + { + APPL_TRACE_DEBUG3("HH State Change: [%s] -> [%s] after Event [%s]", + bta_hh_state_code(in_state), + bta_hh_state_code(p_cb->state), + bta_hh_evt_code(debug_event)); + } +#endif + } + + return; +} +/******************************************************************************* +** +** Function bta_hh_hdl_event +** +** Description HID host main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg) +{ + UINT8 index = BTA_HH_MAX_KNOWN; + tBTA_HH_DEV_CB *p_cb = NULL; + + switch (p_msg->event) + { + case BTA_HH_API_ENABLE_EVT: + bta_hh_api_enable((tBTA_HH_DATA *) p_msg); + break; + + case BTA_HH_API_DISABLE_EVT: + bta_hh_api_disable(); + break; + + case BTA_HH_DISC_CMPL_EVT: /* disable complete */ + bta_hh_disc_cmpl(); + break; + + default: + /* all events processed in state machine need to find corresponding + CB before proceed */ + if (p_msg->event == BTA_HH_API_OPEN_EVT) + { + index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr); + } + else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT) + { + /* if add device */ + if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT) + { + index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda); + } + else /* else remove device by handle */ + { + index = bta_hh_cb.cb_index[p_msg->layer_specific]; +// btla-specific ++ + /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination + * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting + * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN. + * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we + * force the index to be MAX_KNOWN + */ + if (bta_hh_cb.kdev[index].in_use == FALSE) { + index = BTA_HH_MAX_KNOWN; + } +// btla-specific -- + } + } + else if (p_msg->layer_specific < BTA_HH_MAX_KNOWN ) + index = bta_hh_cb.cb_index[p_msg->layer_specific]; + + if (index != BTA_HH_MAX_KNOWN) + p_cb = &bta_hh_cb.kdev[index]; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG2("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index); +#endif + bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg); + } + return (TRUE); +} + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if BTA_HH_DEBUG +/******************************************************************************* +** +** Function bta_hh_evt_code +** +** Description +** +** Returns void +** +*******************************************************************************/ +static char *bta_hh_evt_code(tBTA_HH_INT_EVT evt_code) +{ + switch(evt_code) + { + case BTA_HH_API_DISABLE_EVT: + return "BTA_HH_API_DISABLE_EVT"; + case BTA_HH_API_ENABLE_EVT: + return "BTA_HH_API_ENABLE_EVT"; + case BTA_HH_API_OPEN_EVT: + return "BTA_HH_API_OPEN_EVT"; + case BTA_HH_API_CLOSE_EVT: + return "BTA_HH_API_CLOSE_EVT"; + case BTA_HH_INT_OPEN_EVT: + return "BTA_HH_INT_OPEN_EVT"; + case BTA_HH_INT_CLOSE_EVT: + return "BTA_HH_INT_CLOSE_EVT"; + case BTA_HH_INT_HANDSK_EVT: + return "BTA_HH_INT_HANDSK_EVT"; + case BTA_HH_INT_DATA_EVT: + return "BTA_HH_INT_DATA_EVT"; + case BTA_HH_INT_CTRL_DATA: + return "BTA_HH_INT_CTRL_DATA"; + case BTA_HH_API_WRITE_DEV_EVT: + return "BTA_HH_API_WRITE_DEV_EVT"; + case BTA_HH_SDP_CMPL_EVT: + return "BTA_HH_SDP_CMPL_EVT"; + case BTA_HH_DISC_CMPL_EVT: + return "BTA_HH_DISC_CMPL_EVT"; + case BTA_HH_API_MAINT_DEV_EVT: + return "BTA_HH_API_MAINT_DEV_EVT"; + case BTA_HH_API_GET_DSCP_EVT: + return "BTA_HH_API_GET_DSCP_EVT"; + case BTA_HH_OPEN_CMPL_EVT: + return "BTA_HH_OPEN_CMPL_EVT"; + default: + return "unknown HID Host event code"; + } +} + +/******************************************************************************* +** +** Function bta_hh_state_code +** +** Description get string representation of HID host state code. +** +** Returns void +** +*******************************************************************************/ +static char *bta_hh_state_code(tBTA_HH_STATE state_code) +{ + switch (state_code) + { + case BTA_HH_NULL_ST: + return"BTA_HH_NULL_ST"; + case BTA_HH_IDLE_ST: + return "BTA_HH_IDLE_ST"; + case BTA_HH_W4_CONN_ST: + return "BTA_HH_W4_CONN_ST"; + case BTA_HH_CONN_ST: + return "BTA_HH_CONN_ST"; + default: + return "unknown HID Host state"; + } +} + +#endif /* Debug Functions */ + +#endif /* BTA_HH_INCLUDED */ diff --git a/bta/hh/bta_hh_utils.c b/bta/hh/bta_hh_utils.c new file mode 100644 index 0000000..4349282 --- /dev/null +++ b/bta/hh/bta_hh_utils.c @@ -0,0 +1,417 @@ +/****************************************************************************** + * + * Copyright (C) 2005-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 <string.h> + +#include "bt_target.h" +#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE) + + +#include "bta_hh_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +#define BTA_HH_KB_CTRL_MASK 0x11 +#define BTA_HH_KB_SHIFT_MASK 0x22 +#define BTA_HH_KB_ALT_MASK 0x44 +#define BTA_HH_KB_GUI_MASK 0x88 + +#define BTA_HH_KB_CAPS_LOCK 0x39 /* caps lock */ +#define BTA_HH_KB_NUM_LOCK 0x53 /* num lock */ + + +#define BTA_HH_MAX_RPT_CHARS 8 + +static const UINT8 bta_hh_mod_key_mask[BTA_HH_MOD_MAX_KEY] = +{ + BTA_HH_KB_CTRL_MASK, + BTA_HH_KB_SHIFT_MASK, + BTA_HH_KB_ALT_MASK, + BTA_HH_KB_GUI_MASK +}; + + +/******************************************************************************* +** +** Function bta_hh_find_cb +** +** Description Find best available control block according to BD address. +** +** +** Returns void +** +*******************************************************************************/ +UINT8 bta_hh_find_cb(BD_ADDR bda) +{ + UINT8 xx; + + /* See how many active devices there are. */ + for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++) + { + /* check if any active/known devices is a match */ + if ((!bdcmp (bda, bta_hh_cb.kdev[xx].addr) && + bdcmp(bda, bd_addr_null) != 0) ) + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG2("found kdev_cb[%d] hid_handle = %d ", xx, + bta_hh_cb.kdev[xx].hid_handle) +#endif + return xx; + } +#if BTA_HH_DEBUG + else + APPL_TRACE_DEBUG4("in_use ? [%d] kdev[%d].hid_handle = %d state = [%d]", + bta_hh_cb.kdev[xx].in_use, xx, + bta_hh_cb.kdev[xx].hid_handle, + bta_hh_cb.kdev[xx].state); +#endif + } + + /* if no active device match, find a spot for it */ + for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++) + { + if (!bta_hh_cb.kdev[xx].in_use) + { + bdcpy(bta_hh_cb.kdev[xx].addr, bda); + break; + } + } + /* If device list full, report BTA_HH_MAX_KNOWN */ +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG2("bta_hh_find_cb:: index = %d while max = %d", + xx, BTA_HH_MAX_KNOWN); +#endif + + return xx; +} + +/******************************************************************************* +** +** Function bta_hh_clean_up_kdev +** +** Description Clean up device control block when device is removed from +** manitainace list, and update control block index map. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB *p_cb) +{ + UINT8 index; + + if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE ) + bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_MAX_KNOWN; + + /* reset device control block */ + index = p_cb->index; /* Preserve index for this control block */ + + /* Free buffer for report descriptor info */ + utl_freebuf((void **)&p_cb->dscp_info.descriptor.dsc_list); + + memset(p_cb, 0, sizeof (tBTA_HH_DEV_CB)); /* Reset control block */ + + p_cb->index = index; /* Restore index for this control block */ + p_cb->state = BTA_HH_IDLE_ST; + p_cb->hid_handle = BTA_HH_INVALID_HANDLE; + +} +/******************************************************************************* +** +** Function bta_hh_update_di_info +** +** Description Maintain a known device list for BTA HH. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_update_di_info(tBTA_HH_DEV_CB *p_cb, UINT16 vendor_id, UINT16 product_id, + UINT16 version) +{ +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG3("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x", + vendor_id, product_id, version); +#endif + p_cb->dscp_info.vendor_id = vendor_id; + p_cb->dscp_info.product_id = product_id; + p_cb->dscp_info.version = version; +} +/******************************************************************************* +** +** Function bta_hh_add_device_to_list +** +** Description Maintain a known device list for BTA HH. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_add_device_to_list(tBTA_HH_DEV_CB *p_cb, UINT8 handle, + UINT16 attr_mask, + tHID_DEV_DSCP_INFO *p_dscp_info, + UINT8 sub_class, + UINT16 ssr_max_latency, + UINT16 ssr_min_tout, + UINT8 app_id) +{ +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1("subclass = 0x%2x", sub_class); +#endif + + p_cb->hid_handle = handle; + p_cb->in_use = TRUE; + p_cb->attr_mask = attr_mask; + + p_cb->sub_class = sub_class; + p_cb->app_id = app_id; + + if (ssr_max_latency == HID_SSR_PARAM_INVALID) + p_cb->dscp_info.ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF; + else + p_cb->dscp_info.ssr_max_latency = ssr_max_latency; + + if (ssr_min_tout == HID_SSR_PARAM_INVALID) + p_cb->dscp_info.ssr_min_tout = BTA_HH_SSR_MIN_TOUT_DEF; + else + p_cb->dscp_info.ssr_min_tout = ssr_min_tout; + + /* store report descriptor info */ + if ( p_dscp_info) + { + utl_freebuf((void **)&p_cb->dscp_info.descriptor.dsc_list); + + if (p_dscp_info->dl_len && + (p_cb->dscp_info.descriptor.dsc_list = + (UINT8 *)GKI_getbuf(p_dscp_info->dl_len)) != NULL) + { + p_cb->dscp_info.descriptor.dl_len = p_dscp_info->dl_len; + memcpy(p_cb->dscp_info.descriptor.dsc_list, p_dscp_info->dsc_list, + p_dscp_info->dl_len); + } + } + return; +} + +/******************************************************************************* +** +** Function bta_hh_tod_spt +** +** Description Check to see if this type of device is supported +** +** Returns +** +*******************************************************************************/ +BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb,UINT8 sub_class) +{ + UINT8 xx; + UINT8 cod = (sub_class >> 2); /* lower two bits are reserved */ + + for (xx = 0 ; xx < p_bta_hh_cfg->max_devt_spt; xx ++) + { + if (cod == (UINT8) p_bta_hh_cfg->p_devt_list[xx].tod) + { + p_cb->app_id = p_bta_hh_cfg->p_devt_list[xx].app_id; +#if BTA_HH_DEBUG + APPL_TRACE_EVENT1("bta_hh_tod_spt sub_class:0x%x supported", sub_class); +#endif + return TRUE; + } + } +#if BTA_HH_DEBUG + APPL_TRACE_EVENT1("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class); +#endif + return FALSE; +} + + +/******************************************************************************* +** +** Function bta_hh_parse_keybd_rpt +** +** Description This utility function parse a boot mode keyboard report. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT *p_kb_data, UINT8 *p_report, + UINT16 report_len) +{ + tBTA_HH_KB_CB *p_kb = &bta_hh_cb.kb_cb; + tBTA_HH_KEYBD_RPT *p_data = &p_kb_data->data_rpt.keybd_rpt; + + UINT8 this_char, ctl_shift; + UINT16 xx, yy, key_idx = 0; + UINT8 this_report[BTA_HH_MAX_RPT_CHARS]; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG2("bta_hh_parse_keybd_rpt: (report=%p, report_len=%d) called", + p_report, report_len); +#endif + + if (report_len < 2) + return; + + ctl_shift = *p_report++; + report_len--; + + if (report_len > BTA_HH_MAX_RPT_CHARS) + report_len = BTA_HH_MAX_RPT_CHARS; + + memset (this_report, 0, BTA_HH_MAX_RPT_CHARS); + memset (p_data, 0, sizeof(tBTA_HH_KEYBD_RPT)); + memcpy (this_report, p_report, report_len); + + /* Take care of shift, control, GUI and alt, modifier keys */ + for (xx = 0; xx < BTA_HH_MOD_MAX_KEY; xx ++ ) + { + if (ctl_shift & bta_hh_mod_key_mask[xx]) + { + APPL_TRACE_DEBUG1("Mod Key[%02x] pressed", bta_hh_mod_key_mask[xx] ); + p_kb->mod_key[xx] = TRUE; + } + else if (p_kb->mod_key[xx]) + { + p_kb->mod_key[xx] = FALSE; + } + /* control key flag is set */ + p_data->mod_key[xx] = p_kb->mod_key[xx]; + } + + /***************************************************************************/ + /* First step is to remove all characters we saw in the last report */ + /***************************************************************************/ + for (xx = 0; xx < report_len; xx++) + { + for (yy = 0; yy < BTA_HH_MAX_RPT_CHARS; yy++) + { + if (this_report[xx] == p_kb->last_report[yy]) + { + this_report[xx] = 0; + } + } + } + /***************************************************************************/ + /* Now, process all the characters in the report, up to 6 keycodes */ + /***************************************************************************/ + for (xx = 0; xx < report_len; xx++) + { +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1("this_char = %02x", this_report[xx]); +#endif + if ((this_char = this_report[xx]) == 0) + continue; + /* take the key code as the report data */ + if (this_report[xx] == BTA_HH_KB_CAPS_LOCK) + p_kb->caps_lock = p_kb->caps_lock ? FALSE : TRUE; + else if (this_report[xx] == BTA_HH_KB_NUM_LOCK) + p_kb->num_lock = p_kb->num_lock ? FALSE : TRUE; + else + p_data->this_char[key_idx ++] = this_char; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1("found keycode %02x ", this_report[xx]); +#endif + p_data->caps_lock = p_kb->caps_lock; + p_kb->num_lock = p_kb->num_lock; + } + + memset (p_kb->last_report, 0, BTA_HH_MAX_RPT_CHARS); + memcpy (p_kb->last_report, p_report, report_len); + + return; +} + +/******************************************************************************* +** +** Function bta_hh_parse_mice_rpt +** +** Description This utility function parse a boot mode mouse report. +** +** Returns void +** +*******************************************************************************/ +void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT *p_mice_data, UINT8 *p_report, + UINT16 report_len) +{ + tBTA_HH_MICE_RPT *p_data = &p_mice_data->data_rpt.mice_rpt; +#if BTA_HH_DEBUG + UINT8 xx; + + APPL_TRACE_DEBUG2("bta_hh_parse_mice_rpt: bta_keybd_rpt_rcvd(report=%p, \ + report_len=%d) called", p_report, report_len); +#endif + + if (report_len < 3) + return; + + if (report_len > BTA_HH_MAX_RPT_CHARS) + report_len = BTA_HH_MAX_RPT_CHARS; + +#if BTA_HH_DEBUG + for (xx = 0; xx < report_len; xx++) + { + APPL_TRACE_DEBUG1("this_char = %02x", p_report[xx]); + } +#endif + + /* only first bytes lower 3 bits valid */ + p_data->mouse_button = (p_report[0] & 0x07); + + /* x displacement */ + p_data->delta_x = p_report[1]; + + /* y displacement */ + p_data->delta_y = p_report[2]; + +#if BTA_HH_DEBUG + APPL_TRACE_DEBUG1("mice button: 0x%2x", p_data->mouse_button); + APPL_TRACE_DEBUG2("mice move: x = %d y = %d", p_data->delta_x, + p_data->delta_y ); +#endif + + return; + +} + +#if BTA_HH_DEBUG +/******************************************************************************* +** +** Function bta_hh_trace_dev_db +** +** Description Check to see if this type of device is supported +** +** Returns +** +*******************************************************************************/ +void bta_hh_trace_dev_db(void) +{ + UINT8 xx; + + APPL_TRACE_DEBUG0("bta_hh_trace_dev_db:: Device DB list********************"); + + for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++) + { + APPL_TRACE_DEBUG3("kdev[%d] in_use[%d] handle[%d] ",xx, + bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle); + + APPL_TRACE_DEBUG4("\t\t\t attr_mask[%04x] state [%d] sub_class[%02x] index = %d", + bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state, + bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index); + } + APPL_TRACE_DEBUG0("*********************************************************"); +} +#endif +#endif /* HL_INCLUDED */ diff --git a/bta/hl/bta_hl_act.c b/bta/hl/bta_hl_act.c new file mode 100644 index 0000000..0f46e5e --- /dev/null +++ b/bta/hl/bta_hl_act.c @@ -0,0 +1,2807 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the HeaLth device profile (HL) action functions for + * the state machine. + * + ******************************************************************************/ + +#include <string.h> + +#include "bt_target.h" +#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE) + +#include "gki.h" +#include "sdp_api.h" +#include "bta_sys.h" +#include "port_api.h" +#include "sdp_api.h" +#include "bta_hl_api.h" +#include "bta_hl_int.h" +#include "utl.h" +#include "bd.h" +#include "mca_defs.h" +#include "mca_api.h" + +/***************************************************************************** +** Local Function prototypes +*****************************************************************************/ +#if (BTA_HL_DEBUG == TRUE && BT_TRACE_VERBOSE == TRUE) +static char *bta_hl_mcap_evt_code(UINT8 evt_code); +static char *bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code); +static char *bta_hl_cback_evt_code(UINT8 evt_code); +#endif +static void bta_hl_sdp_cback(UINT8 sdp_op, UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx, UINT16 status); +static void bta_hl_sdp_cback0(UINT16 status); +static void bta_hl_sdp_cback1(UINT16 status); +static void bta_hl_sdp_cback2(UINT16 status); +static void bta_hl_sdp_cback3(UINT16 status); +static void bta_hl_sdp_cback4(UINT16 status); +static void bta_hl_sdp_cback5(UINT16 status); +static void bta_hl_sdp_cback6(UINT16 status); + + +static tSDP_DISC_CMPL_CB * const bta_hl_sdp_cback_arr[] = { + bta_hl_sdp_cback0, + bta_hl_sdp_cback1, + bta_hl_sdp_cback2, + bta_hl_sdp_cback3, + bta_hl_sdp_cback4, + bta_hl_sdp_cback5, + bta_hl_sdp_cback6 +}; + + + +/******************************************************************************* +** +** Function bta_hl_dch_mca_cong_change +** +** Description Action routine for processing congestion change notification +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_cong_change(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_CONG_CHG *p_cong_chg = &p_data->mca_evt.mca_data.cong_chg; + tBTA_HL evt_data; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG2("bta_hl_dch_mca_cong_change mdl_id=%d cong=%d", + p_cong_chg->mdl_id, + p_cong_chg->cong); +#endif + evt_data.dch_cong_ind.cong = + p_dcb->cong = p_cong_chg->cong; + evt_data.dch_cong_ind.mdl_handle = p_dcb->mdl_handle; + evt_data.dch_cong_ind.mcl_handle = p_mcb->mcl_handle; + evt_data.dch_cong_ind.app_handle = p_acb->app_handle; + + p_acb->p_cback(BTA_HL_CONG_CHG_IND_EVT ,(tBTA_HL *) &evt_data ); +} + + + +/******************************************************************************* +** +** Function bta_hl_dch_echo_test +** +** Description Action routine for processing echo test request +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_echo_test(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_echo_test"); +#endif + + p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_GET_ECHO_DATA; + p_dcb->cout_oper |= BTA_HL_CO_GET_ECHO_DATA_MASK; + + bta_hl_co_get_echo_data(p_acb->app_id, p_mcb->mcl_handle, + p_dcb->p_echo_tx_pkt->len, + BTA_HL_GET_BUF_PTR(p_dcb->p_echo_tx_pkt), + BTA_HL_CI_GET_ECHO_DATA_EVT); + +} +/******************************************************************************* +** +** Function bta_hl_dch_sdp_init +** +** Description Action routine for processing DCH SDP initiation +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_sdp_init(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_sdp_init"); +#endif + if ( p_mcb->sdp_oper == BTA_HL_SDP_OP_NONE) + { + p_mcb->sdp_mdl_idx = mdl_idx; + if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN ) + { + p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_OPEN_INIT; + + } + else + { + p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_RECONNECT_INIT; + } + + if (bta_hl_init_sdp(p_mcb->sdp_oper, app_idx, mcl_idx, mdl_idx) != BTA_HL_STATUS_OK) + { + APPL_TRACE_ERROR0("SDP INIT failed"); + p_mcb->sdp_oper = BTA_HL_SDP_OP_NONE; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT, p_data); + } + } + else + { + APPL_TRACE_ERROR0("SDP in use"); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT, p_data); + } +} + + +/******************************************************************************* +** +** Function bta_hl_dch_close_echo_test +** +** Description Action routine for processing the closing of echo test +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_close_echo_test(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_close_echo_test"); +#endif + + switch (p_dcb->echo_oper) + { + case BTA_HL_ECHO_OP_DCH_CLOSE_CFM: + case BTA_HL_ECHO_OP_OPEN_IND: + case BTA_HL_ECHO_OP_ECHO_PKT: + p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST; + break; + case BTA_HL_ECHO_OP_MDL_CREATE_CFM: + case BTA_HL_ECHO_OP_DCH_OPEN_CFM: + case BTA_HL_ECHO_OP_LOOP_BACK: + default: + break; + } + + if (MCA_CloseReq((tMCA_DL) p_dcb->mdl_handle)!= MCA_SUCCESS) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } +} + + +/******************************************************************************* +** +** Function bta_hl_dch_mca_rcv_data +** +** Description Action routine for processing the received data +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_rcv_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_rcv_data"); +#endif + + if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) + { + switch ( p_dcb->echo_oper) + { + case BTA_HL_ECHO_OP_ECHO_PKT: + + if (MCA_WriteReq((tMCA_DL) p_dcb->mdl_handle, p_data->mca_rcv_data_evt.p_pkt) != MCA_SUCCESS) + { + utl_freebuf((void **) &p_data->mca_rcv_data_evt.p_pkt); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data); + } + break; + case BTA_HL_ECHO_OP_LOOP_BACK: + + p_dcb->p_echo_rx_pkt = p_data->mca_rcv_data_evt.p_pkt; + p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA; + p_dcb->cout_oper |= BTA_HL_CO_PUT_ECHO_DATA_MASK; + p_dcb->ci_put_echo_data_status = BTA_HL_STATUS_FAIL; + + bta_hl_co_put_echo_data(p_acb->app_id, p_mcb->mcl_handle, + p_dcb->p_echo_rx_pkt->len, + BTA_HL_GET_BUF_PTR(p_dcb->p_echo_rx_pkt), + BTA_HL_CI_PUT_ECHO_DATA_EVT); + break; + default: + APPL_TRACE_ERROR1("Unknonw echo_oper=%d",p_dcb->echo_oper); + break; + } + + } + else + { + p_dcb->cout_oper |= BTA_HL_CO_PUT_RX_DATA_MASK; + p_dcb->p_rx_pkt = p_data->mca_rcv_data_evt.p_pkt; + + bta_hl_co_put_rx_data(p_acb->app_id, p_dcb->mdl_handle, + p_dcb->p_rx_pkt->len, + BTA_HL_GET_BUF_PTR(p_dcb->p_rx_pkt), + BTA_HL_CI_PUT_RX_DATA_EVT); + + + } +} + + +/******************************************************************************* +** +** Function bta_hl_dch_ci_put_echo_data +** +** Description Action routine for processing the call-in of the +** put echo data event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_ci_put_echo_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_ci_put_echo_data"); +#endif + + p_dcb->cout_oper &= ~BTA_HL_CO_PUT_ECHO_DATA_MASK; + utl_freebuf((void **) &p_dcb->p_echo_rx_pkt); + p_dcb->ci_put_echo_data_status = p_data->ci_get_put_echo_data.status; + + p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_CLOSE_CFM; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data); +} + + + +/******************************************************************************* +** +** Function bta_hl_dch_ci_get_echo_data +** +** Description Action routine for processing the call-in of the +** get echo data event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_ci_get_echo_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL_STATUS status; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_ci_get_echo_data"); +#endif + + p_dcb->cout_oper &= ~BTA_HL_CO_GET_ECHO_DATA_MASK; + + if (!p_dcb->abort_oper) + { + status = p_data->ci_get_put_echo_data.status; + if (status == BTA_HL_STATUS_OK) + { + p_dcb->echo_oper = BTA_HL_ECHO_OP_MDL_CREATE_CFM; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT, p_data); + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + +} + +/******************************************************************************* +** +** Function bta_hl_dch_ci_put_rx_data +** +** Description Action routine for processing the call-in of the +** put rx data event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_ci_put_rx_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL evt_data; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_ci_put_rx_data"); +#endif + + p_dcb->cout_oper &= ~BTA_HL_CO_PUT_RX_DATA_MASK; + utl_freebuf((void **) &p_dcb->p_rx_pkt); + bta_hl_build_rcv_data_ind(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_dcb->mdl_handle); + p_acb->p_cback(BTA_HL_DCH_RCV_DATA_IND_EVT,(tBTA_HL *) &evt_data ); + if (p_dcb->close_pending) + { + if (!p_dcb->cout_oper) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data); + } + + } +} + + + +/******************************************************************************* +** +** Function bta_hl_dch_ci_get_tx_data +** +** Description Action routine for processing the call-in of the +** get tx data event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_ci_get_tx_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_RESULT result; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + BOOLEAN free_buf = FALSE; + BOOLEAN close_dch = FALSE; + tBTA_HL evt_data; + + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_ci_get_tx_data"); +#endif + + p_dcb->cout_oper &= ~BTA_HL_CO_GET_TX_DATA_MASK; + + if (p_dcb->close_pending) + { + status = BTA_HL_STATUS_FAIL; + free_buf = TRUE; + + if (!p_dcb->cout_oper) + { + close_dch = TRUE; + } + } + else + { + if ((result = MCA_WriteReq((tMCA_DL) p_dcb->mdl_handle, p_dcb->p_tx_pkt)) != MCA_SUCCESS) + { + if (result == MCA_BUSY) + { + status = BTA_HL_STATUS_DCH_BUSY; + } + else + { + status = BTA_HL_STATUS_FAIL; + } + free_buf = TRUE; + } + else + { + p_dcb->p_tx_pkt = NULL; + } + } + + if (free_buf) + { + utl_freebuf((void **) &p_dcb->p_tx_pkt); + } + + bta_hl_build_send_data_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_dcb->mdl_handle, + status); + p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT,(tBTA_HL *) &evt_data ); + + if (close_dch) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data); + } +} + + +/******************************************************************************* +** +** Function bta_hl_dch_send_data +** +** Description Action routine for processing api send data request +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_send_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL evt_data; + BOOLEAN success = TRUE; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_send_data"); +#endif + + if (!(p_dcb->cout_oper & BTA_HL_CO_GET_TX_DATA_MASK)) + { + if ((p_dcb->p_tx_pkt = bta_hl_get_buf(p_data->api_send_data.pkt_size)) != NULL) + { + bta_hl_co_get_tx_data( p_acb->app_id, + p_dcb->mdl_handle, + p_data->api_send_data.pkt_size, + BTA_HL_GET_BUF_PTR(p_dcb->p_tx_pkt), + BTA_HL_CI_GET_TX_DATA_EVT); + p_dcb->cout_oper |= BTA_HL_CO_GET_TX_DATA_MASK; + } + else + { + success = FALSE; + } + } + else + { + success = FALSE; + } + + if (!success) + { + bta_hl_build_send_data_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_dcb->mdl_handle, + BTA_HL_STATUS_FAIL); + p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT,(tBTA_HL *) &evt_data ); + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_close_cmpl +** +** Description Action routine for processing the close complete event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL evt_data; + tBTA_HL_EVT event; + BOOLEAN send_evt=TRUE; + tBTA_HL_STATUS status; + +#if (BTA_HL_DEBUG == TRUE) +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_DEBUG1("bta_hl_dch_close_cmpl dch oper=%s", bta_hl_dch_oper_code(p_dcb->dch_oper)); +#else + APPL_TRACE_DEBUG1("bta_hl_dch_close_cmpl dch oper=%d", p_dcb->dch_oper); +#endif +#endif + + switch (p_dcb->dch_oper) + { + case BTA_HL_DCH_OP_LOCAL_OPEN: + case BTA_HL_DCH_OP_LOCAL_RECONNECT: + + if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) + { + bta_hl_build_abort_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + BTA_HL_STATUS_OK); + event = BTA_HL_DCH_ABORT_CFM_EVT; + } + else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK ) + { + bta_hl_build_abort_ind(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle); + event = BTA_HL_DCH_ABORT_IND_EVT; + } + else + { + bta_hl_build_dch_open_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + BTA_HL_INVALID_MDL_HANDLE, + 0,0,0,0,0, BTA_HL_STATUS_FAIL); + event = BTA_HL_DCH_OPEN_CFM_EVT; + if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT) + { + event = BTA_HL_DCH_RECONNECT_CFM_EVT; + } + } + break; + + case BTA_HL_DCH_OP_LOCAL_CLOSE: + case BTA_HL_DCH_OP_REMOTE_DELETE: + case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT: + case BTA_HL_DCH_OP_NONE: + + bta_hl_build_dch_close_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_dcb->mdl_handle, + BTA_HL_STATUS_OK); + event = BTA_HL_DCH_CLOSE_CFM_EVT; + break; + + case BTA_HL_DCH_OP_REMOTE_CLOSE: + bta_hl_build_dch_close_ind(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_dcb->mdl_handle, + p_dcb->intentional_close); + event = BTA_HL_DCH_CLOSE_IND_EVT; + break; + + case BTA_HL_DCH_OP_REMOTE_OPEN: + + if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) + { + bta_hl_build_abort_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + BTA_HL_STATUS_OK); + event = BTA_HL_DCH_ABORT_CFM_EVT; + } + else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK ) + { + bta_hl_build_abort_ind(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle); + event = BTA_HL_DCH_ABORT_IND_EVT; + } + else + { + bta_hl_build_dch_close_ind(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_dcb->mdl_handle, + p_dcb->intentional_close); + event = BTA_HL_DCH_CLOSE_IND_EVT; + } + break; + + case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST: + /* this is normal echo test close */ + case BTA_HL_DCH_OP_REMOTE_CREATE: + case BTA_HL_DCH_OP_REMOTE_RECONNECT: + send_evt=FALSE; + break; + + default: +#if (BTA_HL_DEBUG == TRUE) +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_ERROR1("DCH operation not found oper=%s", bta_hl_dch_oper_code(p_dcb->dch_oper)); +#else + APPL_TRACE_ERROR1("DCH operation not found oper=%d", p_dcb->dch_oper); +#endif +#endif + send_evt=FALSE; + break; + } + + if ( p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID ) + { + p_mcb->echo_test = FALSE; + send_evt=FALSE; + + if ( p_dcb->dch_oper != BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST) + { + switch (p_dcb->echo_oper) + { + case BTA_HL_ECHO_OP_CI_GET_ECHO_DATA: + case BTA_HL_ECHO_OP_SDP_INIT: + case BTA_HL_ECHO_OP_MDL_CREATE_CFM: + case BTA_HL_ECHO_OP_DCH_OPEN_CFM: + case BTA_HL_ECHO_OP_LOOP_BACK: + + status = BTA_HL_STATUS_FAIL; + send_evt = TRUE; + break; + case BTA_HL_ECHO_OP_OPEN_IND: + case BTA_HL_ECHO_OP_ECHO_PKT: + break; + default: + APPL_TRACE_ERROR1("Invalid echo_oper=%d", p_dcb->echo_oper); + break; + } + } + else + { + status = p_dcb->ci_put_echo_data_status; + send_evt = TRUE; + } + + if (send_evt) + { + bta_hl_build_echo_test_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + status); + event = BTA_HL_DCH_ECHO_TEST_CFM_EVT; + } + } + + bta_hl_clean_mdl_cb(app_idx, mcl_idx, mdl_idx); + + if (send_evt) + { + if (p_acb->p_cback) + { +#if (BTA_HL_DEBUG == TRUE) +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_DEBUG1("Send Event: %s", bta_hl_cback_evt_code(event)); +#else + APPL_TRACE_DEBUG1("Send Event: 0x%02x", event); +#endif +#endif + p_acb->p_cback(event,(tBTA_HL *) &evt_data ); + } + } + /* check cch close is in progress or not */ + bta_hl_check_cch_close(app_idx, mcl_idx, p_data, FALSE); +} +/******************************************************************************* +** +** Function bta_hl_dch_mca_close_ind +** +** Description Action routine for processing the close indication +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_close_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + +#if (BTA_HL_DEBUG == TRUE) +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_DEBUG1("bta_hl_dch_mca_close_ind dch oper=%s", bta_hl_dch_oper_code(p_dcb->dch_oper)); +#else + APPL_TRACE_DEBUG1("bta_hl_dch_mca_close_ind dch oper=%d", p_dcb->dch_oper); +#endif +#endif + + p_dcb->intentional_close = FALSE; + if (p_data->mca_evt.mca_data.close_ind.reason == L2CAP_DISC_OK) + { + p_dcb->intentional_close = TRUE; + } + + if (!p_dcb->cout_oper) + { + if ((p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_OPEN) && + (p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_RECONNECT)) + { + p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CLOSE; + } + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + else + { + p_dcb->close_pending = TRUE; + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_close_cfm +** +** Description Action routine for processing the close confirmation +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_close_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + + +#if (BTA_HL_DEBUG == TRUE) +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_DEBUG1("bta_hl_dch_mca_close_cfm dch_oper=%s", bta_hl_dch_oper_code(p_dcb->dch_oper) ); +#else + APPL_TRACE_DEBUG1("bta_hl_dch_mca_close_cfm dch_oper=%d", p_dcb->dch_oper); +#endif +#endif + + switch (p_dcb->dch_oper) + { + case BTA_HL_DCH_OP_LOCAL_CLOSE: + case BTA_HL_DCH_OP_LOCAL_OPEN: + case BTA_HL_DCH_OP_LOCAL_RECONNECT: + case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST: + case BTA_HL_DCH_OP_REMOTE_DELETE: + case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT: + case BTA_HL_DCH_OP_NONE: + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + break; + default: +#if (BTA_HL_DEBUG == TRUE) +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_ERROR1("Invalid dch_oper=%s for close cfm", bta_hl_dch_oper_code(p_dcb->dch_oper) ); +#else + APPL_TRACE_ERROR1("Invalid dch_oper=%d for close cfm", p_dcb->dch_oper); +#endif +#endif + break; + } + +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_close +** +** Description Action routine for processing the DCH close request +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_close(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + tBTA_HL evt_data; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_close"); +#endif + if (!p_dcb->cout_oper) + { + p_dcb->close_pending = FALSE; + if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle)== MCA_SUCCESS) + { + p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE; + } + else + { + status = BTA_HL_STATUS_FAIL; + } + + if ((status != BTA_HL_STATUS_OK) && + (p_mcb->cch_close_dch_oper != BTA_HL_CCH_CLOSE_OP_DCH_CLOSE)) + { + bta_hl_build_dch_close_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_data->api_dch_close.mdl_handle, + status); + p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data ); + } + } + else + { + p_dcb->close_pending = TRUE; + } +} + + +/******************************************************************************* +** +** Function bta_hl_dch_mca_open_ind +** +** Description Action routine for processing the open indication +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_open_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_DL_OPEN *p_open_ind = &p_data->mca_evt.mca_data.open_ind; + tBTA_HL evt_data; + tBTA_HL_EVT event; + UINT8 old_dch_oper; + BOOLEAN send_event = FALSE; + + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_open_ind"); +#endif + if ((p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_OPEN) || + (p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_RECONNECT) ) + { + p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE) p_open_ind->mdl; + p_dcb->mtu = p_open_ind->mtu; + + evt_data.dch_open_ind.mdl_handle = p_dcb->mdl_handle; + evt_data.dch_open_ind.mcl_handle = p_mcb->mcl_handle; + evt_data.dch_open_ind.app_handle = p_acb->app_handle; + + evt_data.dch_open_ind.local_mdep_id = p_dcb->local_mdep_id; + evt_data.dch_open_ind.mdl_id = p_dcb->mdl_id; + evt_data.dch_open_ind.mtu = p_dcb->mtu; + + if ( p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE ) + { + evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_RELIABLE; + if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) + { + p_dcb->is_the_first_reliable = TRUE; + } + } + else + { + evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_STREAMING; + } + evt_data.dch_open_ind.first_reliable = p_dcb->is_the_first_reliable ; + + old_dch_oper = p_dcb->dch_oper; + p_dcb->dch_oper = BTA_HL_DCH_OP_NONE; + + + } + + switch (old_dch_oper) + { + case BTA_HL_DCH_OP_REMOTE_OPEN: + + p_dcb->dch_mode = evt_data.dch_open_ind.dch_mode; + if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) + { + bta_hl_save_mdl_cfg(app_idx, mcl_idx,mdl_idx); + event= BTA_HL_DCH_OPEN_IND_EVT; + send_event= TRUE; + } + else + { + p_dcb->echo_oper = BTA_HL_ECHO_OP_ECHO_PKT; + } + + break; + + case BTA_HL_DCH_OP_REMOTE_RECONNECT: + + if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx)) + { + bta_hl_save_mdl_cfg(app_idx, mcl_idx,mdl_idx); + event= BTA_HL_DCH_RECONNECT_IND_EVT; + send_event= TRUE; + } + else + { + if (MCA_CloseReq((tMCA_DL) p_dcb->mdl_handle) == MCA_SUCCESS) + { + p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT; + } + else + { + APPL_TRACE_ERROR0("Unabel to close DCH for reconnect cfg mismatch"); + } + } + break; + default: + break; + } + + if (send_event) + { + p_acb->p_cback(event ,(tBTA_HL *) &evt_data ); + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_open_cfm +** +** Description Action routine for processing the open confirmation +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_open_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_DL_OPEN *p_open_cfm = &p_data->mca_evt.mca_data.open_cfm; + tBTA_HL evt_data; + tBTA_HL_EVT event; + UINT8 old_dch_oper; + tBTA_HL_DCH_MODE dch_mode; + BOOLEAN send_event = FALSE; + + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_open_cfm"); +#endif + if ((p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) || + (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT)) + { + p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE) p_open_cfm->mdl; + p_dcb->mtu = p_open_cfm->mtu; + + /*todo verify dch_mode, mtu and fcs for reconnect */ + if ( p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE ) + { + dch_mode = BTA_HL_DCH_MODE_RELIABLE; + } + else + { + dch_mode = BTA_HL_DCH_MODE_STREAMING; + } + + if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) + { + if (dch_mode == BTA_HL_DCH_MODE_RELIABLE ) + { + if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) + { + p_dcb->is_the_first_reliable = TRUE; + } + } + } + + bta_hl_build_dch_open_cfm(&evt_data, p_acb->app_handle, + p_mcb->mcl_handle, + p_dcb->mdl_handle, + p_dcb->local_mdep_id, + p_dcb->mdl_id, dch_mode, + p_dcb->is_the_first_reliable, + p_dcb->mtu, + BTA_HL_STATUS_OK); + + old_dch_oper = p_dcb->dch_oper; + p_dcb->dch_oper = BTA_HL_DCH_OP_NONE; + } + + switch (old_dch_oper) + { + case BTA_HL_DCH_OP_LOCAL_OPEN: + + p_dcb->dch_mode = dch_mode; + if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) + { + bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx); + event= BTA_HL_DCH_OPEN_CFM_EVT; + send_event= TRUE; + } + else + { + p_dcb->echo_oper = BTA_HL_ECHO_OP_LOOP_BACK; + if (MCA_WriteReq((tMCA_DL) p_dcb->mdl_handle, p_dcb->p_echo_tx_pkt)!= MCA_SUCCESS) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data); + } + else + { + p_dcb->p_echo_tx_pkt = NULL; + } + } + break; + + case BTA_HL_DCH_OP_LOCAL_RECONNECT: + + if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx)) + { + bta_hl_save_mdl_cfg(app_idx, mcl_idx,mdl_idx); + event= BTA_HL_DCH_RECONNECT_CFM_EVT; + send_event= TRUE; + } + else + { + if (MCA_CloseReq((tMCA_DL) p_dcb->mdl_handle) == MCA_SUCCESS) + { + p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT; + } + else + { + APPL_TRACE_ERROR0("Unabel to close DCH for reconnect cfg mismatch"); + } + } + break; + default: + break; + } + + if (send_event) + p_acb->p_cback(event ,(tBTA_HL *) &evt_data ); +} + + +/******************************************************************************* +** +** Function bta_hl_dch_mca_abort_ind +** +** Description Action routine for processing the abort indication +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_abort_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_abort_ind"); +#endif + + p_dcb->abort_oper |= BTA_HL_ABORT_REMOTE_MASK; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_abort_cfm +** +** Description Action routine for processing the abort confirmation +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_abort_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL evt_data; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_abort_cfm"); +#endif + + if (p_dcb->abort_oper) + { + if (p_data->mca_evt.mca_data.abort_cfm.rsp_code != MCA_RSP_SUCCESS ) + { + if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) + { + bta_hl_build_abort_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + BTA_HL_STATUS_FAIL); + p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT ,(tBTA_HL *) &evt_data ); + } + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + APPL_TRACE_ERROR0("Not expecting Abort CFM "); + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_abort +** +** Description Action routine for processing the abort request +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_abort(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_RESULT mca_result; + tBTA_HL evt_data; + + if (((p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) || + (p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_RECONNECT_INIT)) && + (p_mcb->sdp_mdl_idx == mdl_idx) ) + { + p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK; + return; + } + else if (p_dcb->echo_oper == BTA_HL_ECHO_OP_CI_GET_ECHO_DATA) + { + p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK; + return; + } + + p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK; + + if ((mca_result = MCA_Abort((tMCA_CL) p_mcb->mcl_handle))!= MCA_SUCCESS) + { + if (mca_result == MCA_NO_RESOURCES) + { + p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK; + } + else + { + if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) + { + bta_hl_build_abort_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + BTA_HL_STATUS_FAIL); + p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT ,(tBTA_HL *) &evt_data ); + } + bta_hl_check_cch_close(app_idx, mcl_idx, p_data, FALSE); + } + + + } + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG1("bta_hl_dch_mca_abort abort_oper=0x%x", p_dcb->abort_oper); +#endif + +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_reconnect_ind +** +** Description Action routine for processing the reconnect indication +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_reconnect_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL_MDL_CFG *p_mdl_cfg; + tMCA_EVT_HDR *p_reconnect_ind = &p_data->mca_evt.mca_data.reconnect_ind; + UINT8 mdl_cfg_idx, in_use_mdl_idx, mdep_cfg_idx; + UINT8 rsp_code = MCA_RSP_SUCCESS; + + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG1("bta_hl_dch_mca_reconnect_ind mdl_id=%d", p_reconnect_ind->mdl_id); +#endif + + if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect_ind->mdl_id, &mdl_cfg_idx)) + { + if (!bta_hl_find_mdl_idx(app_idx,mcl_idx,p_reconnect_ind->mdl_id, &in_use_mdl_idx) ) + { + p_mdl_cfg = BTA_HL_GET_MDL_CFG_PTR(app_idx, mdl_cfg_idx); + + if (bta_hl_find_mdep_cfg_idx(app_idx, p_mdl_cfg->local_mdep_id, &mdep_cfg_idx)) + { + p_dcb->in_use = TRUE; + p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_RECONNECT; + p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); + p_dcb->peer_mdep_id = 0xFF; + p_dcb->local_mdep_id = p_mdl_cfg->local_mdep_id ; + p_dcb->local_mdep_cfg_idx = mdep_cfg_idx; + p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN; + p_dcb->mdl_id = p_reconnect_ind->mdl_id; + p_dcb->mdl_cfg_idx_included = TRUE; + p_dcb->mdl_cfg_idx = mdl_cfg_idx; + p_dcb->dch_mode = p_mdl_cfg->dch_mode; + bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx, + &p_dcb->max_rx_apdu_size, + &p_dcb->max_tx_apdu_size); + bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data); + } + else + { + rsp_code = MCA_RSP_BAD_MDL; + } + } + else + { + rsp_code = MCA_RSP_BAD_MDL; + } + } + else + { + rsp_code = MCA_RSP_BAD_MDL; + } + + if (MCA_ReconnectMdlRsp((tMCA_CL) p_mcb->mcl_handle, + p_dcb->local_mdep_id, + p_dcb->mdl_id, + rsp_code, + &p_dcb->chnl_cfg)!= MCA_SUCCESS) + { + MCA_Abort((tMCA_CL) p_mcb->mcl_handle); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_reconnect_cfm +** +** Description Action routine for processing the reconenct confirmation +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_reconnect_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_RSP_EVT *p_reconnect_cfm = &p_data->mca_evt.mca_data.reconnect_cfm; + + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_reconnect_cfm"); +#endif + if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) + { + p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data); + return; + } + + + if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT) + { + if (p_reconnect_cfm->rsp_code == MCA_RSP_SUCCESS) + { + + bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data); + + if (MCA_DataChnlCfg((tMCA_CL) p_mcb->mcl_handle, &p_dcb->chnl_cfg)!= MCA_SUCCESS) + { + /* should be able to abort so no checking of the return code */ + MCA_Abort((tMCA_CL) p_mcb->mcl_handle); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_reconnect +** +** Description Action routine for processing the reconnect request +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_reconnect(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_CHNL_CFG *p_chnl_cfg=NULL; + UINT8 sdp_idx; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_reconnect"); +#endif + if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm, &sdp_idx)) + { + p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm; + if ( MCA_ReconnectMdl((tMCA_CL) p_mcb->mcl_handle, + p_dcb->local_mdep_id, + p_mcb->data_psm, + p_dcb->mdl_id, + p_chnl_cfg ) != MCA_SUCCESS) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } +} + + +/******************************************************************************* +** +** Function bta_hl_dch_create_rsp +** +** Description Action routine for processing BTA_HL_API_DCH_CREATE_RSP_EVT +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_create_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL_API_DCH_CREATE_RSP *p_create_rsp = &p_data->api_dch_create_rsp; + UINT8 mca_rsp_code = MCA_RSP_SUCCESS; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_create_rsp"); +#endif + if (p_create_rsp->rsp_code == BTA_HL_DCH_CREATE_RSP_SUCCESS) + { + p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN; + p_dcb->local_cfg = p_create_rsp->cfg_rsp; + + + + bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data); + } + else + { + mca_rsp_code = MCA_RSP_CFG_REJ; + } + + if (MCA_CreateMdlRsp((tMCA_CL) p_mcb->mcl_handle, + p_dcb->local_mdep_id, + p_dcb->mdl_id, + p_dcb->local_cfg, + mca_rsp_code, + &p_dcb->chnl_cfg)!= MCA_SUCCESS) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_create_ind +** +** Description Action routine for processing +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_create_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_CREATE_IND *p_create_ind = &p_data->mca_evt.mca_data.create_ind; + UINT8 mdep_cfg_idx; + UINT8 cfg_rsp; + UINT8 rsp_code = MCA_RSP_SUCCESS; + BOOLEAN send_create_ind_evt = FALSE; + tBTA_HL evt_data; + tBTA_HL_ECHO_CFG *p_echo_cfg; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_create_ind"); +#endif + + if (bta_hl_find_mdep_cfg_idx(app_idx, p_create_ind->dep_id, &mdep_cfg_idx)) + { + if (p_create_ind->dep_id == BTA_HL_ECHO_TEST_MDEP_ID ) + { + if (bta_hl_find_echo_cfg_rsp(app_idx, mcl_idx, mdep_cfg_idx,p_create_ind->cfg, &cfg_rsp )) + { + p_dcb->in_use = TRUE; + p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN; + p_dcb->local_mdep_id = p_create_ind->dep_id ; + p_dcb->local_mdep_cfg_idx = mdep_cfg_idx; + p_dcb->local_cfg = cfg_rsp; + p_dcb->remote_cfg = p_create_ind->cfg ; + p_dcb->mdl_id = p_create_ind->mdl_id; + p_dcb->mdl_cfg_idx_included = FALSE; + p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx); + p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size; + p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size; + + bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data); + } + else + { + rsp_code = MCA_RSP_CFG_REJ; + } + } + else + + { + p_dcb->in_use = TRUE; + p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CREATE; + p_dcb->local_mdep_id = p_create_ind->dep_id ; + p_dcb->local_mdep_cfg_idx = mdep_cfg_idx; + p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN; + p_dcb->remote_cfg = p_create_ind->cfg; + p_dcb->mdl_id = p_create_ind->mdl_id; + p_dcb->mdl_cfg_idx_included = FALSE; + bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx, + &p_dcb->max_rx_apdu_size, + &p_dcb->max_tx_apdu_size); + send_create_ind_evt = TRUE; + } + } + else + { + rsp_code = MCA_RSP_BAD_MDEP; + } + + if (send_create_ind_evt) + { + evt_data.dch_create_ind.mcl_handle = p_mcb->mcl_handle; + evt_data.dch_create_ind.app_handle = p_acb->app_handle; + evt_data.dch_create_ind.local_mdep_id = p_dcb->local_mdep_id; + evt_data.dch_create_ind.mdl_id = p_dcb->mdl_id; + evt_data.dch_create_ind.cfg = p_dcb->remote_cfg; + p_acb->p_cback(BTA_HL_DCH_CREATE_IND_EVT,(tBTA_HL *) &evt_data ); + } + else + { + if (MCA_CreateMdlRsp((tMCA_CL) p_mcb->mcl_handle, + p_dcb->local_mdep_id, + p_dcb->mdl_id, + p_dcb->local_cfg, + rsp_code, + &p_dcb->chnl_cfg)!= MCA_SUCCESS) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + else + { + if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) + { + p_mcb->echo_test = TRUE; + p_dcb->echo_oper = BTA_HL_ECHO_OP_OPEN_IND; + } + } + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_create_cfm +** +** Description Action routine for processing +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_create_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_CREATE_CFM *p_create_cfm = &p_data->mca_evt.mca_data.create_cfm; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_mca_create_cfm"); +#endif + + if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) + { + p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data); + return; + } + + if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) + { + if (p_create_cfm->rsp_code == MCA_RSP_SUCCESS) + { + if (bta_hl_validate_cfg(app_idx, mcl_idx, mdl_idx, p_create_cfm->cfg )) + { + bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data); + + if (MCA_DataChnlCfg((tMCA_CL) p_mcb->mcl_handle, &p_dcb->chnl_cfg)!= MCA_SUCCESS) + { + /* this should not happen */ + APPL_TRACE_ERROR0("Unable to create data channel"); + MCA_Abort((tMCA_CL) p_mcb->mcl_handle); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + else + { + if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) + { + p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_OPEN_CFM; + } + } + } + else + { + MCA_Abort((tMCA_CL) p_mcb->mcl_handle); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + APPL_TRACE_ERROR0("MCA Create- failed"); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_mca_create +** +** Description Action routine for processing the MDL create request +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_mca_create(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tMCA_RESULT result; + UINT8 sdp_idx; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_dch_mca_create"); +#endif + + if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm, &sdp_idx) && + bta_hl_validate_peer_cfg(app_idx, mcl_idx, mdl_idx, + p_dcb->peer_mdep_id, + p_dcb->peer_mdep_role, + sdp_idx)) + { + + p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm; + if ( (result = MCA_CreateMdl((tMCA_CL) p_mcb->mcl_handle, + p_dcb->local_mdep_id, + p_mcb->data_psm, + p_dcb->mdl_id, + p_dcb->peer_mdep_id, + p_dcb->local_cfg, + NULL )) != MCA_SUCCESS) + { + APPL_TRACE_ERROR1("MCA_CreateMdl FAIL mca_result=%d", result); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + APPL_TRACE_ERROR0("MCA Create- SDP idx or peer MDEP cfg not found"); + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_sdp_fail +** +** Description Action routine for processing the SDP failed event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_sdp_fail(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data) +{ + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_dch_sdp_fail"); +#endif + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); +} + +/****************************************************************************** +** +** Function bta_hl_sdp_cback +** +** Description This is the SDP callback function used by HL. +** This function will be executed by SDP when the service +** search is completed. If the search is successful, it +** finds the first record in the database that matches the +** UUID of the search. Then retrieves the scn from the +** record. +** +** Returns void. +** +******************************************************************************/ +static void bta_hl_sdp_cback(UINT8 sdp_oper, UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx, UINT16 status) +{ + tBTA_HL_MCL_CB *p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_SDP_REC *p_hdp_rec; + tBTA_HL_CCH_SDP *p_cch_buf; + tBTA_HL_DCH_SDP *p_dch_buf; + tSDP_DISC_REC *p_rec = NULL; + tSDP_PROTOCOL_ELEM pe; + tSDP_DISC_ATTR *p_attr; + UINT8 i, rec_cnt; + tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature; + BOOLEAN sdp_parsing_ok =FALSE, result=FALSE; + UINT16 event; + tBTA_HL_MDL_CB *p_dcb; + UINT16 service_uuid; + UINT16 name_len; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG5("bta_hl_sdp_cback status:%d sdp_oper=%d app_idx=%d, mcl_idx=%d, mdl_idx=%d", + status, sdp_oper, app_idx, mcl_idx, mdl_idx); +#endif + + rec_cnt = 0; + service_uuid = bta_hl_get_service_uuids(sdp_oper, app_idx, mcl_idx, mdl_idx); + + if (status == SDP_SUCCESS || status == SDP_DB_FULL) + { + memset(&p_cb->sdp,0, sizeof(tBTA_HL_SDP)); + do + { + if (bta_hl_find_service_in_db(app_idx, mcl_idx, service_uuid, &p_rec)) + { + p_hdp_rec = &p_cb->sdp.sdp_rec[rec_cnt]; + p_cb->sdp.num_recs = rec_cnt+1; + } + else + { + break; + } + + if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe)) + { + p_hdp_rec->ctrl_psm = (UINT16) pe.params[0]; + } + else + { + APPL_TRACE_WARNING0("Control PSM not found"); + break; + } + if (SDP_FindAddProtoListsElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe)) + { + p_hdp_rec->data_psm = (UINT16) pe.params[0]; + } + else + { + APPL_TRACE_WARNING0("Data PSM not found"); + break; + } + + p_hdp_rec->srv_name[0]= '\0'; + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) != NULL) + { + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN) + name_len = (UINT16)SDP_DISC_ATTR_LEN(p_attr->attr_len_type); + else + name_len = BT_MAX_SERVICE_NAME_LEN; + memcpy(p_hdp_rec->srv_name, p_attr->attr_value.v.array, name_len); + } + + p_hdp_rec->srv_desp[0]= '\0'; + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_DESCRIPTION)) != NULL) + { + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN) + name_len = (UINT16)SDP_DISC_ATTR_LEN(p_attr->attr_len_type); + else + name_len = BT_MAX_SERVICE_NAME_LEN; + memcpy(p_hdp_rec->srv_desp, p_attr->attr_value.v.array, name_len); + } + + + p_hdp_rec->provider_name[0]= '\0'; + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PROVIDER_NAME)) != NULL) + { + if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN) + name_len = (UINT16)SDP_DISC_ATTR_LEN(p_attr->attr_len_type); + else + name_len = BT_MAX_SERVICE_NAME_LEN; + memcpy(p_hdp_rec->provider_name, p_attr->attr_value.v.array, name_len); + } + + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_MCAP_SUP_PROC))!=NULL) + { + p_hdp_rec->mcap_sup_proc = p_attr->attr_value.v.u8; + } + else + { + APPL_TRACE_WARNING0("MCAP SUP PROC not found"); + break; + } + + if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_SUP_FEAT_LIST ))!=NULL) + { + if (bta_hl_fill_sup_feature_list (p_attr, &sup_feature)) + { + p_hdp_rec->num_mdeps = (UINT8) sup_feature.num_elems; + for (i=0; i<sup_feature.num_elems; i++) + { + p_hdp_rec->mdep_cfg[i].data_type = sup_feature.list_elem[i].data_type; + p_hdp_rec->mdep_cfg[i].mdep_id = sup_feature.list_elem[i].mdep_id; + p_hdp_rec->mdep_cfg[i].mdep_role = sup_feature.list_elem[i].mdep_role; + /* Check MDEP Description pointer to prevent crash due to null pointer */ + if (sup_feature.list_elem[i].p_mdep_desp != NULL) + { + BCM_STRNCPY_S(p_hdp_rec->mdep_cfg[i].mdep_desp, + sizeof(p_hdp_rec->mdep_cfg[i].mdep_desp), + sup_feature.list_elem[i].p_mdep_desp, + BTA_HL_MDEP_DESP_LEN); + } + else + { + APPL_TRACE_ERROR1("bta_hl_sdp_cback Incorrect Mdep[%d] Description (Null ptr)", i); + } + } + + sdp_parsing_ok = TRUE; + } + else + { + APPL_TRACE_WARNING0("HDP supported feature list fill failed"); + break; + } + } + else + { + APPL_TRACE_WARNING0("HDP supported feature list not found"); + break; + } +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG3("record=%d ctrl_psm=%0x data_psm=%x", + rec_cnt+1, + p_hdp_rec->ctrl_psm, + p_hdp_rec->data_psm ); + APPL_TRACE_DEBUG1("srv_name=[%s]",(p_hdp_rec->srv_name[0] != '\0')? p_hdp_rec->srv_name:"NULL"); + APPL_TRACE_DEBUG1("srv_desp=[%s]",(p_hdp_rec->srv_desp[0] != '\0')? p_hdp_rec->srv_desp:"NULL"); + for (i=0; i<sup_feature.num_elems; i++) + { + APPL_TRACE_DEBUG5("index=0x%02x mdep_id=0x%04x data type=0x%04x mdep role=%s(0x%02x)", + (i+1), + p_hdp_rec->mdep_cfg[i].mdep_id, + p_hdp_rec->mdep_cfg[i].data_type, + (p_hdp_rec->mdep_cfg[i].mdep_role == BTA_HL_MDEP_ROLE_SOURCE)?"Src":"Snk", + p_hdp_rec->mdep_cfg[i].mdep_role); + } + APPL_TRACE_DEBUG1("provider_name=[%s]",(p_hdp_rec->provider_name[0] != '\0')? p_hdp_rec->provider_name:"NULL"); + APPL_TRACE_DEBUG1("found MCAP sup procedure=%d", + p_cb->sdp.sdp_rec[rec_cnt].mcap_sup_proc ); +#endif + rec_cnt++; + if (rec_cnt >= BTA_HL_NUM_SDP_RECS) + { + APPL_TRACE_WARNING1("No more spaces for SDP recs max_rec_cnt=%d", BTA_HL_NUM_SDP_RECS); + break; + } + + + } while (TRUE); + } + + + utl_freebuf((void **)&p_cb->p_db); + + if ( (status == SDP_SUCCESS || status == SDP_DB_FULL) && + p_cb->sdp.num_recs && + sdp_parsing_ok) + { + result = TRUE; + } + else + { + APPL_TRACE_WARNING3("SDP Failed sdp_status=%d num_recs=%d sdp_parsing_ok=%d ", + status, p_cb->sdp.num_recs,sdp_parsing_ok ); + } + + + p_cb->sdp_oper = BTA_HL_SDP_OP_NONE; + + switch (sdp_oper ) + { + case BTA_HL_SDP_OP_CCH_INIT: + case BTA_HL_SDP_OP_SDP_QUERY_NEW: + case BTA_HL_SDP_OP_SDP_QUERY_CURRENT: + + /* send result in event back to BTA */ + if ((p_cch_buf = (tBTA_HL_CCH_SDP *) GKI_getbuf(sizeof(tBTA_HL_CCH_SDP))) != NULL) + { + if (result) + { + if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT) + { + event = BTA_HL_CCH_SDP_OK_EVT; + if (p_cb->close_pending) + { + event = BTA_HL_CCH_SDP_FAIL_EVT; + } + } + else + { + event = BTA_HL_SDP_QUERY_OK_EVT; + } + } + else + { + if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT) + { + event = BTA_HL_CCH_SDP_FAIL_EVT; + } + else + { + event = BTA_HL_SDP_QUERY_FAIL_EVT; + } + } + p_cch_buf->hdr.event = event; + + p_cch_buf->app_idx = app_idx; + p_cch_buf->mcl_idx = mcl_idx; + p_cch_buf->release_mcl_cb = FALSE; + if (sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW) + { + p_cch_buf->release_mcl_cb = TRUE; + } + + bta_sys_sendmsg(p_cch_buf); + } + break; + case BTA_HL_SDP_OP_DCH_OPEN_INIT: + case BTA_HL_SDP_OP_DCH_RECONNECT_INIT: + if ((p_dch_buf = (tBTA_HL_DCH_SDP *) GKI_getbuf(sizeof(tBTA_HL_DCH_SDP))) != NULL) + { + p_dch_buf->hdr.event = BTA_HL_DCH_SDP_FAIL_EVT; + p_dch_buf->app_idx = app_idx; + p_dch_buf->mcl_idx = mcl_idx; + p_dch_buf->mdl_idx = mdl_idx; + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) + { + p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK; + result = FALSE; + } + if (result) + { + if (sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) + { + if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID ) + { + p_dch_buf->hdr.event = BTA_HL_DCH_ECHO_TEST_EVT; + } + else + { + p_dch_buf->hdr.event = BTA_HL_DCH_OPEN_EVT; + } + } + else + { + p_dch_buf->hdr.event = BTA_HL_DCH_RECONNECT_EVT; + } + } + bta_sys_sendmsg(p_dch_buf); + } + break; + default: + break; + } +} + + +/****************************************************************************** +** +** Function bta_hl_sdp_cback0 +** +** Description This is the SDP callback function used by index = 0 +** +** Returns void. +** +******************************************************************************/ +static void bta_hl_sdp_cback0(UINT16 status) +{ + bta_hl_sdp_cback(bta_hl_cb.scb[0].sdp_oper, + bta_hl_cb.scb[0].app_idx, + bta_hl_cb.scb[0].mcl_idx, + bta_hl_cb.scb[0].mdl_idx, + status); + bta_hl_deallocate_spd_cback(0); +} + +/****************************************************************************** +** +** Function bta_hl_sdp_cback1 +** +** Description This is the SDP callback function used by index = 1 +** +** Parameters status - status of the SDP callabck +** +** Returns void. +** +******************************************************************************/ +static void bta_hl_sdp_cback1(UINT16 status) +{ + bta_hl_sdp_cback(bta_hl_cb.scb[1].sdp_oper, + bta_hl_cb.scb[1].app_idx, + bta_hl_cb.scb[1].mcl_idx, + bta_hl_cb.scb[1].mdl_idx, + status); + bta_hl_deallocate_spd_cback(1); +} + +/****************************************************************************** +** +** Function bta_hl_sdp_cback2 +** +** Description This is the SDP callback function used by index = 2 +** +** Returns void. +** +******************************************************************************/ +static void bta_hl_sdp_cback2(UINT16 status) +{ + bta_hl_sdp_cback(bta_hl_cb.scb[2].sdp_oper, + bta_hl_cb.scb[2].app_idx, + bta_hl_cb.scb[2].mcl_idx, + bta_hl_cb.scb[2].mdl_idx, + status); + bta_hl_deallocate_spd_cback(2); +} + +/****************************************************************************** +** +** Function bta_hl_sdp_cback3 +** +** Description This is the SDP callback function used by index = 3 +** +** Returns void. +** +******************************************************************************/ +static void bta_hl_sdp_cback3(UINT16 status) +{ + bta_hl_sdp_cback(bta_hl_cb.scb[3].sdp_oper, + bta_hl_cb.scb[3].app_idx, + bta_hl_cb.scb[3].mcl_idx, + bta_hl_cb.scb[3].mdl_idx, + status); + bta_hl_deallocate_spd_cback(3); +} + +/****************************************************************************** +** +** Function bta_hl_sdp_cback4 +** +** Description This is the SDP callback function used by index = 4 +** +** Parameters status - status of the SDP callabck +** +** Returns void. +** +******************************************************************************/ +static void bta_hl_sdp_cback4(UINT16 status) +{ + bta_hl_sdp_cback(bta_hl_cb.scb[4].sdp_oper, + bta_hl_cb.scb[4].app_idx, + bta_hl_cb.scb[4].mcl_idx, + bta_hl_cb.scb[4].mdl_idx, + status); + bta_hl_deallocate_spd_cback(4); +} + +/****************************************************************************** +** +** Function bta_hl_sdp_cback5 +** +** Description This is the SDP callback function used by index = 5 +** +** Parameters status - status of the SDP callabck +** +** Returns void. +** +******************************************************************************/ +static void bta_hl_sdp_cback5(UINT16 status) +{ + bta_hl_sdp_cback(bta_hl_cb.scb[5].sdp_oper, + bta_hl_cb.scb[5].app_idx, + bta_hl_cb.scb[5].mcl_idx, + bta_hl_cb.scb[5].mdl_idx, + status); + bta_hl_deallocate_spd_cback(5); +} + +/****************************************************************************** +** +** Function bta_hl_sdp_cback6 +** +** Description This is the SDP callback function used by index = 6 +** +** Returns void. +** +******************************************************************************/ +static void bta_hl_sdp_cback6(UINT16 status) +{ + bta_hl_sdp_cback(bta_hl_cb.scb[6].sdp_oper, + bta_hl_cb.scb[6].app_idx, + bta_hl_cb.scb[6].mcl_idx, + bta_hl_cb.scb[6].mdl_idx, + status); + bta_hl_deallocate_spd_cback(6); +} + + +/******************************************************************************* +** +** Function bta_hl_deallocate_spd_cback +** +** Description Deallocate a SDP control block +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +void bta_hl_deallocate_spd_cback(UINT8 sdp_cback_idx) +{ + tBTA_HL_SDP_CB *p_spd_cb = &bta_hl_cb.scb[sdp_cback_idx]; + + memset(p_spd_cb, 0, sizeof(tBTA_HL_SDP_CB)); + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_deallocate_spd_cback index=%d", sdp_cback_idx); +#endif + + +} + +/******************************************************************************* +** +** Function bta_hl_allocate_spd_cback +** +** Description Finds a not in used SDP control block index +** +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +tSDP_DISC_CMPL_CB *bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx, + UINT8 *p_sdp_cback_idx) +{ + UINT8 i; + tSDP_DISC_CMPL_CB *p_cbcak=NULL; + + + for (i=0; i < BTA_HL_NUM_SDP_CBACKS ; i ++) + { + if (!bta_hl_cb.scb[i].in_use) + { + p_cbcak = bta_hl_sdp_cback_arr[i]; + bta_hl_cb.scb[i].in_use = TRUE; + bta_hl_cb.scb[i].sdp_oper = sdp_oper; + bta_hl_cb.scb[i].app_idx = app_idx; + bta_hl_cb.scb[i].mcl_idx = mcl_idx; + bta_hl_cb.scb[i].mdl_idx = mdl_idx; + *p_sdp_cback_idx = i; + break; + } + } + + if (i == BTA_HL_NUM_SDP_CBACKS) + { + APPL_TRACE_WARNING0("No scb is available to allocate") + } + else + { +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_allocate_spd_cback cback_idx=%d ",i ); + APPL_TRACE_DEBUG4("sdp_oper=%d, app_idx=%d, mcl_idx=%d, mdl_idx=%d", + bta_hl_cb.scb[i].sdp_oper, + bta_hl_cb.scb[i].app_idx, + bta_hl_cb.scb[i].mcl_idx, + bta_hl_cb.scb[i].mdl_idx ); +#endif + } + return p_cbcak; +} + + +/******************************************************************************* +** +** Function bta_hl_init_sdp +** +** Description Action routine for processing the SDP initiattion request +** +** Returns void +** +*******************************************************************************/ +tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx) +{ + tBTA_HL_MCL_CB *p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tSDP_UUID uuid_list; + UINT16 attr_list[BTA_HL_NUM_SRCH_ATTR]; + UINT16 num_attrs = BTA_HL_NUM_SRCH_ATTR; + tBTA_HL_STATUS status; + UINT8 sdp_cback_idx; +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG4("bta_hl_init_sdp sdp_oper=%d app_idx=%d mcl_idx=%d, mdl_idx=%d", + sdp_oper, app_idx, mcl_idx, mdl_idx); +#endif + if ((p_cb->sdp_cback = bta_hl_allocate_spd_cback(sdp_oper, app_idx, mcl_idx, mdl_idx, &sdp_cback_idx)) != NULL) + { + if ( p_cb->p_db || + (!p_cb->p_db && + (p_cb->p_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_HL_DISC_SIZE)) != NULL)) + { + attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; + attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; + attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; + attr_list[3] = ATTR_ID_ADDITION_PROTO_DESC_LISTS; + attr_list[4] = ATTR_ID_SERVICE_NAME; + attr_list[5] = ATTR_ID_SERVICE_DESCRIPTION; + attr_list[6] = ATTR_ID_PROVIDER_NAME; + attr_list[7] = ATTR_ID_HDP_SUP_FEAT_LIST; + attr_list[8] = ATTR_ID_HDP_DATA_EXCH_SPEC; + attr_list[9] = ATTR_ID_HDP_MCAP_SUP_PROC; + + + uuid_list.len = LEN_UUID_16; + uuid_list.uu.uuid16 = UUID_SERVCLASS_HDP_PROFILE; + + SDP_InitDiscoveryDb(p_cb->p_db, BTA_HL_DISC_SIZE, 1, &uuid_list, num_attrs, attr_list); + + if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db, p_cb->sdp_cback)) + { + status = BTA_HL_STATUS_FAIL; + } + else + { + status = BTA_HL_STATUS_OK; + } + } + else /* No services available */ + { + status = BTA_HL_STATUS_NO_RESOURCE; + } + } + else + { + status = BTA_HL_STATUS_SDP_NO_RESOURCE; + } + + if (status != BTA_HL_STATUS_OK) + { + utl_freebuf((void **)&p_cb->p_db); + if (status != BTA_HL_STATUS_SDP_NO_RESOURCE ) + { + bta_hl_deallocate_spd_cback(sdp_cback_idx); + } + } + + return status; +} + +/******************************************************************************* +** +** Function bta_hl_cch_sdp_init +** +** Description Action routine for processing the CCH SDP init event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_sdp_init(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) +{ + tBTA_HL_MCL_CB *p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_cch_init_sdp"); +#endif + if ( p_cb->sdp_oper == BTA_HL_SDP_OP_NONE) + { + p_cb->sdp_oper = BTA_HL_SDP_OP_CCH_INIT; + + if (bta_hl_init_sdp( p_cb->sdp_oper, app_idx, mcl_idx, 0xFF) != BTA_HL_STATUS_OK) + { + p_cb->sdp_oper = BTA_HL_SDP_OP_NONE; + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data); + } + } + else + { + APPL_TRACE_ERROR0("SDP in use"); + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_hl_cch_mca_open +** +** Description Action routine for processing the CCH open request +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_mca_open(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + UINT8 sdp_idx; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_cch_mca_open"); +#endif + + if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->req_ctrl_psm, &sdp_idx)) + { + p_mcb->ctrl_psm = p_mcb->sdp.sdp_rec[sdp_idx].ctrl_psm; + p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm; + if ( MCA_ConnectReq((tMCA_HANDLE) p_acb->app_handle, + p_mcb->bd_addr, + p_mcb->ctrl_psm , + p_mcb->sec_mask) != MCA_SUCCESS) + { + + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_hl_cch_mca_close +** +** Description Action routine for processing the CCH close request +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_mca_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_cch_mca_close"); +#endif + if (p_mcb->sdp_oper != BTA_HL_SDP_OP_CCH_INIT) + { + if ( MCA_DisconnectReq((tMCA_HANDLE) p_acb->app_handle) != MCA_SUCCESS) + { + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data); + } + } + else + { + p_mcb->close_pending = TRUE; + } +} + +/******************************************************************************* +** +** Function bta_hl_cch_close_cmpl +** +** Description Action routine for processing the CCH close complete event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + + tBTA_HL evt_data; + tBTA_HL_EVT event; + BOOLEAN send_evt=TRUE; +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_cch_close_cmpl"); +#endif + bta_sys_conn_close(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr); + + switch (p_mcb->cch_oper) + { + case BTA_HL_CCH_OP_LOCAL_OPEN: + bta_hl_build_cch_open_cfm(&evt_data, p_acb->app_handle, + p_mcb->mcl_handle, + p_mcb->bd_addr, + BTA_HL_STATUS_FAIL); + event = BTA_HL_CCH_OPEN_CFM_EVT; + break; + case BTA_HL_CCH_OP_LOCAL_CLOSE: + bta_hl_build_cch_close_cfm(&evt_data, p_acb->app_handle, + p_mcb->mcl_handle, + BTA_HL_STATUS_OK); + event = BTA_HL_CCH_CLOSE_CFM_EVT; + break; + case BTA_HL_CCH_OP_REMOTE_CLOSE: + bta_hl_build_cch_close_ind(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_mcb->intentional_close); + event = BTA_HL_CCH_CLOSE_IND_EVT; + break; + default: + send_evt=FALSE; + break; + } + + + memset(p_mcb, 0 ,sizeof(tBTA_HL_MCL_CB)); + + if (send_evt)p_acb->p_cback(event,(tBTA_HL *) &evt_data ); + + bta_hl_check_deregistration(app_idx, p_data); +} + +/******************************************************************************* +** +** Function bta_hl_cch_mca_disconnect +** +** Description Action routine for processing the CCH disconnect indication +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_mca_disconnect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) +{ + + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb; + UINT8 i; +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_cch_mca_disconnect"); +#endif + + p_mcb->intentional_close = FALSE; + if (p_data->mca_evt.mca_data.disconnect_ind.reason == L2CAP_DISC_OK) + { + p_mcb->intentional_close = TRUE; + } + + for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++) + { + p_dcb= BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, i); + if (p_dcb->in_use && (p_dcb->dch_state != BTA_HL_DCH_IDLE_ST)) + { + if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE ) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_MCA_CLOSE_IND_EVT, p_data); + } + } + } + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data); +} + +/******************************************************************************* +** +** Function bta_hl_cch_mca_rsp_tout +** +** Description Action routine for processing the MCAP response timeout +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_mca_rsp_tout(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) +{ + + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_cch_mca_rsp_tout"); +#endif + + p_mcb->rsp_tout = TRUE; + + bta_hl_check_cch_close(app_idx,mcl_idx,p_data,TRUE); +} +/******************************************************************************* +** +** Function bta_hl_cch_mca_connect +** +** Description Action routine for processing the CCH connect indication +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_mca_connect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL evt_data; + tBTA_HL_EVT event; + BOOLEAN send_event=TRUE; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_cch_mca_connect"); +#endif + + p_mcb->mcl_handle = p_data->mca_evt.mcl_handle; + bdcpy(p_mcb->bd_addr, p_data->mca_evt.mca_data.connect_ind.bd_addr); + p_mcb->cch_mtu = p_data->mca_evt.mca_data.connect_ind.mtu; + + bta_sys_conn_open(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr); + switch (p_mcb->cch_oper) + { + case BTA_HL_CCH_OP_LOCAL_OPEN: + bta_hl_build_cch_open_cfm(&evt_data, p_acb->app_handle, + p_mcb->mcl_handle, + p_mcb->bd_addr, + BTA_HL_STATUS_OK); + event = BTA_HL_CCH_OPEN_CFM_EVT; + break; + case BTA_HL_CCH_OP_REMOTE_OPEN: + bta_hl_build_cch_open_ind(&evt_data, p_acb->app_handle, + p_mcb->mcl_handle, + p_mcb->bd_addr); + event = BTA_HL_CCH_OPEN_IND_EVT; + break; + default: + send_event = FALSE; + break; + } + + p_mcb->cch_oper = BTA_HL_CCH_OP_NONE; + if (send_event) p_acb->p_cback(event,(tBTA_HL *) &evt_data ); +} + +/******************************************************************************* +** +** Function bta_hl_mcap_ctrl_cback +** +** Description MCAP control callback function for HL. +** +** Returns void +** +*******************************************************************************/ +void bta_hl_mcap_ctrl_cback (tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event, + tMCA_CTRL *p_data) +{ + tBTA_HL_MCA_EVT * p_msg; + BOOLEAN send_event=TRUE; + UINT16 mca_event; + +#if (BTA_HL_DEBUG == TRUE) +#if (BT_TRACE_VERBOSE == TRUE) + APPL_TRACE_EVENT1("bta_hl_mcap_ctrl_cback event[%s]",bta_hl_mcap_evt_code(event)); +#else + APPL_TRACE_EVENT1("bta_hl_mcap_ctrl_cback event[0x%02x]", event); +#endif +#endif + + switch (event) + { + + case MCA_CREATE_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_CREATE_IND_EVT; + break; + case MCA_CREATE_CFM_EVT: + mca_event = (UINT16) BTA_HL_MCA_CREATE_CFM_EVT; + break; + case MCA_RECONNECT_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_RECONNECT_IND_EVT; + break; + case MCA_RECONNECT_CFM_EVT: + mca_event = (UINT16) BTA_HL_MCA_RECONNECT_CFM_EVT; + break; + case MCA_ABORT_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_ABORT_IND_EVT; + break; + case MCA_ABORT_CFM_EVT: + mca_event = (UINT16) BTA_HL_MCA_ABORT_CFM_EVT; + break; + case MCA_DELETE_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_DELETE_IND_EVT; + break; + case MCA_DELETE_CFM_EVT: + mca_event = (UINT16) BTA_HL_MCA_DELETE_CFM_EVT; + break; + case MCA_CONNECT_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_CONNECT_IND_EVT; + break; + case MCA_DISCONNECT_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_DISCONNECT_IND_EVT; + break; + case MCA_OPEN_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_OPEN_IND_EVT; + break; + case MCA_OPEN_CFM_EVT: + mca_event = (UINT16) BTA_HL_MCA_OPEN_CFM_EVT; + break; + case MCA_CLOSE_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_CLOSE_IND_EVT; + break; + case MCA_CLOSE_CFM_EVT: + mca_event = (UINT16) BTA_HL_MCA_CLOSE_CFM_EVT; + break; + case MCA_CONG_CHG_EVT: + mca_event = (UINT16) BTA_HL_MCA_CONG_CHG_EVT; + break; + case MCA_RSP_TOUT_IND_EVT: + mca_event = (UINT16) BTA_HL_MCA_RSP_TOUT_IND_EVT; + break; + case MCA_ERROR_RSP_EVT: + + default: + send_event=FALSE; + break; + } + + if ((p_msg = (tBTA_HL_MCA_EVT *)GKI_getbuf(sizeof(tBTA_HL_MCA_EVT))) != NULL) + { + p_msg->hdr.event = mca_event; + p_msg->app_handle = (tBTA_HL_APP_HANDLE) handle; + p_msg->mcl_handle = (tBTA_HL_MCL_HANDLE) mcl; + memcpy (&p_msg->mca_data, p_data, sizeof(tMCA_CTRL)); + bta_sys_sendmsg(p_msg); + } +} + + +/******************************************************************************* +** +** Function bta_hl_mcap_data_cback +** +** Description MCAP data callback function for HL. +** +** Returns void +** +*******************************************************************************/ +void bta_hl_mcap_data_cback (tMCA_DL mdl, BT_HDR *p_pkt) +{ + tBTA_HL_MCA_RCV_DATA_EVT *p_msg; + + UINT8 app_idx, mcl_idx, mdl_idx; + if (bta_hl_find_mdl_idx_using_handle ((tBTA_HL_MDL_HANDLE)mdl, &app_idx, &mcl_idx, &mdl_idx)) + { + if ((p_msg = (tBTA_HL_MCA_RCV_DATA_EVT *)GKI_getbuf(sizeof(tBTA_HL_MCA_RCV_DATA_EVT))) != NULL) + { + p_msg->hdr.event = BTA_HL_MCA_RCV_DATA_EVT; + p_msg->app_idx = app_idx; + p_msg->mcl_idx = mcl_idx; + p_msg->mdl_idx = mdl_idx; + p_msg->p_pkt = p_pkt; + bta_sys_sendmsg(p_msg); + } + } +} +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if (BTA_HL_DEBUG == TRUE && BT_TRACE_VERBOSE == TRUE) + +/******************************************************************************* +** +** Function bta_hl_mcap_evt_code +** +** Description get the MCAP event string pointer +** +** Returns char * - event string pointer +** +*******************************************************************************/ +static char *bta_hl_mcap_evt_code(UINT8 evt_code) +{ + + switch (evt_code) + { + + case MCA_ERROR_RSP_EVT: + return "MCA_ERROR_RSP_EVT"; + case MCA_CREATE_IND_EVT: + return "MCA_CREATE_IND_EVT"; + case MCA_CREATE_CFM_EVT: + return "MCA_CREATE_CFM_EVT"; + case MCA_RECONNECT_IND_EVT: + return "MCA_RECONNECT_IND_EVT"; + case MCA_RECONNECT_CFM_EVT: + return "MCA_RECONNECT_CFM_EVT"; + case MCA_ABORT_IND_EVT: + return "MCA_ABORT_IND_EVT"; + case MCA_ABORT_CFM_EVT: + return "MCA_ABORT_CFM_EVT"; + case MCA_DELETE_IND_EVT: + return "MCA_DELETE_IND_EVT"; + case MCA_DELETE_CFM_EVT: + return "MCA_DELETE_CFM_EVT"; + + case MCA_CONNECT_IND_EVT: + return "MCA_CONNECT_IND_EVT"; + case MCA_DISCONNECT_IND_EVT: + return "MCA_DISCONNECT_IND_EVT"; + case MCA_OPEN_IND_EVT: + return "MCA_OPEN_IND_EVT"; + case MCA_OPEN_CFM_EVT: + return "MCA_OPEN_CFM_EVT"; + case MCA_CLOSE_IND_EVT: + return "MCA_CLOSE_IND_EVT"; + case MCA_CLOSE_CFM_EVT: + return "MCA_CLOSE_CFM_EVT"; + case MCA_CONG_CHG_EVT: + return "MCA_CONG_CHG_EVT"; + case MCA_RSP_TOUT_IND_EVT: + return "MCA_RSP_TOUT_IND_EVT"; + default: + return "Unknown MCAP event code"; + } +} + + +/******************************************************************************* +** +** Function bta_hl_cback_evt_code +** +** Description get the HDP event string pointer +** +** Returns char * - event string pointer +** +*******************************************************************************/ +static char *bta_hl_cback_evt_code(UINT8 evt_code) +{ + + switch (evt_code) + { + + case BTA_HL_CCH_OPEN_IND_EVT: + return "BTA_HL_CCH_OPEN_IND_EVT"; + case BTA_HL_CCH_OPEN_CFM_EVT: + return "BTA_HL_CCH_OPEN_CFM_EVT"; + case BTA_HL_CCH_CLOSE_IND_EVT: + return "BTA_HL_CCH_CLOSE_IND_EVT"; + case BTA_HL_CCH_CLOSE_CFM_EVT: + return "BTA_HL_CCH_CLOSE_CFM_EVT"; + case BTA_HL_DCH_OPEN_IND_EVT: + return "BTA_HL_DCH_OPEN_IND_EVT"; + case BTA_HL_DCH_OPEN_CFM_EVT: + return "BTA_HL_DCH_OPEN_CFM_EVT"; + case BTA_HL_DCH_CLOSE_IND_EVT: + return "BTA_HL_DCH_CLOSE_IND_EVT"; + case BTA_HL_DCH_CLOSE_CFM_EVT: + return "BTA_HL_DCH_CLOSE_CFM_EVT"; + case BTA_HL_DCH_RCV_DATA_IND_EVT: + return "BTA_HL_DCH_RCV_DATA_IND_EVT"; + case BTA_HL_REGISTER_CFM_EVT: + return "BTA_HL_REGISTER_CFM_EVT"; + case BTA_HL_DEREGISTER_CFM_EVT: + return "BTA_HL_DEREGISTER_CFM_EVT"; + case BTA_HL_DCH_RECONNECT_CFM_EVT: + return "BTA_HL_DCH_RECONNECT_CFM_EVT"; + case BTA_HL_DCH_RECONNECT_IND_EVT: + return "BTA_HL_DCH_RECONNECT_IND_EVT"; + case BTA_HL_DCH_ECHO_TEST_CFM_EVT: + return "BTA_HL_DCH_ECHO_TEST_CFM_EVT"; + case BTA_HL_SDP_QUERY_CFM_EVT: + return "BTA_HL_SDP_QUERY_CFM_EVT"; + case BTA_HL_CONG_CHG_IND_EVT: + return "BTA_HL_CONG_CHG_IND_EVT"; + case BTA_HL_DCH_CREATE_IND_EVT: + return "BTA_HL_DCH_CREATE_IND_EVT"; + case BTA_HL_DELETE_MDL_IND_EVT: + return "BTA_HL_DELETE_MDL_IND_EVT"; + case BTA_HL_DELETE_MDL_CFM_EVT: + return "BTA_HL_DELETE_MDL_CFM_EVT"; + case BTA_HL_DCH_ABORT_IND_EVT: + return "BTA_HL_DCH_ABORT_IND_EVT"; + case BTA_HL_DCH_ABORT_CFM_EVT: + return "BTA_HL_DCH_ABORT_CFM_EVT"; + default: + return "Unknown HDP event code"; + } +} + + + +/******************************************************************************* +** +** Function bta_hl_dch_oper_code +** +** Description Get the DCH operation string +** +** Returns char * - DCH operation string pointer +** +*******************************************************************************/ +static char *bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code) +{ + + switch (oper_code) + { + case BTA_HL_DCH_OP_NONE: + return "BTA_HL_DCH_OP_NONE"; + case BTA_HL_DCH_OP_REMOTE_CREATE: + return "BTA_HL_DCH_OP_REMOTE_CREATE"; + case BTA_HL_DCH_OP_LOCAL_OPEN: + return "BTA_HL_DCH_OP_LOCAL_OPEN"; + case BTA_HL_DCH_OP_REMOTE_OPEN: + return "BTA_HL_DCH_OP_REMOTE_OPEN"; + case BTA_HL_DCH_OP_LOCAL_CLOSE: + return "BTA_HL_DCH_OP_LOCAL_CLOSE"; + case BTA_HL_DCH_OP_REMOTE_CLOSE: + return "BTA_HL_DCH_OP_REMOTE_CLOSE"; + case BTA_HL_DCH_OP_LOCAL_DELETE: + return "BTA_HL_DCH_OP_LOCAL_DELETE"; + case BTA_HL_DCH_OP_REMOTE_DELETE: + return "BTA_HL_DCH_OP_REMOTE_DELETE"; + case BTA_HL_DCH_OP_LOCAL_RECONNECT: + return "BTA_HL_DCH_OP_LOCAL_RECONNECT"; + case BTA_HL_DCH_OP_REMOTE_RECONNECT: + return "BTA_HL_DCH_OP_REMOTE_RECONNECT"; + case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST: + return "BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST"; + case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT: + return "BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT"; + default: + return "Unknown DCH oper code"; + } +} + + +#endif /* Debug Functions */ +#endif /* HL_INCLUDED */ diff --git a/bta/hl/bta_hl_api.c b/bta/hl/bta_hl_api.c new file mode 100644 index 0000000..8c8d621 --- /dev/null +++ b/bta/hl/bta_hl_api.c @@ -0,0 +1,485 @@ +/****************************************************************************** + * + * 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 of the API for the HeaLth device profile (HL) + * subsystem of BTA, Broadcom Corp's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ + +#include <string.h> + +#include "bt_target.h" +#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE) + +#include "gki.h" +#include "bd.h" +#include "bta_hl_api.h" +#include "bta_hl_int.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_hl_reg = +{ + bta_hl_hdl_event, + BTA_HlDisable +}; + +/******************************************************************************* +** +** Function BTA_HlEnable +** +** Description Enable the HL subsystems. This function must be +** called before any other functions in the HL API are called. +** When the enable operation is completed the callback function +** will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event. +** +** Parameters p_cback - HL event call back function +** +** Returns void +** +*******************************************************************************/ +void BTA_HlEnable(tBTA_HL_CTRL_CBACK *p_ctrl_cback) +{ + tBTA_HL_API_ENABLE *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_HL, &bta_hl_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_HL_API_ENABLE *)GKI_getbuf(sizeof(tBTA_HL_API_ENABLE))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_ENABLE_EVT; + p_buf->p_cback = p_ctrl_cback; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlDisable +** +** Description Disable the HL subsystem. +** +** Returns void +** +*******************************************************************************/ +void BTA_HlDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_HL); + if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_HL_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlRegister +** +** Description Register an HDP application +** +** Parameters app_id - Application ID +** p_reg_param - non-platform related parameters for the +** HDP application +** p_cback - HL event callback fucntion +** +** Returns void +** +*******************************************************************************/ +void BTA_HlRegister(UINT8 app_id, + tBTA_HL_REG_PARAM *p_reg_param, + tBTA_HL_CBACK *p_cback) +{ + tBTA_HL_API_REGISTER *p_buf; + + if ((p_buf = (tBTA_HL_API_REGISTER *)GKI_getbuf((UINT16)sizeof(tBTA_HL_API_REGISTER))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_REGISTER_EVT; + p_buf->app_id = app_id; + p_buf->sec_mask = (p_reg_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); + p_buf->p_cback = p_cback; + if (p_reg_param->p_srv_name) + { + BCM_STRNCPY_S(p_buf->srv_name, sizeof(p_buf->srv_name), + p_reg_param->p_srv_name, BTA_SERVICE_NAME_LEN); + p_buf->srv_name[BTA_SERVICE_NAME_LEN] = '\0'; + } + else + p_buf->srv_name[0]= '\0'; + + if (p_reg_param->p_srv_desp) + { + BCM_STRNCPY_S(p_buf->srv_desp, sizeof(p_buf->srv_desp), + p_reg_param->p_srv_desp, BTA_SERVICE_DESP_LEN); + p_buf->srv_desp[BTA_SERVICE_DESP_LEN]= '\0'; + } + else + p_buf->srv_desp[0]= '\0'; + + if (p_reg_param->p_provider_name) + { + BCM_STRNCPY_S(p_buf->provider_name, sizeof(p_buf->provider_name), + p_reg_param->p_provider_name, BTA_PROVIDER_NAME_LEN); + p_buf->provider_name[BTA_PROVIDER_NAME_LEN]= '\0'; + } + else + p_buf->provider_name[0]= '\0'; + + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlDeregister +** +** Description Deregister an HDP application +** +** Parameters app_handle - Application handle +** +** Returns void +** +*******************************************************************************/ +void BTA_HlDeregister(tBTA_HL_APP_HANDLE app_handle) +{ + tBTA_HL_API_DEREGISTER *p_buf; + + if ((p_buf = (tBTA_HL_API_DEREGISTER *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DEREGISTER)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_DEREGISTER_EVT; + p_buf->app_handle = app_handle; + bta_sys_sendmsg(p_buf); + } +} +/******************************************************************************* +** +** Function BTA_HlCchOpen +** +** Description Open a Control channel connection with the specified BD address +** +** Parameters app_handle - Application Handle +** p_open_param - parameters for opening a control channel +** +** Returns void +** +** Note: The control PSM value is used to select which +** HDP insatnce should be used in case the peer device support +** multiple HDP instances. Also, if the control PSM value is zero +** then the first HDP instance is used for the control channel setup +*******************************************************************************/ +void BTA_HlCchOpen(tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_CCH_OPEN_PARAM *p_open_param) +{ + tBTA_HL_API_CCH_OPEN *p_buf; + + if ((p_buf = (tBTA_HL_API_CCH_OPEN *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_CCH_OPEN)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_CCH_OPEN_EVT; + p_buf->app_handle = app_handle; + p_buf->sec_mask = (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); + bdcpy(p_buf->bd_addr, p_open_param->bd_addr); + p_buf->ctrl_psm = p_open_param->ctrl_psm; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlCchClose +** +** Description Close a Control channel connection with the specified MCL +** handle +** +** Parameters mcl_handle - MCL handle +** +** Returns void +** +*******************************************************************************/ +void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle) +{ + tBTA_HL_API_CCH_CLOSE *p_buf; + + if ((p_buf = (tBTA_HL_API_CCH_CLOSE *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_CCH_CLOSE)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_CCH_CLOSE_EVT; + p_buf->mcl_handle = mcl_handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlDchOpen +** +** Description Open a data channel connection with the specified DCH parameters +** +** Parameters mcl_handle - MCL handle +** p_open_param - parameters for opening a data channel +** +** Returns void +** +*******************************************************************************/ +void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_DCH_OPEN_PARAM *p_open_param) +{ + tBTA_HL_API_DCH_OPEN *p_buf; + + if ((p_buf = (tBTA_HL_API_DCH_OPEN *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_OPEN)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_DCH_OPEN_EVT; + p_buf->mcl_handle = mcl_handle; + p_buf->ctrl_psm = p_open_param->ctrl_psm; + p_buf->local_mdep_id = p_open_param->local_mdep_id; + p_buf->peer_mdep_id = p_open_param->peer_mdep_id; + p_buf->local_cfg = p_open_param->local_cfg; + p_buf->sec_mask = (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlDchReconnect +** +** Description Reconnect a data channel with the specified MDL_ID +** +** Parameters mcl_handle - MCL handle +*8 p_recon_param - parameters for reconnecting a data channel +** +** Returns void +** +*******************************************************************************/ +void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_DCH_RECONNECT_PARAM *p_recon_param) +{ + tBTA_HL_API_DCH_RECONNECT *p_buf; + + if ((p_buf = (tBTA_HL_API_DCH_RECONNECT *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_RECONNECT)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_DCH_RECONNECT_EVT; + p_buf->mcl_handle = mcl_handle; + p_buf->ctrl_psm = p_recon_param->ctrl_psm; + p_buf->mdl_id = p_recon_param->mdl_id; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlDchClose +** +** Description Close a data channel with the specified MDL handle +** +** Parameters mdl_handle - MDL handle +** +** Returns void +** +*******************************************************************************/ +void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle) +{ + tBTA_HL_API_DCH_CLOSE *p_buf; + + if ((p_buf = (tBTA_HL_API_DCH_CLOSE *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_CLOSE)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_DCH_CLOSE_EVT; + p_buf->mdl_handle = mdl_handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlDchAbort +** +** Description Abort the current data channel setup with the specified MCL +** handle +** +** Parameters mcl_handle - MCL handle +** +** +** Returns void +** +*******************************************************************************/ +void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle) +{ + tBTA_HL_API_DCH_ABORT *p_buf; + + if ((p_buf = (tBTA_HL_API_DCH_ABORT *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_ABORT)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_DCH_ABORT_EVT; + p_buf->mcl_handle = mcl_handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlSendData +** +** Description Send an APDU to the peer device +** +** Parameters mdl_handle - MDL handle +** pkt_size - size of the data packet to be sent +** +** Returns void +** +*******************************************************************************/ +void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle, + UINT16 pkt_size) +{ + tBTA_HL_API_SEND_DATA *p_buf = NULL; + + if ((p_buf = (tBTA_HL_API_SEND_DATA *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_SEND_DATA)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_SEND_DATA_EVT; + p_buf->mdl_handle = mdl_handle; + p_buf->pkt_size = pkt_size; + bta_sys_sendmsg(p_buf); + } + +} + +/******************************************************************************* +** +** Function BTA_HlDeleteMdl +** +** Description Delete the specified MDL_ID within the specified MCL handle +** +** Parameters mcl_handle - MCL handle +** mdl_id - MDL ID +** +** Returns void +** +** note: If mdl_id = 0xFFFF then this means to delete all MDLs +** and this value can only be used with DeleteMdl request only +** not other requests +** +*******************************************************************************/ +void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_ID mdl_id ) +{ + tBTA_HL_API_DELETE_MDL *p_buf; + + if ((p_buf = (tBTA_HL_API_DELETE_MDL *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DELETE_MDL)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_DELETE_MDL_EVT; + p_buf->mcl_handle = mcl_handle; + p_buf->mdl_id = mdl_id; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_HlDchEchoTest +** +** Description Initiate an echo test with the specified MCL handle +** +** Parameters mcl_handle - MCL handle +*8 p_echo_test_param - parameters for echo testing +** +** Returns void +** +*******************************************************************************/ +void BTA_HlDchEchoTest( tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_DCH_ECHO_TEST_PARAM *p_echo_test_param) +{ + tBTA_HL_API_DCH_ECHO_TEST *p_buf; + + if ((p_buf = (tBTA_HL_API_DCH_ECHO_TEST *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_ECHO_TEST)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_DCH_ECHO_TEST_EVT; + p_buf->mcl_handle = mcl_handle; + p_buf->ctrl_psm = p_echo_test_param->ctrl_psm; + p_buf->local_cfg = p_echo_test_param->local_cfg; + p_buf->pkt_size = p_echo_test_param->pkt_size; + bta_sys_sendmsg(p_buf); + } +} + + +/******************************************************************************* +** +** Function BTA_HlSdpQuery +** +** Description SDP query request for the specified BD address +** +** Parameters app_handle - application handle +** bd_addr - BD address +** +** Returns void +** +*******************************************************************************/ +void BTA_HlSdpQuery(tBTA_HL_APP_HANDLE app_handle, + BD_ADDR bd_addr) +{ + tBTA_HL_API_SDP_QUERY *p_buf; + + if ((p_buf = (tBTA_HL_API_SDP_QUERY *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_SDP_QUERY)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_SDP_QUERY_EVT; + p_buf->app_handle = app_handle; + bdcpy(p_buf->bd_addr, bd_addr); + bta_sys_sendmsg(p_buf); + } +} + + +/******************************************************************************* +** +** Function BTA_HlDchCreateMdlRsp +** +** Description Set the Response and configuration values for the Create MDL +** request +** +** Parameters mcl_handle - MCL handle +** p_rsp_param - parameters specified whether the request should +** be accepted or not and if it should be accepted +** then it also specified the configuration response +** value +** +** Returns void +** +*******************************************************************************/ +void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_DCH_CREATE_RSP_PARAM *p_rsp_param) +{ + tBTA_HL_API_DCH_CREATE_RSP *p_buf; + + if ((p_buf = (tBTA_HL_API_DCH_CREATE_RSP *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_API_DCH_CREATE_RSP)))) != NULL) + { + p_buf->hdr.event = BTA_HL_API_DCH_CREATE_RSP_EVT; + p_buf->mcl_handle = mcl_handle; + p_buf->mdl_id = p_rsp_param->mdl_id; + p_buf->local_mdep_id = p_rsp_param->local_mdep_id; + p_buf->rsp_code = p_rsp_param->rsp_code; + p_buf->cfg_rsp = p_rsp_param->cfg_rsp; + bta_sys_sendmsg(p_buf); + } +} + +#endif /* HL_INCLUDED */ diff --git a/bta/hl/bta_hl_ci.c b/bta/hl/bta_hl_ci.c new file mode 100644 index 0000000..bd04b44 --- /dev/null +++ b/bta/hl/bta_hl_ci.c @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * 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-in functions. + * + ******************************************************************************/ +#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_int.h" + +/******************************************************************************* +** +** Function bta_hl_ci_get_tx_data +** +** Description This function is called in response to the +** bta_hl_co_get_tx_data call-out function. +** +** Parameters mdl_handle -MDL handle +** status - BTA_MA_STATUS_OK if operation is successful +** BTA_MA_STATUS_FAIL if any errors have occurred. +** evt - evt from the call-out function +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_hl_ci_get_tx_data( tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_STATUS status, + UINT16 evt ) +{ + tBTA_HL_CI_GET_PUT_DATA *p_evt; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG3("bta_hl_ci_get_tx_data mdl_handle=%d status=%d evt=%d\n", + mdl_handle, status, evt); +#endif + + if ((p_evt = (tBTA_HL_CI_GET_PUT_DATA *)GKI_getbuf(sizeof(tBTA_HL_CI_GET_PUT_DATA))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->mdl_handle = mdl_handle; + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_hl_ci_put_rx_data +** +** Description This function is called in response to the +** bta_hl_co_put_rx_data call-out function. +** +** Parameters mdl_handle -MDL handle +** status - BTA_MA_STATUS_OK if operation is successful +** BTA_MA_STATUS_FAIL if any errors have occurred. +** evt - evt from the call-out function +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_hl_ci_put_rx_data( tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_STATUS status, + UINT16 evt ) +{ + tBTA_HL_CI_GET_PUT_DATA *p_evt; +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG3("bta_hl_ci_put_rx_data mdl_handle=%d status=%d evt=%d\n", + mdl_handle, status, evt); +#endif + + if ((p_evt = (tBTA_HL_CI_GET_PUT_DATA *)GKI_getbuf(sizeof(tBTA_HL_CI_GET_PUT_DATA))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->mdl_handle = mdl_handle; + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + + +/******************************************************************************* +** +** Function bta_hl_ci_get_echo_data +** +** Description This function is called in response to the +** bta_hl_co_get_echo_data call-out function. +** +** Parameters mcl_handle -MCL handle +** status - BTA_MA_STATUS_OK if operation is successful +** BTA_MA_STATUS_FAIL if any errors have occurred. +** evt - evt from the call-out function +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_hl_ci_get_echo_data( tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status, + UINT16 evt ) +{ + tBTA_HL_CI_ECHO_DATA *p_evt; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG3("bta_hl_ci_get_echo_data mcl_handle=%d status=%d evt=%d\n", + mcl_handle, status, evt); +#endif + + if ((p_evt = (tBTA_HL_CI_ECHO_DATA *)GKI_getbuf(sizeof(tBTA_HL_CI_ECHO_DATA))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->mcl_handle = mcl_handle; + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + +/******************************************************************************* +** +** Function bta_hl_ci_put_echo_data +** +** Description This function is called in response to the +** bta_hl_co_put_echo_data call-out function. +** +** Parameters mcl_handle -MCL handle +** status - BTA_MA_STATUS_OK if operation is successful +** BTA_MA_STATUS_FAIL if any errors have occurred. +** evt - evt from the call-out function +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_hl_ci_put_echo_data( tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status, + UINT16 evt ) +{ + tBTA_HL_CI_ECHO_DATA *p_evt; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG3("bta_hl_ci_put_echo_data mcl_handle=%d status=%d evt=%d\n", + mcl_handle, status, evt); +#endif + + if ((p_evt = (tBTA_HL_CI_ECHO_DATA *)GKI_getbuf(sizeof(tBTA_HL_CI_ECHO_DATA))) != NULL) + { + p_evt->hdr.event = evt; + p_evt->mcl_handle = mcl_handle; + p_evt->status = status; + bta_sys_sendmsg(p_evt); + } +} + diff --git a/bta/hl/bta_hl_int.h b/bta/hl/bta_hl_int.h new file mode 100644 index 0000000..648eb2c --- /dev/null +++ b/bta/hl/bta_hl_int.h @@ -0,0 +1,858 @@ +/****************************************************************************** + * + * Copyright (C) 1998-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 private file for the message access equipment (MSE) + * subsystem. + * + ******************************************************************************/ +#ifndef BTA_HL_INT_H +#define BTA_HL_INT_H + +#include "bt_target.h" +#include "bta_sys.h" +#include "obx_api.h" +#include "bta_hl_api.h" +#include "bta_hl_co.h" +#include "l2cdefs.h" + + +typedef UINT16 (tBTA_HL_ALLOCATE_PSM) (void); + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +#ifndef BTA_HL_DISC_SIZE +#define BTA_HL_DISC_SIZE 1600 +#endif +#define BTA_HL_NUM_SRCH_ATTR 10 +#define BTA_HL_MIN_SDP_MDEP_LEN 7 + +/* L2CAP defualt parameters */ +#define BTA_HL_L2C_TX_WIN_SIZE 10 +#define BTA_HL_L2C_MAX_TRANSMIT 32 +#define BTA_HL_L2C_RTRANS_TOUT 2000 +#define BTA_HL_L2C_MON_TOUT 12000 +#define BTA_HL_L2C_MPS 1017 +#define BTA_HL_L2C_USER_RX_POOL_ID L2CAP_DEFAULT_ERM_POOL_ID +#define BTA_HL_L2C_USER_TX_POOL_ID L2CAP_DEFAULT_ERM_POOL_ID /* todo this should be based on data type */ +#define BTA_HL_L2C_FCR_RX_POOL_ID L2CAP_DEFAULT_ERM_POOL_ID +#define BTA_HL_L2C_FCR_TX_POOL_ID L2CAP_DEFAULT_ERM_POOL_ID + +/* L2CAP FCS setting*/ +#define BTA_HL_MCA_USE_FCS MCA_FCS_USE +#define BTA_HL_MCA_NO_FCS MCA_FCS_BYPASS +#define BTA_HL_L2C_USE_FCS 1 +#define BTA_HL_L2C_NO_FCS 0 +#define BTA_HL_DEFAULT_SOURCE_FCS BTA_HL_L2C_USE_FCS + +/* SDP Operations */ +#define BTA_HL_SDP_OP_NONE 0 +#define BTA_HL_SDP_OP_CCH_INIT 1 +#define BTA_HL_SDP_OP_DCH_OPEN_INIT 2 +#define BTA_HL_SDP_OP_DCH_RECONNECT_INIT 3 +#define BTA_HL_SDP_OP_SDP_QUERY_NEW 4 +#define BTA_HL_SDP_OP_SDP_QUERY_CURRENT 5 + +typedef UINT8 tBTA_HL_SDP_OPER; + +/* CCH Operations */ +#define BTA_HL_CCH_OP_NONE 0 +#define BTA_HL_CCH_OP_LOCAL_OPEN 1 +#define BTA_HL_CCH_OP_REMOTE_OPEN 2 +#define BTA_HL_CCH_OP_LOCAL_CLOSE 3 +#define BTA_HL_CCH_OP_REMOTE_CLOSE 4 + +typedef UINT8 tBTA_HL_CCH_OPER; + +/* Pending DCH close operations when closing a CCH */ +#define BTA_HL_CCH_CLOSE_OP_DCH_NONE 0 +#define BTA_HL_CCH_CLOSE_OP_DCH_ABORT 1 +#define BTA_HL_CCH_CLOSE_OP_DCH_CLOSE 2 +typedef UINT8 tBTA_HL_CCH_CLOSE_DCH_OPER; + +/* DCH Operations */ +#define BTA_HL_DCH_OP_NONE 0 +#define BTA_HL_DCH_OP_REMOTE_CREATE 1 +#define BTA_HL_DCH_OP_LOCAL_OPEN 2 +#define BTA_HL_DCH_OP_REMOTE_OPEN 3 +#define BTA_HL_DCH_OP_LOCAL_CLOSE 4 +#define BTA_HL_DCH_OP_REMOTE_CLOSE 5 +#define BTA_HL_DCH_OP_LOCAL_DELETE 6 +#define BTA_HL_DCH_OP_REMOTE_DELETE 7 +#define BTA_HL_DCH_OP_LOCAL_RECONNECT 8 +#define BTA_HL_DCH_OP_REMOTE_RECONNECT 9 +#define BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST 10 +#define BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT 11 + +typedef UINT8 tBTA_HL_DCH_OPER; + +/* Echo test Operations */ +#define BTA_HL_ECHO_OP_NONE 0 +#define BTA_HL_ECHO_OP_CI_GET_ECHO_DATA 1 +#define BTA_HL_ECHO_OP_SDP_INIT 2 +#define BTA_HL_ECHO_OP_MDL_CREATE_CFM 3 +#define BTA_HL_ECHO_OP_DCH_OPEN_CFM 4 +#define BTA_HL_ECHO_OP_LOOP_BACK 5 +#define BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA 6 +#define BTA_HL_ECHO_OP_DCH_CLOSE_CFM 7 +#define BTA_HL_ECHO_OP_OPEN_IND 8 +#define BTA_HL_ECHO_OP_ECHO_PKT 9 + +typedef UINT8 tBTA_HL_ECHO_OPER; + +/* abort status mask for abort_oper */ + +#define BTA_HL_ABORT_NONE_MASK 0x00 +#define BTA_HL_ABORT_PENDING_MASK 0x01 +#define BTA_HL_ABORT_LOCAL_MASK 0x10 +#define BTA_HL_ABORT_REMOTE_MASK 0x20 +#define BTA_HL_ABORT_CCH_CLOSE_MASK 0x40 + +/* call out mask for cout_oper */ +#define BTA_HL_CO_NONE_MASK 0x00 +#define BTA_HL_CO_GET_TX_DATA_MASK 0x01 +#define BTA_HL_CO_PUT_RX_DATA_MASK 0x02 +#define BTA_HL_CO_GET_ECHO_DATA_MASK 0x04 +#define BTA_HL_CO_PUT_ECHO_DATA_MASK 0x08 + +typedef struct +{ + UINT16 mtu; + UINT8 fcs; /* '0' No FCS, otherwise '1' */ +} tBTA_HL_L2CAP_CFG_INFO; + + +/* State Machine Events */ +enum +{ + /* these events are handled by the state machine */ + BTA_HL_CCH_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HL), + BTA_HL_CCH_SDP_OK_EVT, + BTA_HL_CCH_SDP_FAIL_EVT, + BTA_HL_MCA_CONNECT_IND_EVT, + BTA_HL_MCA_DISCONNECT_IND_EVT, + BTA_HL_CCH_CLOSE_EVT, + BTA_HL_CCH_CLOSE_CMPL_EVT, + BTA_HL_MCA_RSP_TOUT_IND_EVT, + /* DCH EVENT */ + BTA_HL_DCH_SDP_INIT_EVT, + BTA_HL_DCH_OPEN_EVT, + BTA_HL_MCA_CREATE_IND_EVT, + BTA_HL_MCA_CREATE_CFM_EVT, + BTA_HL_MCA_OPEN_IND_EVT, + + BTA_HL_MCA_OPEN_CFM_EVT, + BTA_HL_DCH_CLOSE_EVT, + BTA_HL_MCA_CLOSE_IND_EVT, + BTA_HL_MCA_CLOSE_CFM_EVT, + BTA_HL_API_SEND_DATA_EVT, + + BTA_HL_MCA_RCV_DATA_EVT, + BTA_HL_DCH_CLOSE_CMPL_EVT, + BTA_HL_DCH_RECONNECT_EVT, + BTA_HL_DCH_SDP_FAIL_EVT, + BTA_HL_MCA_RECONNECT_IND_EVT, + + BTA_HL_MCA_RECONNECT_CFM_EVT, + BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, + BTA_HL_API_DCH_CREATE_RSP_EVT, + BTA_HL_DCH_ABORT_EVT, + BTA_HL_MCA_ABORT_IND_EVT, + + BTA_HL_MCA_ABORT_CFM_EVT, + BTA_HL_MCA_CONG_CHG_EVT, + BTA_HL_CI_GET_TX_DATA_EVT, + BTA_HL_CI_PUT_RX_DATA_EVT, + BTA_HL_CI_GET_ECHO_DATA_EVT, + BTA_HL_DCH_ECHO_TEST_EVT, + BTA_HL_CI_PUT_ECHO_DATA_EVT, + + /* these events are handled outside the state machine */ + BTA_HL_API_ENABLE_EVT, + BTA_HL_API_DISABLE_EVT, + BTA_HL_API_REGISTER_EVT, + BTA_HL_API_DEREGISTER_EVT, + BTA_HL_API_CCH_OPEN_EVT, + BTA_HL_API_CCH_CLOSE_EVT, + BTA_HL_API_DCH_OPEN_EVT, + BTA_HL_API_DCH_RECONNECT_EVT, + BTA_HL_API_DCH_CLOSE_EVT, + BTA_HL_API_DELETE_MDL_EVT, + BTA_HL_API_DCH_ABORT_EVT, + + BTA_HL_API_DCH_ECHO_TEST_EVT, + BTA_HL_API_SDP_QUERY_EVT, + BTA_HL_SDP_QUERY_OK_EVT, + BTA_HL_SDP_QUERY_FAIL_EVT, + BTA_HL_MCA_DELETE_IND_EVT, + BTA_HL_MCA_DELETE_CFM_EVT +}; +typedef UINT16 tBTA_HL_INT_EVT; + +#define BTA_HL_DCH_EVT_MIN BTA_HL_DCH_SDP_INIT_EVT +#define BTA_HL_DCH_EVT_MAX 0xFFFF + + +/* state machine states */ +enum +{ + BTA_HL_CCH_IDLE_ST = 0, /* Idle */ + BTA_HL_CCH_OPENING_ST, /* Opening a connection*/ + BTA_HL_CCH_OPEN_ST, /* Connection is open */ + BTA_HL_CCH_CLOSING_ST /* Closing is in progress */ +}; +typedef UINT8 tBTA_HL_CCH_STATE; + +enum +{ + BTA_HL_DCH_IDLE_ST = 0, /* Idle */ + BTA_HL_DCH_OPENING_ST, /* Opening a connection*/ + BTA_HL_DCH_OPEN_ST, /* Connection is open */ + BTA_HL_DCH_CLOSING_ST /* Closing is in progress */ +}; +typedef UINT8 tBTA_HL_DCH_STATE; + + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_CTRL_CBACK *p_cback; /* pointer to control callback function */ +} tBTA_HL_API_ENABLE; + +typedef struct +{ + BT_HDR hdr; + UINT8 app_id; + tBTA_HL_CBACK *p_cback; /* pointer to application callback function */ + tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */ + tBTA_SEC sec_mask; /* security mask for accepting conenction*/ + char srv_name[BTA_SERVICE_NAME_LEN +1]; /* service name to be used in the SDP; null terminated*/ + char srv_desp[BTA_SERVICE_DESP_LEN +1]; /* service description to be used in the SDP; null terminated */ + char provider_name[BTA_PROVIDER_NAME_LEN +1]; /* provide name to be used in the SDP; null terminated */ +} tBTA_HL_API_REGISTER; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_API_DEREGISTER; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_APP_HANDLE app_handle; + UINT16 ctrl_psm; + BD_ADDR bd_addr; /* Address of peer device */ + tBTA_SEC sec_mask; /* security mask for initiating connection*/ +} tBTA_HL_API_CCH_OPEN; + + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MCL_HANDLE mcl_handle; +} tBTA_HL_API_CCH_CLOSE; + + + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MCL_HANDLE mcl_handle; + UINT16 ctrl_psm; + tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */ + tBTA_HL_MDEP_ID peer_mdep_id; /* peer mdep id */ + tBTA_HL_DCH_CFG local_cfg; + tBTA_SEC sec_mask; /* security mask for initiating connection*/ +} tBTA_HL_API_DCH_OPEN; + + +typedef struct +{ + BT_HDR hdr; + + tBTA_HL_MCL_HANDLE mcl_handle; + UINT16 ctrl_psm; + tBTA_HL_MDL_ID mdl_id; +} tBTA_HL_API_DCH_RECONNECT; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MDL_HANDLE mdl_handle; +} tBTA_HL_API_DCH_CLOSE; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_MDL_ID mdl_id; +} tBTA_HL_API_DELETE_MDL; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MCL_HANDLE mcl_handle; +} tBTA_HL_API_DCH_ABORT; + + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MDL_HANDLE mdl_handle; + UINT16 pkt_size; +} tBTA_HL_API_SEND_DATA; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MCL_HANDLE mcl_handle; + UINT16 ctrl_psm; + UINT16 pkt_size; + tBTA_HL_DCH_CFG local_cfg; +} tBTA_HL_API_DCH_ECHO_TEST; + +typedef struct +{ + BT_HDR hdr; + UINT8 app_idx; + UINT8 mcl_idx; + BOOLEAN release_mcl_cb; +}tBTA_HL_CCH_SDP; + + +/* MCA callback event parameters. */ +typedef struct +{ + BT_HDR hdr; + tBTA_HL_APP_HANDLE app_handle; + tBTA_HL_MCL_HANDLE mcl_handle; + tMCA_CTRL mca_data; +} tBTA_HL_MCA_EVT; + + +/* MCA callback event parameters. */ +typedef struct +{ + BT_HDR hdr; + UINT8 app_idx; + UINT8 mcl_idx; + UINT8 mdl_idx; + BT_HDR *p_pkt; +} tBTA_HL_MCA_RCV_DATA_EVT; + + +typedef struct +{ + BT_HDR hdr; + UINT8 app_idx; + UINT8 mcl_idx; + UINT8 mdl_idx; +}tBTA_HL_DCH_SDP; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_APP_HANDLE app_handle; + BD_ADDR bd_addr; /* Address of peer device */ +} tBTA_HL_API_SDP_QUERY; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_MDL_ID mdl_id; + tBTA_HL_MDEP_ID local_mdep_id; + tBTA_HL_DCH_CREATE_RSP rsp_code; + tBTA_HL_DCH_CFG cfg_rsp; +} tBTA_HL_API_DCH_CREATE_RSP; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MDL_HANDLE mdl_handle; + tBTA_HL_STATUS status; +} tBTA_HL_CI_GET_PUT_DATA; + +typedef struct +{ + BT_HDR hdr; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_STATUS status; +} tBTA_HL_CI_ECHO_DATA; + +/* union of all state machine event data types */ +typedef union +{ + BT_HDR hdr; + tBTA_HL_API_ENABLE api_enable; /* data for BTA_MSE_API_ENABLE_EVT */ + tBTA_HL_API_REGISTER api_reg; + tBTA_HL_API_DEREGISTER api_dereg; + tBTA_HL_API_CCH_OPEN api_cch_open; + tBTA_HL_API_CCH_CLOSE api_cch_close; + tBTA_HL_API_DCH_CREATE_RSP api_dch_create_rsp; + tBTA_HL_API_DCH_OPEN api_dch_open; + tBTA_HL_API_DCH_RECONNECT api_dch_reconnect; + tBTA_HL_API_DCH_CLOSE api_dch_close; + tBTA_HL_API_DELETE_MDL api_delete_mdl; + tBTA_HL_API_DCH_ABORT api_dch_abort; + tBTA_HL_API_SEND_DATA api_send_data; + tBTA_HL_API_DCH_ECHO_TEST api_dch_echo_test; + tBTA_HL_API_SDP_QUERY api_sdp_query; + + tBTA_HL_CCH_SDP cch_sdp; + tBTA_HL_MCA_EVT mca_evt; + tBTA_HL_MCA_RCV_DATA_EVT mca_rcv_data_evt; + tBTA_HL_DCH_SDP dch_sdp; /* for DCH_OPEN_EVT and DCH_RECONNECT_EVT */ + tBTA_HL_CI_GET_PUT_DATA ci_get_put_data; + tBTA_HL_CI_ECHO_DATA ci_get_put_echo_data; +} tBTA_HL_DATA; + + +typedef struct +{ + BOOLEAN in_use; + UINT16 mdl_id; + tBTA_HL_MDL_HANDLE mdl_handle; + tBTA_HL_DCH_OPER dch_oper; + BOOLEAN intentional_close; + tBTA_HL_DCH_STATE dch_state; + UINT8 abort_oper; + UINT16 req_data_psm; + UINT16 max_rx_apdu_size; + UINT16 max_tx_apdu_size; + BT_HDR *p_tx_pkt; + BT_HDR *p_rx_pkt; + tBTA_HL_MDEP_ID local_mdep_id; + UINT8 local_mdep_cfg_idx; + tBTA_HL_DCH_CFG local_cfg; + tBTA_HL_DCH_CFG remote_cfg; + tBTA_HL_MDEP_ID peer_mdep_id; + UINT16 peer_data_type; + tBTA_HL_MDEP_ROLE peer_mdep_role; + tBTA_HL_DCH_MODE dch_mode; + tBTA_SEC sec_mask; + BOOLEAN is_the_first_reliable; + BOOLEAN delete_mdl; + UINT16 mtu; + tMCA_CHNL_CFG chnl_cfg; + BOOLEAN mdl_cfg_idx_included; + UINT8 mdl_cfg_idx; + UINT8 echo_oper; + BOOLEAN cong; + BOOLEAN close_pending; + UINT8 cout_oper; + BT_HDR *p_echo_tx_pkt; + BT_HDR *p_echo_rx_pkt; + tBTA_HL_STATUS ci_put_echo_data_status; +}tBTA_HL_MDL_CB; + +typedef struct +{ + tBTA_HL_MDL_CB mdl[BTA_HL_NUM_MDLS_PER_MCL]; + tBTA_HL_DELETE_MDL delete_mdl; + BOOLEAN in_use; + tBTA_HL_CCH_STATE cch_state; + UINT16 req_ctrl_psm; + UINT16 ctrl_psm; + UINT16 data_psm; + BD_ADDR bd_addr; + UINT16 cch_mtu; + UINT16 sec_mask; + tBTA_HL_MCL_HANDLE mcl_handle; + tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */ + tSDP_DISC_CMPL_CB *sdp_cback; + tBTA_HL_SDP_OPER sdp_oper; + BOOLEAN close_pending; + UINT8 sdp_mdl_idx; + tBTA_HL_SDP sdp; + UINT8 cch_oper; + BOOLEAN intentional_close; + BOOLEAN rsp_tout; + UINT8 timer_oper; + BOOLEAN echo_test; + UINT8 echo_mdl_idx; + UINT8 cch_close_dch_oper; +}tBTA_HL_MCL_CB; + +typedef struct +{ + tBTA_HL_MCL_CB mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */ + tBTA_HL_CBACK *p_cback; /* pointer to control callback function */ + BOOLEAN in_use; /* this CB is in use*/ + BOOLEAN deregistering; + UINT8 app_id; + UINT32 sdp_handle; /* SDP record handle */ + tBTA_HL_SUP_FEATURE sup_feature; + tBTA_HL_MDL_CFG mdl_cfg[BTA_HL_NUM_MDL_CFGS]; + tBTA_HL_DEVICE_TYPE dev_type; + tBTA_HL_APP_HANDLE app_handle; + UINT16 ctrl_psm; /* L2CAP PSM for the MCAP control channel */ + UINT16 data_psm; /* L2CAP PSM for the MCAP data channel */ + UINT16 sec_mask; /* Security mask for BTM_SetSecurityLevel() */ + + char srv_name[BTA_SERVICE_NAME_LEN +1]; /* service name to be used in the SDP; null terminated*/ + char srv_desp[BTA_SERVICE_DESP_LEN +1]; /* service description to be used in the SDP; null terminated */ + char provider_name[BTA_PROVIDER_NAME_LEN +1]; /* provide name to be used in the SDP; null terminated */ + + tMCA_CTRL_CBACK *p_mcap_cback; /* pointer to MCAP callback function */ + tMCA_DATA_CBACK *p_data_cback; +}tBTA_HL_APP_CB; + + +typedef struct +{ + BOOLEAN in_use; + tBTA_HL_SDP_OPER sdp_oper; + UINT8 app_idx; + UINT8 mcl_idx; + UINT8 mdl_idx; +}tBTA_HL_SDP_CB; + +typedef struct +{ + BOOLEAN in_use; + UINT8 app_idx; + UINT8 mcl_idx; +}tBTA_HL_TIMER_CB; + +typedef struct +{ + tBTA_HL_APP_CB acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */ + tBTA_HL_CTRL_CBACK *p_ctrl_cback; /* pointer to control callback function */ + BOOLEAN enable; + BOOLEAN disabling; + + tBTA_HL_SDP_CB scb[BTA_HL_NUM_SDP_CBACKS]; + tBTA_HL_TIMER_CB tcb[BTA_HL_NUM_TIMERS]; + BOOLEAN enable_random_psm; + tBTA_HL_ALLOCATE_PSM *p_alloc_psm; +}tBTA_HL_CB; + +/****************************************************************************** +** Configuration Definitions +*******************************************************************************/ +/* Configuration structure */ + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* HL control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_HL_CB bta_hl_cb; +#else +extern tBTA_HL_CB *bta_hl_cb_ptr; + #define bta_hl_cb (*bta_hl_cb_ptr) +#endif + +#define BTA_HL_GET_CB_PTR() &(bta_hl_cb) +#define BTA_HL_GET_APP_CB_PTR(app_idx) &(bta_hl_cb.acb[(app_idx)]) +#define BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)]) +#define BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[mdl_idx]) +#define BTA_HL_GET_MDL_CFG_PTR(app_idx, item_idx) &(bta_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)]) +#define BTA_HL_GET_ECHO_CFG_PTR(app_idx) &(bta_hl_cb.acb[(app_idx)].sup_feature.echo_cfg) +#define BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx) &(bta_hl_cb.acb[(app_idx)].sup_feature.mdep[mdep_cfg_idx].mdep_cfg) +#define BTA_HL_GET_DATA_CFG_PTR(app_idx, mdep_cfg_idx, data_cfg_idx) \ + &(bta_hl_cb.acb[(app_idx)].sup_feature.mdep[mdep_cfg_idx].mdep_cfg.data_cfg[data_cfg_idx]) +#define BTA_HL_GET_BUF_PTR(p_pkt) ((UINT8 *)((UINT8 *) (p_pkt+1) + p_pkt->offset)) + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + /* main */ + extern BOOLEAN bta_hl_hdl_event(BT_HDR *p_msg); + /* sdp */ + extern BOOLEAN bta_hl_fill_sup_feature_list( const tSDP_DISC_ATTR *p_attr, + tBTA_HL_SUP_FEATURE_LIST_ELEM *p_list); + + extern tBTA_HL_STATUS bta_hl_sdp_register (UINT8 app_idx); + extern tSDP_DISC_REC *bta_hl_find_sink_or_src_srv_class_in_db (const tSDP_DISCOVERY_DB *p_db, + const tSDP_DISC_REC *p_start_rec); + + /* action routines */ + extern void bta_hl_dch_ci_get_tx_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_ci_put_rx_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_ci_get_echo_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + + extern void bta_hl_dch_echo_test(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_ci_put_echo_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_send_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_sdp_fail(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_cong_change(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_reconnect_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_reconnect_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_reconnect(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_sdp_init(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_close_echo_test(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_create_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_rcv_data(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_close_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_close_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_close(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_delete_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + + extern void bta_hl_dch_mca_delete_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_delete(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_abort_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_abort_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_abort(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_open_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_open_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_create_ind(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_create_cfm(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_dch_mca_create(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_DATA *p_data); + extern void bta_hl_deallocate_spd_cback(UINT8 sdp_cback_idx); + extern tSDP_DISC_CMPL_CB *bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx, + UINT8 *p_sdp_cback_idx); + extern tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx); + extern void bta_hl_cch_sdp_init(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + extern void bta_hl_cch_mca_open(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + extern void bta_hl_cch_mca_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + extern void bta_hl_cch_close_cmpl(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + extern void bta_hl_cch_mca_disconnect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + extern void bta_hl_cch_mca_rsp_tout(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + extern void bta_hl_cch_mca_connect(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + + /* State machine drivers */ + extern void bta_hl_cch_sm_execute(UINT8 inst_idx, UINT8 mcl_idx, + UINT16 event, tBTA_HL_DATA *p_data); + extern void bta_hl_dch_sm_execute(UINT8 inst_idx, UINT8 mcl_idx, UINT8 mdl_idx, + UINT16 event, tBTA_HL_DATA *p_data); + /* MCAP callback functions */ + extern void bta_hl_mcap_ctrl_cback(tMCA_HANDLE handle, tMCA_CL mcl, UINT8 event, + tMCA_CTRL *p_data); + + extern void bta_hl_mcap_data_cback(tMCA_DL mdl, BT_HDR *p_pkt); + + /* utility functions */ + extern BOOLEAN bta_hl_set_ctrl_psm_for_dch(UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx, UINT16 ctrl_psm); + extern BOOLEAN bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP *p_sdp, + UINT16 ctrl_psm, + UINT8 *p_sdp_idx); + extern UINT8 bta_hl_set_user_tx_pool_id(UINT16 max_tx_size); + extern UINT8 bta_hl_set_user_rx_pool_id(UINT16 mtu); + extern UINT8 bta_hl_set_tx_win_size(UINT16 mtu, UINT16 mps); + extern UINT16 bta_hl_set_mps(UINT16 mtu); + extern void bta_hl_clean_mdl_cb(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx); + extern BT_HDR * bta_hl_get_buf(UINT16 data_size); + extern BOOLEAN bta_hl_find_service_in_db( UINT8 app_idx, UINT8 mcl_idx, + UINT16 service_uuid, + tSDP_DISC_REC **pp_rec ); + extern UINT16 bta_hl_get_service_uuids(UINT8 sdp_oper, UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx ); + extern BOOLEAN bta_hl_find_echo_cfg_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdep_idx, UINT8 cfg, + UINT8 *p_cfg_rsp); + extern BOOLEAN bta_hl_validate_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + UINT8 cfg); + extern BOOLEAN bta_hl_find_cch_cb_indexes(tBTA_HL_DATA *p_msg, + UINT8 *p_app_idx, + UINT8 *p_mcl_idx); + extern BOOLEAN bta_hl_find_dch_cb_indexes(tBTA_HL_DATA *p_msg, + UINT8 *p_app_idx, + UINT8 *p_mcl_idx, + UINT8 *p_mdl_idx); + extern UINT16 bta_hl_allocate_mdl_id(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx ); + extern BOOLEAN bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle, + UINT8 *p_app_idx, UINT8 *p_mcl_idx, + UINT8 *p_mdl_idx); + extern BOOLEAN bta_hl_find_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, UINT16 mdl_id, + UINT8 *p_mdl_idx); + extern BOOLEAN bta_hl_find_an_active_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, + UINT8 *p_mdl_idx); + extern BOOLEAN bta_hl_find_dch_setup_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, + UINT8 *p_mdl_idx); + extern BOOLEAN bta_hl_find_an_in_use_mcl_idx(UINT8 app_idx, + UINT8 *p_mcl_idx); + extern BOOLEAN bta_hl_find_an_in_use_app_idx(UINT8 *p_app_idx); + extern BOOLEAN bta_hl_find_app_idx(UINT8 app_id, UINT8 *p_app_idx); + extern BOOLEAN bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle, + UINT8 *p_app_idx); + extern BOOLEAN bta_hl_find_mcl_idx_using_handle( tBTA_HL_MCL_HANDLE mcl_handle, + UINT8 *p_app_idx, UINT8 *p_mcl_idx); + extern BOOLEAN bta_hl_find_mcl_idx(UINT8 app_idx, BD_ADDR p_bd_addr, UINT8 *p_mcl_idx); + extern BOOLEAN bta_hl_is_the_first_reliable_existed(UINT8 app_idx, UINT8 mcl_idx ); + extern BOOLEAN bta_hl_find_non_active_mdl_cfg(UINT8 app_idx, UINT8 start_mdl_cfg_idx, + UINT8 *p_mdl_cfg_idx); + extern BOOLEAN bta_hl_find_avail_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx, + UINT8 *p_mdl_cfg_idx); + extern BOOLEAN bta_hl_find_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx, + tBTA_HL_MDL_ID mdl_id, UINT8 *p_mdl_cfg_idx); + extern BOOLEAN bta_hl_get_cur_time(UINT8 app_idx, UINT8 *p_cur_time); + extern void bta_hl_sort_cfg_time_idx(UINT8 app_idx, UINT8 *a, UINT8 n); + extern void bta_hl_compact_mdl_cfg_time(UINT8 app_idx); + extern BOOLEAN bta_hl_is_mdl_exsit_in_mcl(UINT8 app_idx, BD_ADDR bd_addr, + tBTA_HL_MDL_ID mdl_id); + extern BOOLEAN bta_hl_delete_mdl_cfg(UINT8 app_idx, BD_ADDR bd_addr, + tBTA_HL_MDL_ID mdl_id); + extern BOOLEAN bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id); + extern BOOLEAN bta_hl_find_mdep_cfg_idx(UINT8 app_idx, + tBTA_HL_MDEP_ID local_mdep_id, UINT8 *p_mdep_cfg_idx); + extern void bta_hl_find_rxtx_apdu_size(UINT8 app_idx, UINT8 mdep_cfg_idx, + UINT16 *p_rx_apu_size, + UINT16 *p_tx_apu_size); + extern BOOLEAN bta_hl_validate_peer_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_MDEP_ID peer_mdep_id, + tBTA_HL_MDEP_ROLE peer_mdep_role, + UINT8 sdp_idx); + extern tBTA_HL_STATUS bta_hl_chk_local_cfg(UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdep_cfg_idx, + tBTA_HL_DCH_CFG local_cfg); + + extern BOOLEAN bta_hl_validate_reconnect_params(UINT8 app_idx, UINT8 mcl_idx, + tBTA_HL_API_DCH_RECONNECT *p_reconnect, + UINT8 *p_mdep_cfg_idx, UINT8 *p_mdl_cfg_idx); + extern BOOLEAN bta_hl_find_avail_mcl_idx(UINT8 app_idx, UINT8 *p_mcl_idx); + extern BOOLEAN bta_hl_find_avail_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, + UINT8 *p_mdl_idx); + extern BOOLEAN bta_hl_is_a_duplicate_id(UINT8 app_id); + extern BOOLEAN bta_hl_find_avail_app_idx(UINT8 *p_idx); + extern tBTA_HL_STATUS bta_hl_app_registration(UINT8 app_idx); + extern void bta_hl_discard_data(UINT16 event, tBTA_HL_DATA *p_data); + extern void bta_hl_save_mdl_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx ); + extern void bta_hl_set_dch_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, tBTA_HL_DATA *p_data); + extern BOOLEAN bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd, tBTA_HL_L2CAP_CFG_INFO *p_cfg); + extern BOOLEAN bta_hl_validate_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx); + extern BOOLEAN bta_hl_is_cong_on(UINT8 app_id, BD_ADDR bd_addr, tBTA_HL_MDL_ID mdl_id); + extern void bta_hl_check_cch_close(UINT8 app_idx, UINT8 mcl_idx, + tBTA_HL_DATA *p_data, BOOLEAN check_dch_setup); + extern void bta_hl_clean_app(UINT8 app_idx); + extern void bta_hl_check_deregistration(UINT8 app_idx, tBTA_HL_DATA *p_data ); + extern void bta_hl_check_disable(tBTA_HL_DATA *p_data ); + extern void bta_hl_build_abort_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle); + extern void bta_hl_build_abort_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status); + extern void bta_hl_build_dch_close_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_STATUS status); + extern void bta_hl_build_dch_close_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle, + BOOLEAN intentional); + extern void bta_hl_build_send_data_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_STATUS status ); + extern void bta_hl_build_rcv_data_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle); + extern void bta_hl_build_cch_open_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + BD_ADDR bd_addr, + tBTA_HL_STATUS status ); + extern void bta_hl_build_cch_open_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + BD_ADDR bd_addr); + extern void bta_hl_build_cch_close_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status ); + extern void bta_hl_build_cch_close_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + BOOLEAN intentional); + + extern void bta_hl_build_dch_open_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_MDEP_ID local_mdep_id, + tBTA_HL_MDL_ID mdl_id, + tBTA_HL_DCH_MODE dch_mode, + BOOLEAN first_reliable, + UINT16 mtu, + tBTA_HL_STATUS status); + + extern void bta_hl_build_delete_mdl_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_ID mdl_id, + tBTA_HL_STATUS status); + extern void bta_hl_build_echo_test_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status ); + extern void bta_hl_build_sdp_query_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + BD_ADDR bd_addr, + tBTA_HL_SDP *p_sdp, + tBTA_HL_STATUS status); + +#if (BTA_HL_DEBUG == TRUE) + extern char *bta_hl_status_code(tBTA_HL_STATUS status); + extern char *bta_hl_evt_code(tBTA_HL_INT_EVT evt_code); +#endif +#ifdef __cplusplus +} +#endif +#endif /* BTA_MSE_INT_H */ + + diff --git a/bta/hl/bta_hl_main.c b/bta/hl/bta_hl_main.c new file mode 100644 index 0000000..afac4c3 --- /dev/null +++ b/bta/hl/bta_hl_main.c @@ -0,0 +1,1920 @@ +/****************************************************************************** + * + * Copyright (C) 1998-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the HeaLth device profile main functions and state + * machine. + * + ******************************************************************************/ +#include <string.h> + +#include "bt_target.h" +#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE) + + + +#include "bta_hl_api.h" +#include "bta_hl_int.h" +#include "gki.h" +#include "utl.h" +#include "bd.h" +#include "l2c_api.h" +#include "mca_defs.h" + + +#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE) +static char *bta_hl_cch_state_code(tBTA_HL_CCH_STATE state_code); +static char *bta_hl_dch_state_code(tBTA_HL_DCH_STATE state_code); +#endif + +extern UINT16 L2CA_AllocateRandomPsm(void); +extern UINT16 L2CA_AllocatePsm(void); +/***************************************************************************** +** DCH State Table +*****************************************************************************/ +/***************************************************************************** +** Constants and types +*****************************************************************************/ +/* state machine action enumeration list for DCH */ +/* The order of this enumeration must be the same as bta_hl_dch_act_tbl[] */ +enum +{ + BTA_HL_DCH_MCA_CREATE, + BTA_HL_DCH_MCA_CREATE_CFM, + BTA_HL_DCH_MCA_CREATE_IND, + BTA_HL_DCH_MCA_OPEN_CFM, + BTA_HL_DCH_MCA_OPEN_IND, + BTA_HL_DCH_MCA_CLOSE, + BTA_HL_DCH_MCA_CLOSE_CFM, + BTA_HL_DCH_MCA_CLOSE_IND, + BTA_HL_DCH_CLOSE_CMPL, + BTA_HL_DCH_MCA_RCV_DATA, + + BTA_HL_DCH_SDP_INIT, + BTA_HL_DCH_MCA_RECONNECT, + BTA_HL_DCH_MCA_RECONNECT_IND, + BTA_HL_DCH_MCA_RECONNECT_CFM, + BTA_HL_DCH_CLOSE_ECHO_TEST, + BTA_HL_DCH_CREATE_RSP, + BTA_HL_DCH_MCA_ABORT, + BTA_HL_DCH_MCA_ABORT_IND, + BTA_HL_DCH_MCA_ABORT_CFM, + BTA_HL_DCH_MCA_CONG_CHANGE, + + BTA_HL_DCH_SDP_FAIL, + BTA_HL_DCH_SEND_DATA, + BTA_HL_DCH_CI_GET_TX_DATA, + BTA_HL_DCH_CI_PUT_RX_DATA, + BTA_HL_DCH_CI_GET_ECHO_DATA, + BTA_HL_DCH_ECHO_TEST, + BTA_HL_DCH_CI_PUT_ECHO_DATA, + BTA_HL_DCH_IGNORE +}; + +typedef void (*tBTA_HL_DCH_ACTION)(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, tBTA_HL_DATA *p_data); + +static const tBTA_HL_DCH_ACTION bta_hl_dch_action[] = +{ + bta_hl_dch_mca_create, + bta_hl_dch_mca_create_cfm, + bta_hl_dch_mca_create_ind, + bta_hl_dch_mca_open_cfm, + bta_hl_dch_mca_open_ind, + bta_hl_dch_mca_close, + bta_hl_dch_mca_close_cfm, + bta_hl_dch_mca_close_ind, + bta_hl_dch_close_cmpl, + bta_hl_dch_mca_rcv_data, + + bta_hl_dch_sdp_init, + bta_hl_dch_mca_reconnect, + bta_hl_dch_mca_reconnect_ind, + bta_hl_dch_mca_reconnect_cfm, + bta_hl_dch_close_echo_test, + bta_hl_dch_create_rsp, + bta_hl_dch_mca_abort, + bta_hl_dch_mca_abort_ind, + bta_hl_dch_mca_abort_cfm, + bta_hl_dch_mca_cong_change, + + bta_hl_dch_sdp_fail, + bta_hl_dch_send_data, + bta_hl_dch_ci_get_tx_data, + bta_hl_dch_ci_put_rx_data, + bta_hl_dch_ci_get_echo_data, + bta_hl_dch_echo_test, + bta_hl_dch_ci_put_echo_data, +}; + + +/* state table information */ +#define BTA_HL_DCH_ACTIONS 1 /* number of actions */ +#define BTA_HL_DCH_ACTION_COL 0 /* position of action */ +#define BTA_HL_DCH_NEXT_STATE 1 /* position of next state */ +#define BTA_HL_DCH_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for idle state */ +static const UINT8 bta_hl_dch_st_idle[][BTA_HL_DCH_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_SDP_INIT, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_MCA_CREATE, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_MCA_CREATE_IND, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, + +/* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, + +/* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_MCA_RECONNECT, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_MCA_RECONNECT_IND, BTA_HL_DCH_OPENING_ST}, + +/* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, + +/* BTA_HL_MCA_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_ECHO_TEST, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST} +}; + +/* state table for opening state */ +static const UINT8 bta_hl_dch_st_opening[][BTA_HL_DCH_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_SDP_INIT, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_MCA_CREATE, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_MCA_CREATE_CFM, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_MCA_OPEN_IND, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_MCA_OPEN_CFM, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_MCA_CLOSE_IND, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, + +/* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_MCA_RECONNECT, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_SDP_FAIL, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_MCA_RECONNECT_CFM, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_CREATE_RSP, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_MCA_ABORT, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_MCA_ABORT_IND, BTA_HL_DCH_OPENING_ST}, + +/* BTA_HL_MCA_ABORT_CFM_EVT */ {BTA_HL_DCH_MCA_ABORT_CFM, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_ECHO_TEST, BTA_HL_DCH_OPENING_ST}, +/* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST} +}; + +/* state table for open state */ +static const UINT8 bta_hl_dch_st_open[][BTA_HL_DCH_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_MCA_CLOSE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_MCA_CLOSE_IND, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_SEND_DATA, BTA_HL_DCH_OPEN_ST}, + +/* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_MCA_RCV_DATA, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_CLOSE_ECHO_TEST, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, + +/* BTA_HL_DCH_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_MCA_CONG_CHANGE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_CI_GET_TX_DATA, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_CI_PUT_RX_DATA, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST}, +/* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_PUT_ECHO_DATA, BTA_HL_DCH_OPEN_ST} +}; + + +/* state table for closing state */ +static const UINT8 bta_hl_dch_st_closing[][BTA_HL_DCH_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_MCA_CLOSE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, + +/* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST}, +/* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, + +/* BTA_HL_DCH_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_CI_GET_TX_DATA, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_CI_PUT_RX_DATA, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST}, +/* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_PUT_ECHO_DATA, BTA_HL_DCH_CLOSING_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_HL_DCH_ST_TBL)[BTA_HL_DCH_NUM_COLS]; + +/* state table */ +const tBTA_HL_DCH_ST_TBL bta_hl_dch_st_tbl[] = +{ + bta_hl_dch_st_idle, + bta_hl_dch_st_opening, + bta_hl_dch_st_open, + bta_hl_dch_st_closing +}; + +/***************************************************************************** +** CCH State Table +*****************************************************************************/ +/***************************************************************************** +** Constants and types +*****************************************************************************/ +/* state machine action enumeration list for CCH */ +enum +{ + BTA_HL_CCH_SDP_INIT, + BTA_HL_CCH_MCA_OPEN, + BTA_HL_CCH_MCA_CLOSE, + BTA_HL_CCH_CLOSE_CMPL, + BTA_HL_CCH_MCA_CONNECT, + BTA_HL_CCH_MCA_DISCONNECT, + BTA_HL_CCH_MCA_RSP_TOUT, + BTA_HL_CCH_IGNORE +}; + +/* type for action functions */ +typedef void (*tBTA_HL_CCH_ACTION)(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data); + +/* action function list for MAS */ +const tBTA_HL_CCH_ACTION bta_hl_cch_action[] = +{ + bta_hl_cch_sdp_init, + bta_hl_cch_mca_open, + bta_hl_cch_mca_close, + bta_hl_cch_close_cmpl, + bta_hl_cch_mca_connect, + bta_hl_cch_mca_disconnect, + bta_hl_cch_mca_rsp_tout +}; + + +/* state table information */ +#define BTA_HL_CCH_ACTIONS 1 /* number of actions */ +#define BTA_HL_CCH_NEXT_STATE 1 /* position of next state */ +#define BTA_HL_CCH_NUM_COLS 2 /* number of columns in state tables */ + + +/* state table for MAS idle state */ +static const UINT8 bta_hl_cch_st_idle[][BTA_HL_CCH_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_SDP_INIT, BTA_HL_CCH_OPENING_ST}, +/* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST} +}; + +/* state table for obex/rfcomm connection state */ +static const UINT8 bta_hl_cch_st_opening[][BTA_HL_CCH_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPENING_ST}, +/* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_MCA_OPEN, BTA_HL_CCH_OPENING_ST}, +/* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT, BTA_HL_CCH_CLOSING_ST}, +/* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE, BTA_HL_CCH_CLOSING_ST}, +/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_MCA_RSP_TOUT, BTA_HL_CCH_CLOSING_ST} +}; + +/* state table for open state */ +static const UINT8 bta_hl_cch_st_open[][BTA_HL_CCH_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT, BTA_HL_CCH_CLOSING_ST}, +/* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE, BTA_HL_CCH_CLOSING_ST}, +/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_MCA_RSP_TOUT, BTA_HL_CCH_CLOSING_ST} +}; + +/* state table for closing state */ +static const UINT8 bta_hl_cch_st_closing[][BTA_HL_CCH_NUM_COLS] = +{ +/* Event Action 1 Next state */ +/* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_CLOSING_ST}, +/* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT, BTA_HL_CCH_OPEN_ST}, +/* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT, BTA_HL_CCH_CLOSING_ST}, +/* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE, BTA_HL_CCH_CLOSING_ST}, +/* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_CLOSE_CMPL, BTA_HL_CCH_IDLE_ST}, +/* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_CLOSING_ST} +}; + +/* type for state table CCH */ +typedef const UINT8 (*tBTA_HL_CCH_ST_TBL)[BTA_HL_CCH_NUM_COLS]; + +/* MAS state table */ +const tBTA_HL_CCH_ST_TBL bta_hl_cch_st_tbl[] = +{ + bta_hl_cch_st_idle, + bta_hl_cch_st_opening, + bta_hl_cch_st_open, + bta_hl_cch_st_closing +}; + + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* HL control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_HL_CB bta_hl_cb; +#endif + + +/******************************************************************************* +** +** Function bta_hl_cch_sm_execute +** +** Description State machine event handling function for CCH +** +** Returns void +** +*******************************************************************************/ +void bta_hl_cch_sm_execute(UINT8 app_idx, UINT8 mcl_idx, + UINT16 event, tBTA_HL_DATA *p_data) +{ + tBTA_HL_CCH_ST_TBL state_table; + UINT8 action; + int i; + tBTA_HL_MCL_CB *p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + +#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE) + tBTA_HL_CCH_STATE in_state = p_cb->cch_state; + UINT16 cur_evt = event; + APPL_TRACE_DEBUG3("HDP CCH Event Handler: State 0x%02x [%s], Event [%s]", in_state, + bta_hl_cch_state_code(in_state), + bta_hl_evt_code(cur_evt)); +#endif + + /* look up the state table for the current state */ + state_table = bta_hl_cch_st_tbl[p_cb->cch_state]; + + event &= 0x00FF; + + /* set next state */ + p_cb->cch_state = state_table[event][BTA_HL_CCH_NEXT_STATE]; + + for (i = 0; i < BTA_HL_CCH_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_HL_CCH_IGNORE) + { + (*bta_hl_cch_action[action])(app_idx, mcl_idx, p_data); + } + else + { + /* discard HDP data */ + bta_hl_discard_data(p_data->hdr.event, p_data); + break; + } + } +#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE) + if (in_state != p_cb->cch_state) + { + APPL_TRACE_DEBUG3("HL CCH State Change: [%s] -> [%s] after [%s]", + bta_hl_cch_state_code(in_state), + bta_hl_cch_state_code(p_cb->cch_state), + bta_hl_evt_code(cur_evt)); + } +#endif + +} + +/******************************************************************************* +** +** Function bta_hl_dch_sm_execute +** +** Description State machine event handling function for DCH +** +** Returns void +** +*******************************************************************************/ +void bta_hl_dch_sm_execute(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + UINT16 event, tBTA_HL_DATA *p_data) +{ + tBTA_HL_DCH_ST_TBL state_table; + UINT8 action; + int i; + tBTA_HL_MDL_CB *p_cb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + +#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE) + tBTA_HL_DCH_STATE in_state = p_cb->dch_state; + UINT16 cur_evt = event; + APPL_TRACE_DEBUG3("HDP DCH Event Handler: State 0x%02x [%s], Event [%s]", in_state, + bta_hl_dch_state_code(in_state), + bta_hl_evt_code(cur_evt)); +#endif + + /* look up the state table for the current state */ + state_table = bta_hl_dch_st_tbl[p_cb->dch_state]; + event -= BTA_HL_DCH_EVT_MIN; + + /* set next state */ + p_cb->dch_state = state_table[event][BTA_HL_DCH_NEXT_STATE]; + + for (i = 0; i < BTA_HL_DCH_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_HL_DCH_IGNORE) + { + (*bta_hl_dch_action[action])(app_idx, mcl_idx, mdl_idx, p_data); + } + else + { + /* discard mas data */ + bta_hl_discard_data(p_data->hdr.event, p_data); + break; + } + } + + +#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE) + if (in_state != p_cb->dch_state) + { + APPL_TRACE_DEBUG3("HL DCH State Change: [%s] -> [%s] after [%s]", + bta_hl_dch_state_code(in_state), + bta_hl_dch_state_code(p_cb->dch_state), + bta_hl_evt_code(cur_evt)); + } +#endif +} +/******************************************************************************* +** +** Function bta_hl_api_enable +** +** Description Process the API enable request to enable the HL subsystem +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_enable(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL_CTRL evt_data; + + /* If already enabled then reject this request */ + if (p_cb->enable) + { + APPL_TRACE_ERROR0("HL is already enabled"); + evt_data.enable_cfm.status = BTA_HL_STATUS_FAIL; + if (p_data->api_enable.p_cback) + p_data->api_enable.p_cback(BTA_HL_CTRL_ENABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data); + return; + } + + /* Done with checking. now perform the enable oepration*/ + /* initialize control block */ + memset(p_cb, 0, sizeof(tBTA_HL_CB)); + p_cb->enable = TRUE; + p_cb->p_ctrl_cback = p_data->api_enable.p_cback; + evt_data.enable_cfm.status = BTA_HL_STATUS_OK; + if (p_data->api_enable.p_cback) + p_data->api_enable.p_cback(BTA_HL_CTRL_ENABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data); + +} +/******************************************************************************* +** +** Function bta_hl_api_disable +** +** Description Process the API disable request to disable the HL subsystem +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_disable(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL_CTRL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + + if (p_cb->enable) + { + p_cb->disabling = TRUE; + bta_hl_check_disable(p_data); + } + else + { + status = BTA_HL_STATUS_FAIL; + evt_data.disable_cfm.status = status; + if (p_cb->p_ctrl_cback) p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data); + } + + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_disable status =%s", bta_hl_status_code(status)); + } +#endif + +} + +/******************************************************************************* +** +** Function bta_hl_api_register +** +** Description Process the API registration request to register an HDP applciation +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_register(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + UINT8 app_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL; + + if (p_cb->enable) + { + if (!bta_hl_is_a_duplicate_id(p_data->api_reg.app_id)) + { + if (bta_hl_find_avail_app_idx(&app_idx)) + { + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + p_acb->in_use = TRUE; + p_acb->app_id = p_data->api_reg.app_id; + p_acb->p_cback = p_data->api_reg.p_cback; + p_acb->sec_mask = p_data->api_reg.sec_mask; + p_acb->dev_type = p_data->api_reg.dev_type; + BCM_STRNCPY_S(p_acb->srv_name, sizeof(p_acb->srv_name), p_data->api_reg.srv_name, BTA_SERVICE_NAME_LEN); + BCM_STRNCPY_S(p_acb->srv_desp, sizeof(p_acb->srv_desp), p_data->api_reg.srv_desp, BTA_SERVICE_DESP_LEN); + BCM_STRNCPY_S(p_acb->provider_name, sizeof(p_acb->provider_name), p_data->api_reg.provider_name, BTA_PROVIDER_NAME_LEN); + bta_hl_cb.p_alloc_psm = L2CA_AllocatePSM; + p_acb->ctrl_psm = bta_hl_cb.p_alloc_psm(); + p_acb->data_psm = bta_hl_cb.p_alloc_psm(); + p_acb->p_mcap_cback = bta_hl_mcap_ctrl_cback; + status = bta_hl_app_registration(app_idx); + } + else + { + status = BTA_HL_STATUS_NO_RESOURCE; + } + } + else + { + status = BTA_HL_STATUS_DUPLICATE_APP_ID; + } + } + + if (status != BTA_HL_STATUS_OK) + { + if ((status != BTA_HL_STATUS_DUPLICATE_APP_ID) && + (status != BTA_HL_STATUS_NO_RESOURCE)) + { + memset(p_acb, 0, sizeof(tBTA_HL_APP_CB)); + } + } +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_register status =%s", bta_hl_status_code(status)); + } +#endif + + evt_data.reg_cfm.status = status; + evt_data.reg_cfm.app_id = p_data->api_reg.app_id; + evt_data.reg_cfm.app_handle = p_acb->app_handle; + if (p_data->api_reg.p_cback) + { + p_data->api_reg.p_cback(BTA_HL_REGISTER_CFM_EVT, (tBTA_HL *) &evt_data); + } + + if (status == BTA_HL_STATUS_OK) + { + evt_data.sdp_info_ind.app_handle = p_acb->app_handle; + evt_data.sdp_info_ind.ctrl_psm = p_acb->ctrl_psm; + evt_data.sdp_info_ind.data_psm = p_acb->data_psm; + evt_data.sdp_info_ind.data_x_spec = BTA_HL_SDP_IEEE_11073_20601; + evt_data.sdp_info_ind.mcap_sup_procs = BTA_HL_MCAP_SUP_PROC_MASK ; + + if (p_data->api_reg.p_cback) + { + p_data->api_reg.p_cback(BTA_HL_SDP_INFO_IND_EVT, (tBTA_HL *) &evt_data); + } + } +} + +/******************************************************************************* +** +** Function bta_hl_api_deregister +** +** Description Process the API de-registration request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_deregister(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + + UINT8 app_idx; + tBTA_HL_APP_CB *p_acb; + + if (bta_hl_find_app_idx_using_handle(p_data->api_dereg.app_handle, &app_idx)) + { + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + p_acb->deregistering= TRUE; + bta_hl_check_deregistration(app_idx,p_data); + } + else + { + APPL_TRACE_ERROR1("Inavlide app_handle=%d", p_data->api_dereg.app_handle); + } +} + +/******************************************************************************* +** +** Function bta_hl_api_cch_open +** +** Description Process the API CCH open request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_cch_open(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + + if (bta_hl_find_app_idx_using_handle(p_data->api_cch_open.app_handle, &app_idx)) + { + + if (!bta_hl_find_mcl_idx(app_idx, p_data->api_cch_open.bd_addr, &mcl_idx)) + { + if (bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + p_mcb->in_use = TRUE; + p_mcb->req_ctrl_psm = p_data->api_cch_open.ctrl_psm; + p_mcb->sec_mask = p_data->api_cch_open.sec_mask; + bdcpy(p_mcb->bd_addr, p_data->api_cch_open.bd_addr); + p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_OPEN; + } + else + { + status = BTA_HL_STATUS_NO_RESOURCE; + } + } + else + { + /* Only one MCL per BD_ADDR */ + status = BTA_HL_STATUS_FAIL; + } + } + else + { + status = BTA_HL_STATUS_INVALID_APP_HANDLE; + } +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_cch_open status =%s", bta_hl_status_code(status)); + } +#endif + switch (status) + { + case BTA_HL_STATUS_OK: + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_OPEN_EVT, p_data); + break; + case BTA_HL_STATUS_NO_RESOURCE: + case BTA_HL_STATUS_FAIL: + bta_hl_build_cch_open_cfm(&evt_data, p_data->api_cch_open.app_handle, + 0, + p_data->api_cch_open.bd_addr, + status); + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + p_acb->p_cback(BTA_HL_CCH_OPEN_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + default: + APPL_TRACE_ERROR1("status code=%d", status); + break; + } +} + +/******************************************************************************* +** +** Function bta_hl_api_cch_close +** +** Description Process the API CCH close request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_cch_close(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + + if (bta_hl_find_mcl_idx_using_handle(p_data->api_cch_close.mcl_handle, &app_idx, &mcl_idx)) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE; + } + else + { + status = BTA_HL_STATUS_INVALID_MCL_HANDLE; + } +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_cch_close status =%s", bta_hl_status_code(status)); + } +#endif + switch (status) + { + case BTA_HL_STATUS_OK: + bta_hl_check_cch_close(app_idx, mcl_idx, p_data, TRUE); + break; + + case BTA_HL_STATUS_FAIL: + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + bta_hl_build_cch_close_cfm(&evt_data, + p_acb->app_handle, + p_data->api_cch_close.mcl_handle, + status); + p_acb->p_cback(BTA_HL_CCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + + default: + APPL_TRACE_ERROR1("status code=%d", status); + break; + + } + +} + +/******************************************************************************* +** +** Function bta_hl_api_dch_open +** +** Description Process the API DCH open request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_dch_open(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx, mdl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + tBTA_HL_MDL_CB *p_dcb; + tBTA_HL_MDEP_CFG *p_mdep_cfg; + UINT8 mdep_cfg_idx; + + if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_open.mcl_handle, &app_idx, &mcl_idx)) + { + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + + if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) + { + if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + + if (bta_hl_find_mdep_cfg_idx(app_idx, p_data->api_dch_open.local_mdep_id, &mdep_cfg_idx)) + { + if ( mdep_cfg_idx && + (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SINK)) + { + p_data->api_dch_open.local_cfg = BTA_HL_DCH_CFG_NO_PREF; + } + + if ((status = bta_hl_chk_local_cfg(app_idx,mcl_idx,mdep_cfg_idx,p_data->api_dch_open.local_cfg)) + == BTA_HL_STATUS_OK) + { + + if (p_data->api_dch_open.local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) + { + if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx, p_data->api_dch_open.ctrl_psm)) + { + p_mdep_cfg = BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx); + p_dcb->in_use = TRUE; + p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_OPEN; + p_dcb->sec_mask = p_data->api_dch_open.sec_mask; + p_dcb->local_mdep_id = p_data->api_dch_open.local_mdep_id; + p_dcb->peer_mdep_id = p_data->api_dch_open.peer_mdep_id; + + if (p_mdep_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK) + { + p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE; + } + else + { + p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SINK; + } + + p_dcb->local_mdep_cfg_idx = mdep_cfg_idx; + p_dcb->local_cfg = p_data->api_dch_open.local_cfg; + + bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx, + &p_dcb->max_rx_apdu_size, + &p_dcb->max_tx_apdu_size); + p_dcb->mdl_id = bta_hl_allocate_mdl_id(app_idx,mcl_idx,mdl_idx); + p_dcb->mdl_cfg_idx_included = FALSE; + } + else + { + status = BTA_HL_STATUS_INVALID_CTRL_PSM; + } + + } + else + { + status = BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID; + } + } + } + else + { + status = BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID; + } + } + else + { + status = BTA_HL_STATUS_NO_RESOURCE; + } + } + else + { + status = BTA_HL_STATUS_NO_CCH; + } + } + else + { + status = BTA_HL_STATUS_INVALID_MCL_HANDLE; + } + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_dch_open status =%s", bta_hl_status_code(status)); + } +#endif + switch (status) + { + case BTA_HL_STATUS_OK: + if (p_mcb->sdp.num_recs) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT, p_data); + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_INIT_EVT, p_data); + } + break; + case BTA_HL_STATUS_INVALID_DCH_CFG: + case BTA_HL_STATUS_NO_FIRST_RELIABLE: + case BTA_HL_STATUS_NO_CCH: + case BTA_HL_STATUS_NO_RESOURCE: + case BTA_HL_STATUS_FAIL: + case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID: + case BTA_HL_STATUS_INVALID_CTRL_PSM: + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + bta_hl_build_dch_open_cfm(&evt_data, + p_acb->app_handle, + p_data->api_dch_open.mcl_handle, + BTA_HL_INVALID_MDL_HANDLE, + 0,0,0,0,0, status); + p_acb->p_cback(BTA_HL_DCH_OPEN_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + default: + APPL_TRACE_ERROR1("Status code=%d", status); + break; + + } + +} +/******************************************************************************* +** +** Function bta_hl_api_dch_close +** +** Description Process the API DCH close request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_dch_close(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx, mdl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + tBTA_HL_MDL_CB *p_dcb; + + + if (bta_hl_find_mdl_idx_using_handle(p_data->api_dch_close.mdl_handle, &app_idx, &mcl_idx, &mdl_idx )) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + if (p_dcb->dch_state != BTA_HL_DCH_OPEN_ST) + { + status = BTA_HL_STATUS_FAIL; + } + } + else + { + status = BTA_HL_STATUS_INVALID_MDL_HANDLE; + } + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_dch_close status =%s", bta_hl_status_code(status)); + } +#endif + + switch (status) + { + case BTA_HL_STATUS_OK: + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data); + break; + case BTA_HL_STATUS_FAIL: + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + bta_hl_build_dch_close_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_data->api_dch_close.mdl_handle, + status); + + p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + default: + APPL_TRACE_ERROR1("Status code=%d", status); + break; + } +} + + +/******************************************************************************* +** +** Function bta_hl_api_dch_reconnect +** +** Description Process the API DCH reconnect request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_dch_reconnect(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx, mdl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + tBTA_HL_MDL_CB *p_dcb; + UINT8 mdep_cfg_idx; + UINT8 mdl_cfg_idx; + + if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_open.mcl_handle, &app_idx, &mcl_idx)) + { + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) + { + if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + if (bta_hl_validate_reconnect_params(app_idx, mcl_idx, &(p_data->api_dch_reconnect), + &mdep_cfg_idx, &mdl_cfg_idx )) + { + if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) && + (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode != BTA_HL_DCH_MODE_RELIABLE)) + { + status = BTA_HL_STATUS_NO_FIRST_RELIABLE; + } + else + { + if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx, p_data->api_dch_open.ctrl_psm)) + { + p_dcb->in_use = TRUE; + p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_RECONNECT; + p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); + p_dcb->local_mdep_id = p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id; + p_dcb->local_mdep_cfg_idx = mdep_cfg_idx; + p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN; + p_dcb->mdl_id = p_data->api_dch_reconnect.mdl_id; + p_dcb->mdl_cfg_idx_included = TRUE; + p_dcb->mdl_cfg_idx = mdl_cfg_idx; + p_dcb->dch_mode = p_acb->mdl_cfg[mdl_cfg_idx].dch_mode; + bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx, + &p_dcb->max_rx_apdu_size, + &p_dcb->max_tx_apdu_size); + } + else + { + status = BTA_HL_STATUS_INVALID_CTRL_PSM; + } + } + } + else + { + status = BTA_HL_STATUS_INVALID_RECONNECT_CFG; + } + } + else + { + status = BTA_HL_STATUS_NO_RESOURCE; + } + } + else + { + status = BTA_HL_STATUS_NO_CCH; + } + } + else + { + status = BTA_HL_STATUS_INVALID_MCL_HANDLE; + } + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_dch_reconnect status=%s", bta_hl_status_code(status)); + } +#endif + + switch (status) + { + case BTA_HL_STATUS_OK: + if (p_mcb->sdp.num_recs) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_RECONNECT_EVT, p_data); + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_INIT_EVT, p_data); + } + break; + case BTA_HL_STATUS_INVALID_RECONNECT_CFG: + case BTA_HL_STATUS_NO_FIRST_RELIABLE: + case BTA_HL_STATUS_NO_CCH: + case BTA_HL_STATUS_NO_RESOURCE: + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + bta_hl_build_dch_open_cfm(&evt_data, + p_acb->app_handle, + p_data->api_dch_reconnect.mcl_handle, + BTA_HL_INVALID_MDL_HANDLE, + 0,p_data->api_dch_reconnect.mdl_id,0,0,0, status); + p_acb->p_cback(BTA_HL_DCH_RECONNECT_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + default: + APPL_TRACE_ERROR1("Status code=%d", status); + break; + } +} + +/******************************************************************************* +** +** Function bta_hl_api_dch_echo_test +** +** Description Process the API Echo test request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_dch_echo_test(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx, mdl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + tBTA_HL_MDL_CB *p_dcb; + tBTA_HL_ECHO_CFG *p_echo_cfg; + + + if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_echo_test.mcl_handle, &app_idx, &mcl_idx)) + { + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) + { + if (!p_mcb->echo_test ) + { + if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + + if ((p_data->api_dch_echo_test.local_cfg == BTA_HL_DCH_CFG_RELIABLE) || + (p_data->api_dch_echo_test.local_cfg == BTA_HL_DCH_CFG_STREAMING)) + { + if ((p_dcb->p_echo_tx_pkt = bta_hl_get_buf(p_data->api_dch_echo_test.pkt_size)) != NULL ) + { + if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx, p_data->api_dch_open.ctrl_psm)) + { + p_dcb->in_use = TRUE; + p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_OPEN; + p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT); + p_dcb->local_mdep_cfg_idx = BTA_HL_ECHO_TEST_MDEP_CFG_IDX; + p_dcb->local_cfg = p_data->api_dch_echo_test.local_cfg; + p_dcb->local_mdep_id = BTA_HL_ECHO_TEST_MDEP_ID; + p_dcb->peer_mdep_id = BTA_HL_ECHO_TEST_MDEP_ID; + p_dcb->mdl_id = bta_hl_allocate_mdl_id(app_idx,mcl_idx,mdl_idx); + p_dcb->mdl_cfg_idx_included = FALSE; + p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx); + p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size; + p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size; + p_mcb->echo_test = TRUE; + p_mcb->echo_mdl_idx = mdl_idx; + } + else + { + status = BTA_HL_STATUS_INVALID_CTRL_PSM; + } + } + else + { + status = BTA_HL_STATUS_NO_RESOURCE; + } + } + else + { + status = BTA_HL_STATUS_INVALID_DCH_CFG; + } + } + else + { + status = BTA_HL_STATUS_NO_RESOURCE; + } + } + else + { + status = BTA_HL_STATUS_ECHO_TEST_BUSY; + } + } + else + { + status = BTA_HL_STATUS_NO_CCH; + } + } + else + { + status = BTA_HL_STATUS_NO_MCL; + } + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_dch_echo_test status=%s", bta_hl_status_code(status)); + } +#endif + + switch (status) + { + case BTA_HL_STATUS_OK: + if (p_mcb->sdp.num_recs) + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ECHO_TEST_EVT, p_data); + } + else + { + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_INIT_EVT, p_data); + } + break; + case BTA_HL_STATUS_NO_CCH: + case BTA_HL_STATUS_ECHO_TEST_BUSY: + case BTA_HL_STATUS_NO_RESOURCE: + case BTA_HL_STATUS_INVALID_DCH_CFG: + bta_hl_build_echo_test_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + status); + p_acb->p_cback(BTA_HL_DCH_ECHO_TEST_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + + default: + APPL_TRACE_ERROR1("Status code=%s", status); + break; + } +} + + +/******************************************************************************* +** +** Function bta_hl_api_sdp_query +** +** Description Process the API SDP query request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_sdp_query(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + + + if (bta_hl_find_app_idx_using_handle(p_data->api_sdp_query.app_handle, &app_idx)) + { + if (!bta_hl_find_mcl_idx(app_idx, p_data->api_sdp_query.bd_addr, &mcl_idx)) + { + if (bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + p_mcb->in_use = TRUE; + bdcpy(p_mcb->bd_addr, p_data->api_sdp_query.bd_addr); + p_mcb->sdp_oper = BTA_HL_SDP_OP_SDP_QUERY_NEW ; + } + else + { + status = BTA_HL_STATUS_NO_RESOURCE; + } + } + else + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + if (p_mcb->sdp_oper != BTA_HL_SDP_OP_NONE) + { + status = BTA_HL_STATUS_SDP_NO_RESOURCE; + } + else + { + p_mcb->sdp_oper = BTA_HL_SDP_OP_SDP_QUERY_CURRENT; + } + } + } + else + { + status = BTA_HL_STATUS_INVALID_APP_HANDLE; + } + + if (status == BTA_HL_STATUS_OK) + { + status = bta_hl_init_sdp( p_mcb->sdp_oper, app_idx, mcl_idx, 0xFF); + if ( (status != BTA_HL_STATUS_OK) && + (p_mcb->sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW) ) + { + memset(p_mcb, 0 ,sizeof(tBTA_HL_MCL_CB)); + } + } +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_sdp_query status=%s", bta_hl_status_code(status)); + } +#endif + switch (status) + { + case BTA_HL_STATUS_NO_RESOURCE: + case BTA_HL_STATUS_FAIL: + case BTA_HL_STATUS_SDP_NO_RESOURCE: + bta_hl_build_sdp_query_cfm(&evt_data, + p_data->api_sdp_query.app_handle, + p_data->api_sdp_query.bd_addr, + NULL, + status); + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + case BTA_HL_STATUS_OK: + break; + default: + APPL_TRACE_ERROR1("Status code=%d", status); + break; + } +} + + + + +/******************************************************************************* +** +** Function bta_hl_sdp_query_results +** +** Description Process the SDP query results +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_sdp_query_results(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx = p_data->cch_sdp.app_idx; + UINT8 mcl_idx = p_data->cch_sdp.mcl_idx; + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR( app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR( app_idx, mcl_idx); + tBTA_HL_SDP *p_sdp=NULL; + tBTA_HL_SDP_OPER sdp_oper; + UINT16 event; + BOOLEAN release_sdp_buf=FALSE; + + event = p_data->hdr.event; + sdp_oper = p_mcb->sdp_oper; + + if ( event == BTA_HL_SDP_QUERY_OK_EVT) + { + if ((p_sdp = (tBTA_HL_SDP *)GKI_getbuf((UINT16)(sizeof(tBTA_HL_SDP)))) != NULL) + { + memcpy(p_sdp, &p_mcb->sdp, sizeof(tBTA_HL_SDP)); + release_sdp_buf = TRUE; + } + else + { + status = BTA_HL_STATUS_SDP_NO_RESOURCE; + } + } + else + { + status = BTA_HL_STATUS_SDP_FAIL; + } + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_sdp_query_results status=%s", bta_hl_status_code(status)); + } +#endif + + bta_hl_build_sdp_query_cfm(&evt_data,p_acb->app_handle, + p_mcb->bd_addr,p_sdp,status); + p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT,(tBTA_HL *) &evt_data ); + + if (release_sdp_buf) + { + utl_freebuf((void **) &p_sdp); + } + + if (p_data->cch_sdp.release_mcl_cb) + { + memset(p_mcb, 0 ,sizeof(tBTA_HL_MCL_CB)); + } + else + { + if (p_mcb->close_pending) + { + bta_hl_check_cch_close(app_idx,mcl_idx,p_data, TRUE); + } + + if (!p_mcb->ctrl_psm) + { + /* this is a control channel acceptor do not store the sdp records*/ + memset(&p_mcb->sdp, 0, sizeof(tBTA_HL_SDP)); + } + } +} + + +/******************************************************************************* +** +** Function bta_hl_api_delete_mdl +** +** Description Process the API DELETE MDL request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_delete_mdl(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + + if (bta_hl_find_mcl_idx_using_handle(p_data->api_delete_mdl.mcl_handle, &app_idx, &mcl_idx )) + { + if (bta_hl_is_mdl_value_valid(p_data->api_delete_mdl.mdl_id)) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + if (bta_hl_is_mdl_exsit_in_mcl(app_idx, + p_mcb->bd_addr, + p_data->api_delete_mdl.mdl_id)) + { + + + p_mcb->delete_mdl.mcl_handle = p_data->api_delete_mdl.mcl_handle; + p_mcb->delete_mdl.mdl_id = p_data->api_delete_mdl.mdl_id; + p_mcb->delete_mdl.delete_req_pending = TRUE; + + if (MCA_Delete((tMCA_CL) p_mcb->mcl_handle, + p_data->api_delete_mdl.mdl_id)!= MCA_SUCCESS) + { + status = BTA_HL_STATUS_FAIL; + memset(&p_mcb->delete_mdl, 0, sizeof(tBTA_HL_DELETE_MDL)); + } + } + else + { + status = BTA_HL_STATUS_NO_MDL_ID_FOUND; + } + } + else + { + status = BTA_HL_STATUS_INVALID_MDL_ID; + } + } + else + { + status = BTA_HL_STATUS_INVALID_MCL_HANDLE; + } + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_delete_mdl status=%s", bta_hl_status_code(status)); + } +#endif + switch (status) + { + case BTA_HL_STATUS_OK: + break; + case BTA_HL_STATUS_FAIL: + case BTA_HL_STATUS_NO_MDL_ID_FOUND: + case BTA_HL_STATUS_INVALID_MDL_ID: + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + bta_hl_build_delete_mdl_cfm(&evt_data, + p_acb->app_handle, + p_data->api_delete_mdl.mcl_handle, + p_data->api_delete_mdl.mdl_id, + status); + + p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + case BTA_HL_STATUS_INVALID_APP_HANDLE: + default: + APPL_TRACE_ERROR1("status code =%d", status); + break; + } +} + +/******************************************************************************* +** +** Function bta_hl_mca_delete_mdl_cfm +** +** Description Process the DELETE MDL confirmation event +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_mca_delete_mdl_cfm(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx; + tMCA_RSP_EVT *p_delete_cfm = &p_data->mca_evt.mca_data.delete_cfm; + tBTA_HL_MCL_CB *p_mcb; + BOOLEAN send_cfm_evt = TRUE; + tBTA_HL_APP_CB *p_acb; + + if (bta_hl_find_mcl_idx_using_handle(p_data->mca_evt.mcl_handle, &app_idx, &mcl_idx)) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + if ( p_mcb->delete_mdl.delete_req_pending) + { + if (p_delete_cfm->rsp_code == MCA_RSP_SUCCESS ) + { + + if (!bta_hl_delete_mdl_cfg(app_idx, + p_mcb->bd_addr , + p_delete_cfm->mdl_id)) + { + status = BTA_HL_STATUS_FAIL; + } + } + else + { + status = BTA_HL_STATUS_FAIL; + } + + memset(&p_mcb->delete_mdl, 0, sizeof(tBTA_HL_DELETE_MDL)); + } + else + { + send_cfm_evt = FALSE; + } + } + else + { + send_cfm_evt = FALSE; + } + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_delete_mdl status=%s", bta_hl_status_code(status)); + } +#endif + + if (send_cfm_evt) + { + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + bta_hl_build_delete_mdl_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + p_delete_cfm->mdl_id, + status); + + p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT,(tBTA_HL *) &evt_data ); + } +} + +/******************************************************************************* +** +** Function bta_hl_mca_delete_mdl_ind +** +** Description Process the DELETE MDL indication event +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_mca_delete_mdl_ind(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + tBTA_HL evt_data; + UINT8 app_idx, mcl_idx, mdl_idx; + tMCA_EVT_HDR *p_delete_ind = &p_data->mca_evt.mca_data.delete_ind; + tBTA_HL_MCL_CB *p_mcb; + tBTA_HL_MDL_CB *p_dcb; + BOOLEAN send_ind_evt = TRUE; + tBTA_HL_APP_CB *p_acb; + + if (bta_hl_find_mcl_idx_using_handle(p_data->mca_evt.mcl_handle, &app_idx, &mcl_idx) ) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + + if (bta_hl_find_mdl_idx(app_idx, mcl_idx, p_delete_ind->mdl_id, &mdl_idx )) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_DELETE; + } + if (bta_hl_delete_mdl_cfg(app_idx, + p_mcb->bd_addr , + p_delete_ind->mdl_id)) + { + send_ind_evt = TRUE; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!send_ind_evt) + { + APPL_TRACE_DEBUG1("bta_hl_mca_delete_mdl_ind is_send_ind_evt =%d", send_ind_evt); + } +#endif + + if (send_ind_evt) + { + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + evt_data.delete_mdl_ind.mcl_handle = p_mcb->mcl_handle; + evt_data.delete_mdl_ind.app_handle = p_acb->app_handle; + evt_data.delete_mdl_ind.mdl_id = p_delete_ind->mdl_id; + p_acb->p_cback(BTA_HL_DELETE_MDL_IND_EVT,(tBTA_HL *) &evt_data ); + } +} + + + +/******************************************************************************* +** +** Function bta_hl_api_dch_abort +** +** Description Process the API DCH abort request +** +** Returns void +** +*******************************************************************************/ +static void bta_hl_api_dch_abort(tBTA_HL_CB *p_cb, tBTA_HL_DATA *p_data) +{ + + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + UINT8 app_idx, mcl_idx, mdl_idx; + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + tBTA_HL_MDL_CB *p_dcb; + tBTA_HL evt_data; + + + if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_abort.mcl_handle, &app_idx, &mcl_idx )) + { + + if (!bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx )) + { + status = BTA_HL_STATUS_NO_MDL_ID_FOUND; + } + else + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + if (p_dcb->abort_oper) + { + /* abort already in progress*/ + status = BTA_HL_STATUS_FAIL; + } + else + { + p_dcb->abort_oper = BTA_HL_ABORT_LOCAL_MASK; + } + } + } + else + { + status = BTA_HL_STATUS_INVALID_MCL_HANDLE; + } + + +#if BTA_HL_DEBUG == TRUE + if (status != BTA_HL_STATUS_OK) + { + APPL_TRACE_DEBUG1("bta_hl_api_dch_abort status=%s", bta_hl_status_code(status)); + } +#endif + switch (status) + { + case BTA_HL_STATUS_OK: + + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data); + break; + case BTA_HL_STATUS_NO_MDL_ID_FOUND: + case BTA_HL_STATUS_FAIL: + + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + bta_hl_build_abort_cfm(&evt_data, + p_acb->app_handle, + p_mcb->mcl_handle, + BTA_HL_STATUS_FAIL); + p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT,(tBTA_HL *) &evt_data ); + break; + case BTA_HL_STATUS_INVALID_BD_ADDR: + case BTA_HL_STATUS_INVALID_APP_HANDLE: + default: + APPL_TRACE_ERROR1("Status code=%d", status); + break; + } +} + +/******************************************************************************* +** +** Function bta_hl_hdl_event +** +** Description HL main event handling function. +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_hl_hdl_event(BT_HDR *p_msg) +{ + UINT8 app_idx, mcl_idx, mdl_idx; + BOOLEAN success = TRUE; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("BTA HL Event Handler: Event [%s]", + bta_hl_evt_code(p_msg->event)); +#endif + + switch (p_msg->event) + { + case BTA_HL_API_ENABLE_EVT: + bta_hl_api_enable(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_DISABLE_EVT: + bta_hl_api_disable(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_REGISTER_EVT: + bta_hl_api_register(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_DEREGISTER_EVT: + bta_hl_api_deregister(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_CCH_OPEN_EVT: + bta_hl_api_cch_open(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_CCH_CLOSE_EVT: + bta_hl_api_cch_close(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_DCH_OPEN_EVT: + bta_hl_api_dch_open(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_DCH_CLOSE_EVT: + bta_hl_api_dch_close(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_DELETE_MDL_EVT: + bta_hl_api_delete_mdl(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_DCH_RECONNECT_EVT: + bta_hl_api_dch_reconnect(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + + case BTA_HL_API_DCH_ECHO_TEST_EVT: + bta_hl_api_dch_echo_test(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + + case BTA_HL_API_SDP_QUERY_EVT: + bta_hl_api_sdp_query(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + + case BTA_HL_MCA_DELETE_CFM_EVT: + bta_hl_mca_delete_mdl_cfm(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + + case BTA_HL_MCA_DELETE_IND_EVT: + bta_hl_mca_delete_mdl_ind(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + + case BTA_HL_SDP_QUERY_OK_EVT: + case BTA_HL_SDP_QUERY_FAIL_EVT: + bta_hl_sdp_query_results(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + case BTA_HL_API_DCH_ABORT_EVT: + bta_hl_api_dch_abort(&bta_hl_cb, (tBTA_HL_DATA *) p_msg); + break; + + + default: + if (p_msg->event < BTA_HL_DCH_EVT_MIN) + { + if (bta_hl_find_cch_cb_indexes((tBTA_HL_DATA *) p_msg, &app_idx, &mcl_idx)) + { + bta_hl_cch_sm_execute( app_idx, + mcl_idx, + p_msg->event, (tBTA_HL_DATA *) p_msg); + } + else + { +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_ERROR1("unable to find control block indexes for CCH: [event=%s]", + bta_hl_evt_code(p_msg->event)); +#else + APPL_TRACE_ERROR1("unable to find control block indexes for CCH: [event=%d]", p_msg->event); +#endif + success = FALSE; + } + } + else + { + if (bta_hl_find_dch_cb_indexes((tBTA_HL_DATA *) p_msg, &app_idx, &mcl_idx, &mdl_idx)) + { + bta_hl_dch_sm_execute( app_idx, + mcl_idx, + mdl_idx, + p_msg->event, (tBTA_HL_DATA *) p_msg); + } + else + { + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_ERROR1("unable to find control block indexes for DCH : [event=%s]", + bta_hl_evt_code(p_msg->event)); +#else + APPL_TRACE_ERROR1("unable to find control block indexes for DCH: [event=%d]", p_msg->event); +#endif + success = FALSE; + } + } + + break; + } + + return(success); +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if (BTA_HL_DEBUG == TRUE) && (BT_USE_TRACES == TRUE) + +/******************************************************************************* +** +** Function bta_hl_cch_state_code +** +** Description Map CCH state code to the corresponding state string +** +** Returns string pointer for the associated state name +** +*******************************************************************************/ +static char *bta_hl_cch_state_code(tBTA_HL_CCH_STATE state_code) +{ + switch (state_code) + { + case BTA_HL_CCH_IDLE_ST: + return "BTA_HL_CCH_IDLE_ST"; + case BTA_HL_CCH_OPENING_ST: + return "BTA_HL_CCH_OPENING_ST"; + case BTA_HL_CCH_OPEN_ST: + return "BTA_HL_CCH_OPEN_ST"; + case BTA_HL_CCH_CLOSING_ST: + return "BTA_HL_CCH_CLOSING_ST"; + default: + return "Unknown CCH state code"; + } +} + +/******************************************************************************* +** +** Function bta_hl_dch_state_code +** +** Description Map DCH state code to the corresponding state string +** +** Returns string pointer for the associated state name +** +*******************************************************************************/ +static char *bta_hl_dch_state_code(tBTA_HL_DCH_STATE state_code) +{ + switch (state_code) + { + case BTA_HL_DCH_IDLE_ST: + return "BTA_HL_DCH_IDLE_ST"; + case BTA_HL_DCH_OPENING_ST: + return "BTA_HL_DCH_OPENING_ST"; + case BTA_HL_DCH_OPEN_ST: + return "BTA_HL_DCH_OPEN_ST"; + case BTA_HL_DCH_CLOSING_ST: + return "BTA_HL_DCH_CLOSING_ST"; + default: + return "Unknown DCH state code"; + } +} +#endif /* Debug Functions */ +#endif /* HL_INCLUDED */ diff --git a/bta/hl/bta_hl_sdp.c b/bta/hl/bta_hl_sdp.c new file mode 100644 index 0000000..15620e8 --- /dev/null +++ b/bta/hl/bta_hl_sdp.c @@ -0,0 +1,436 @@ +/****************************************************************************** + * + * Copyright (C) 1998-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 <string.h> + +#include "bt_target.h" +#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE) + +#include "sdp_api.h" +#include "bta_hl_int.h" + + +/******************************************************************************* +** +** Function bta_hl_fill_sup_feature_list +** +** Description Fill the supported features from teh SDP record +** +** Returns TRUE if found, FALSE if not +** If found, the passed protocol list element is filled in. +** +*******************************************************************************/ +BOOLEAN bta_hl_fill_sup_feature_list( const tSDP_DISC_ATTR *p_attr, + tBTA_HL_SUP_FEATURE_LIST_ELEM *p_list) +{ + tSDP_DISC_ATTR *p_sattr; + UINT8 seq_len, item_cnt; + UINT8 list_cnt=0; + BOOLEAN status=TRUE; + + for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) + { + /* mdep sequence */ + if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) + { + return(FALSE); + } + seq_len =SDP_DISC_ATTR_LEN(p_attr->attr_len_type); + item_cnt=0; + + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr && (item_cnt < 4) ; p_sattr = p_sattr->p_next_attr) + { + /* for each mdep list */ + + p_list->list_elem[list_cnt].p_mdep_desp = NULL; + switch (item_cnt) + { + case 0: + p_list->list_elem[list_cnt].mdep_id = p_sattr->attr_value.v.u8; + break; + case 1: + p_list->list_elem[list_cnt].data_type = p_sattr->attr_value.v.u16; + break; + case 2: + p_list->list_elem[list_cnt].mdep_role = (tBTA_HL_MDEP_ROLE) p_sattr->attr_value.v.u8; + break; + case 3: + p_list->list_elem[list_cnt].p_mdep_desp = (char *) p_sattr->attr_value.v.array; + break; + } + + item_cnt++; + } + list_cnt++; + } + p_list->num_elems = list_cnt; + return(status); +} + +/******************************************************************************* +** +** Function bta_hl_compose_supported_feature_list +** +** Description This function is called to compose a data sequence from +** the supported feature element list struct pointer +** +** Returns the length of the data sequence +** +*******************************************************************************/ +int bta_hl_compose_supported_feature_list( UINT8 *p, UINT16 num_elem, + const tBTA_HL_SUP_FEATURE_ELEM *p_elem_list) +{ + UINT16 xx, str_len, seq_len; + UINT8 *p_head = p; + + for (xx = 0; xx < num_elem; xx++, p_elem_list++) + { + UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + seq_len=7; + str_len=0; + if (p_elem_list->p_mdep_desp) + { + str_len = strlen(p_elem_list->p_mdep_desp)+1; + seq_len += str_len+2; /* todo add a # symbol for 2 */ + } + + *p++ = (UINT8) seq_len; + + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE); + UINT8_TO_BE_STREAM (p, p_elem_list->mdep_id); + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); + UINT16_TO_BE_STREAM (p, p_elem_list->data_type); + UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE); + UINT8_TO_BE_STREAM (p, p_elem_list->mdep_role); + + if (str_len) + { + UINT8_TO_BE_STREAM (p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); + UINT8_TO_BE_STREAM (p, str_len); + ARRAY_TO_BE_STREAM(p, p_elem_list->p_mdep_desp, str_len); + } + } + + return(p - p_head); +} + +/******************************************************************************* +** +** Function bta_hl_add_sup_feature_list +** +** Description This function is called to add a protocol descriptor list to +** a record. This would be through the SDP database maintenance API. +** If the protocol list already exists in the record, it is replaced +** with the new list. +** +** Returns TRUE if added OK, else FALSE +** +*******************************************************************************/ +BOOLEAN bta_hl_add_sup_feature_list (UINT32 handle, UINT16 num_elem, + const tBTA_HL_SUP_FEATURE_ELEM *p_elem_list) +{ + UINT8 *p_buf; + int offset; + BOOLEAN result = FALSE; + + if ((p_buf = (UINT8 *)GKI_getbuf(BTA_HL_SUP_FEATURE_SDP_BUF_SIZE)) != NULL) + { + offset = bta_hl_compose_supported_feature_list(p_buf, num_elem, p_elem_list); + result = SDP_AddAttribute (handle, ATTR_ID_HDP_SUP_FEAT_LIST, + DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, p_buf); + GKI_freebuf(p_buf); + } + return result; +} +/***************************************************************************** +** +** Function: bta_hl_sdp_register +** +** Purpose: Register an HDP application with SDP +** +** Parameters: p_cb - Pointer to MA instance control block +** p_service_name - MA server name +** inst_id - MAS instance ID +** msg_type - Supported message type(s) +** +** +** Returns: void +** +*****************************************************************************/ +tBTA_HL_STATUS bta_hl_sdp_register (UINT8 app_idx) +{ + UINT16 svc_class_id_list[BTA_HL_NUM_SVC_ELEMS]; + tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS]; + tSDP_PROTO_LIST_ELEM add_proto_list; + tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list; + UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP}; + UINT8 i,j, cnt,mdep_id, mdep_role; + UINT8 data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601; + UINT8 mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK; + UINT16 profile_uuid = UUID_SERVCLASS_HDP_PROFILE; + UINT16 version = BTA_HL_VERSION_01_00; + UINT8 num_services=1; + tBTA_HL_APP_CB *p_cb = BTA_HL_GET_APP_CB_PTR(app_idx); + BOOLEAN result = TRUE; + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_sdp_register app_idx=%d",app_idx); +#endif + + if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) && + (!p_cb->sup_feature.advertize_source_sdp)) + { + return BTA_HL_STATUS_OK; + } + + if ((p_cb->sdp_handle = SDP_CreateRecord()) == 0) + { + return BTA_HL_STATUS_SDP_NO_RESOURCE; + } + + num_services=1; + svc_class_id_list[0]= UUID_SERVCLASS_HDP_SOURCE; + if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) + { + svc_class_id_list[0]= UUID_SERVCLASS_HDP_SINK; + } + else + { + if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) + { + /* dual role */ + num_services=2; + svc_class_id_list[1]= UUID_SERVCLASS_HDP_SINK; + } + } + result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services, svc_class_id_list); + + if (result) + { + /* add the protocol element sequence */ + proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + proto_elem_list[0].num_params = 1; + proto_elem_list[0].params[0] = p_cb->ctrl_psm; + proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL; + proto_elem_list[1].num_params = 1; + proto_elem_list[1].params[0] = version; + result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS, proto_elem_list); + + result &= SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version); + } + + if (result) + { + add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS; + add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + add_proto_list.list_elem[0].num_params = 1; + add_proto_list.list_elem[0].params[0] = p_cb->data_psm; + add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA; + add_proto_list.list_elem[1].num_params = 0; + result &= SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS, + (tSDP_PROTO_LIST_ELEM *)&add_proto_list); + } + + if (result) + { + if (p_cb->srv_name[0] ) + { + result &= SDP_AddAttribute(p_cb->sdp_handle, + (UINT16)ATTR_ID_SERVICE_NAME, + (UINT8)TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_cb->srv_name) + 1), + (UINT8 *)p_cb->srv_name); + } /* end of setting optional service name */ + } + + if (result) + { + if (p_cb->srv_desp[0] ) + { + result &= SDP_AddAttribute(p_cb->sdp_handle, + (UINT16)ATTR_ID_SERVICE_DESCRIPTION, + (UINT8)TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_cb->srv_desp) + 1), + (UINT8 *)p_cb->srv_desp); + + } /* end of setting optional service description */ + + } + + if (result) + { + if (p_cb->provider_name[0] ) + { + result &= SDP_AddAttribute(p_cb->sdp_handle, + (UINT16)ATTR_ID_PROVIDER_NAME, + (UINT8)TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_cb->provider_name) + 1), + (UINT8 *)p_cb->provider_name); + } /* end of setting optional provider name */ + } + + /* add supported feture list */ + + if (result) + { + cnt=0; + for (i=1; i<= p_cb->sup_feature.num_of_mdeps; i++) + { + mdep_id = (UINT8)p_cb->sup_feature.mdep[i].mdep_id; + mdep_role = (UINT8)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role; + + for (j=0; j<p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types; j++) + { + sup_feature_list.list_elem[cnt].mdep_id = mdep_id; + sup_feature_list.list_elem[cnt].mdep_role = mdep_role; + sup_feature_list.list_elem[cnt].data_type = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type; + if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') + { + sup_feature_list.list_elem[cnt].p_mdep_desp = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp; + } + else + { + sup_feature_list.list_elem[cnt].p_mdep_desp = NULL; + } + + cnt++; + if (cnt>BTA_HL_NUM_SUP_FEATURE_ELEMS) + { + result = FALSE; + break; + } + } + } + sup_feature_list.num_elems = cnt; + result &= bta_hl_add_sup_feature_list (p_cb->sdp_handle, + sup_feature_list.num_elems, + sup_feature_list.list_elem); + } + if (result) + { + result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC, UINT_DESC_TYPE, + (UINT32)1, (UINT8*)&data_exchange_spec); + } + + if (result) + { + + result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC, UINT_DESC_TYPE, + (UINT32)1, (UINT8*)&mcap_sup_proc); + } + + if (result) + { + result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); + } + + if (result) + { + for(i=0; i < num_services; i++) + { + bta_sys_add_uuid(svc_class_id_list[i]); + APPL_TRACE_DEBUG2("dbg bta_sys_add_uuid i=%d uuid=0x%x", i, svc_class_id_list[i]); //todo + } + } + else + { + if (p_cb->sdp_handle) + { + SDP_DeleteRecord(p_cb->sdp_handle); + p_cb->sdp_handle = 0; + } + status = BTA_HL_STATUS_SDP_FAIL; + } +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_sdp_register status=%s", bta_hl_status_code(status)); +#endif + return status; +} + +/******************************************************************************* +** +** Function bta_hl_find_sink_or_src_srv_class_in_db +** +** Description This function queries an SDP database for either a HDP Sink or +** Source service class ID. +** If the p_start_rec pointer is NULL, it looks from the beginning +** of the database, else it continues from the next record after +** p_start_rec. +** +** Returns Pointer to record containing service class, or NULL +** +*******************************************************************************/ +tSDP_DISC_REC *bta_hl_find_sink_or_src_srv_class_in_db (const tSDP_DISCOVERY_DB *p_db, + const tSDP_DISC_REC *p_start_rec) +{ +#if SDP_CLIENT_ENABLED == TRUE + tSDP_DISC_REC *p_rec; + tSDP_DISC_ATTR *p_attr, *p_sattr; + + /* Must have a valid database */ + if (p_db == NULL) + return(NULL); + + + if (!p_start_rec) + { + + p_rec = p_db->p_first_rec; + } + else + { + p_rec = p_start_rec->p_next_rec; + } + + while (p_rec) + { + p_attr = p_rec->p_first_attr; + while (p_attr) + { + if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) + && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) + { + for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) + { + if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) + && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) + && ( (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK) || + (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE)) ) + { + return(p_rec); + } + } + break; + } + + p_attr = p_attr->p_next_attr; + } + + p_rec = p_rec->p_next_rec; + } +#endif + /* If here, no matching UUID found */ + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_find_sink_or_src_srv_class_in_db failed"); +#endif + + return(NULL); +} +#endif /* HL_INCLUDED */ diff --git a/bta/hl/bta_hl_utils.c b/bta/hl/bta_hl_utils.c new file mode 100644 index 0000000..7f94a9c --- /dev/null +++ b/bta/hl/bta_hl_utils.c @@ -0,0 +1,3337 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file implements utility functions for the HeaLth device profile + * (HL). + * + ******************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#include "bt_target.h" +#if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE) + + +#include "gki.h" +#include "utl.h" +#include "bd.h" +#include "bta_fs_api.h" +#include "bta_hl_int.h" +#include "bta_hl_co.h" +#include "mca_defs.h" +#include "mca_api.h" + + +/******************************************************************************* +** +** Function bta_hl_set_ctrl_psm_for_dch +** +** Description This function set the control PSM for the DCH setup +** +** Returns BOOLEAN - TRUE - control PSM setting is successful +*******************************************************************************/ +BOOLEAN bta_hl_set_ctrl_psm_for_dch(UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx, UINT16 ctrl_psm) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + BOOLEAN success = TRUE, update_ctrl_psm = FALSE; + + if (p_mcb->sdp.num_recs) + { + if (p_mcb->ctrl_psm != ctrl_psm) + { + /* can not use a different ctrl PSM than the current one*/ + success = FALSE; + } + } + else + { + /* No SDP info control i.e. channel was opened by the peer */ + update_ctrl_psm = TRUE; + } + + if (success && update_ctrl_psm) + { + p_mcb->ctrl_psm = ctrl_psm; + } + + +#if BTA_HL_DEBUG == TRUE + if (!success) + { + APPL_TRACE_DEBUG4("bta_hl_set_ctrl_psm_for_dch num_recs=%d success=%d update_ctrl_psm=%d ctrl_psm=0x%x ", + p_mcb->sdp.num_recs, success, update_ctrl_psm, ctrl_psm ); + } +#endif + + return success; +} + + +/******************************************************************************* +** +** Function bta_hl_find_sdp_idx_using_ctrl_psm +** +** Description +** +** Returns UINT8 pool_id +** +*******************************************************************************/ +BOOLEAN bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP *p_sdp, + UINT16 ctrl_psm, + UINT8 *p_sdp_idx) +{ + BOOLEAN found=FALSE; + tBTA_HL_SDP_REC *p_rec; + UINT8 i; + + if (ctrl_psm != 0) + { + for (i=0; i<p_sdp->num_recs; i++) + { + p_rec = &p_sdp->sdp_rec[i]; + if (p_rec->ctrl_psm == ctrl_psm) + { + *p_sdp_idx = i; + found = TRUE; + break; + } + } + } + else + { + *p_sdp_idx = 0; + found = TRUE; + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG3("bta_hl_find_sdp_idx_using_ctrl_psm found=%d sdp_idx=%d ctrl_psm=0x%x ", + found, *p_sdp_idx, ctrl_psm ); + } +#endif + return found; +} + +/******************************************************************************* +** +** Function bta_hl_set_user_tx_pool_id +** +** Description This function sets the user tx pool id +** +** Returns UINT8 pool_id +** +*******************************************************************************/ + +UINT8 bta_hl_set_user_tx_pool_id(UINT16 max_tx_size) +{ + UINT8 pool_id; + + if (max_tx_size > GKI_get_pool_bufsize (OBX_FCR_TX_POOL_ID)) + { + pool_id = BTA_HL_LRG_DATA_POOL_ID; + } + else + { + pool_id = L2CAP_DEFAULT_ERM_POOL_ID; + } + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG3("bta_hl_set_user_rx_pool_id pool_id=%d max_tx_size=%d default_ertm_pool_size=%d", + pool_id, max_tx_size, GKI_get_pool_bufsize (OBX_FCR_TX_POOL_ID)); +#endif + + return pool_id; +} + +/******************************************************************************* +** +** Function bta_hl_set_user_rx_pool_id +** +** Description This function sets the user trx pool id +** +** Returns UINT8 pool_id +** +*******************************************************************************/ + +UINT8 bta_hl_set_user_rx_pool_id(UINT16 mtu) +{ + UINT8 pool_id; + + if (mtu > GKI_get_pool_bufsize (OBX_FCR_RX_POOL_ID)) + { + pool_id = BTA_HL_LRG_DATA_POOL_ID; + } + else + { + pool_id = L2CAP_DEFAULT_ERM_POOL_ID; + } + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG3("bta_hl_set_user_rx_pool_id pool_id=%d mtu=%d default_ertm_pool_size=%d", + pool_id, mtu, GKI_get_pool_bufsize (OBX_FCR_RX_POOL_ID)); +#endif + + return pool_id; +} + + + +/******************************************************************************* +** +** Function bta_hl_set_tx_win_size +** +** Description This function sets the tx window size +** +** Returns UINT8 tx_win_size +** +*******************************************************************************/ +UINT8 bta_hl_set_tx_win_size(UINT16 mtu, UINT16 mps) +{ + UINT8 tx_win_size; + + if (mtu <= mps) + { + tx_win_size =1; + } + else + { + if (mps > 0) + { + tx_win_size = (mtu/mps)+1; + } + else + { + APPL_TRACE_ERROR0("The MPS is zero"); + tx_win_size = 10; + } + } + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG3("bta_hl_set_tx_win_size win_size=%d mtu=%d mps=%d", + tx_win_size, mtu, mps); +#endif + return tx_win_size; +} + +/******************************************************************************* +** +** Function bta_hl_set_mps +** +** Description This function sets the MPS +** +** Returns UINT16 MPS +** +*******************************************************************************/ +UINT16 bta_hl_set_mps(UINT16 mtu) +{ + UINT16 mps; + if (mtu > BTA_HL_L2C_MPS) + { + mps = BTA_HL_L2C_MPS; + } + else + { + mps = mtu; + } +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG2("bta_hl_set_mps mps=%d mtu=%d", + mps, mtu); +#endif + return mps; +} + + +/******************************************************************************* +** +** Function bta_hl_clean_mdl_cb +** +** Description This function clean up the specified MDL control block +** +** Returns void +** +*******************************************************************************/ +void bta_hl_clean_mdl_cb(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx) +{ + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG3("bta_hl_clean_mdl_cb app_idx=%d mcl_idx=%d mdl_idx=%d", + app_idx, mcl_idx, mdl_idx); +#endif + utl_freebuf((void **) &p_dcb->p_tx_pkt); + utl_freebuf((void **) &p_dcb->p_rx_pkt); + utl_freebuf((void **) &p_dcb->p_echo_tx_pkt); + utl_freebuf((void **) &p_dcb->p_echo_rx_pkt); + + memset((void *)p_dcb, 0 , sizeof(tBTA_HL_MDL_CB)); +} + + +/******************************************************************************* +** +** Function bta_hl_get_buf +** +** Description This function allocate a buffer based on the specified data size +** +** Returns BT_HDR *. +** +*******************************************************************************/ +BT_HDR * bta_hl_get_buf(UINT16 data_size) +{ + BT_HDR *p_new; + UINT16 size = data_size + L2CAP_MIN_OFFSET + BT_HDR_SIZE; + + if (size < GKI_MAX_BUF_SIZE) + { + p_new = (BT_HDR *)GKI_getbuf(size); + } + else + { + p_new = (BT_HDR *) GKI_getpoolbuf(BTA_HL_LRG_DATA_POOL_ID); + } + + if (p_new) + { + p_new->len = data_size; + p_new->offset = L2CAP_MIN_OFFSET; + } + + return p_new; +} + +/******************************************************************************* +** +** Function bta_hl_find_service_in_db +** +** Description This function check the specified service class(es) can be find in +** the received SDP database +** +** Returns BOOLEAN TRUE - found +** FALSE - not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_service_in_db( UINT8 app_idx, UINT8 mcl_idx, + UINT16 service_uuid, + tSDP_DISC_REC **pp_rec ) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + BOOLEAN found = TRUE; + + switch (service_uuid) + { + case UUID_SERVCLASS_HDP_SINK: + case UUID_SERVCLASS_HDP_SOURCE: + if ((*pp_rec = SDP_FindServiceInDb(p_mcb->p_db, service_uuid, + *pp_rec)) == NULL) + { + found = FALSE; + } + break; + default: + if (((*pp_rec = bta_hl_find_sink_or_src_srv_class_in_db(p_mcb->p_db, + *pp_rec)) == NULL)) + { + found = FALSE; + } + break; + } + return found; +} + +/******************************************************************************* +** +** Function bta_hl_get_service_uuids +** +** +** Description This function finds the service class(es) for both CCH and DCH oeprations +** +** Returns UINT16 - service_id +** if service_uuid = 0xFFFF then it means service uuid +** can be either Sink or Source +** +*******************************************************************************/ +UINT16 bta_hl_get_service_uuids(UINT8 sdp_oper, UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdl_idx ) +{ + tBTA_HL_MDL_CB *p_dcb; + UINT16 service_uuid = 0xFFFF; /* both Sink and Source */ + + switch (sdp_oper) + { + + case BTA_HL_SDP_OP_DCH_OPEN_INIT: + case BTA_HL_SDP_OP_DCH_RECONNECT_INIT: + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) + { + if (p_dcb->peer_mdep_role == BTA_HL_MDEP_ROLE_SINK) + { + service_uuid = UUID_SERVCLASS_HDP_SINK; + } + else + { + service_uuid = UUID_SERVCLASS_HDP_SOURCE; + } + } + break; + case BTA_HL_SDP_OP_CCH_INIT: + default: + /* use default that is both Sink and Source */ + break; + } +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_get_service_uuids service_uuid=0x%x",service_uuid ); +#endif + return service_uuid; +} + +/******************************************************************************* +** +** Function bta_hl_find_echo_cfg_rsp +** +** +** Description This function finds the configuration response for the echo test +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_echo_cfg_rsp(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdep_idx, UINT8 cfg, + UINT8 *p_cfg_rsp) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MDEP *p_mdep= &p_acb->sup_feature.mdep[mdep_idx]; + BOOLEAN status =TRUE; + + if (p_mdep->mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) + { + if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING)) + { + *p_cfg_rsp = cfg; + } + else if (cfg == BTA_HL_DCH_CFG_NO_PREF ) + { + *p_cfg_rsp = BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG; + } + else + { + status = FALSE; + APPL_TRACE_ERROR0("Inavlid echo cfg value"); + } + return status; + } + +#if BTA_HL_DEBUG == TRUE + if (!status) + { + APPL_TRACE_DEBUG4("bta_hl_find_echo_cfg_rsp status=failed app_idx=%d mcl_idx=%d mdep_idx=%d cfg=%d", + app_idx, mcl_idx, mdep_idx, cfg); + } +#endif + + return status; +} + +/******************************************************************************* +** +** Function bta_hl_validate_dch_cfg +** +** Description This function validate the DCH configuration +** +** Returns BOOLEAN - TRUE cfg is valid +** FALSE not valid +** +*******************************************************************************/ +BOOLEAN bta_hl_validate_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + UINT8 cfg) +{ + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + BOOLEAN is_valid =FALSE; + + + if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) && + (cfg != BTA_HL_DCH_CFG_RELIABLE)) + { + APPL_TRACE_ERROR0("the first DCH should be a reliable channel"); + return is_valid; + } + + switch (p_dcb->local_cfg) + { + case BTA_HL_DCH_CFG_NO_PREF: + + if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING)) + { + is_valid = TRUE; + } + break; + case BTA_HL_DCH_CFG_RELIABLE: + case BTA_HL_DCH_CFG_STREAMING: + if (p_dcb->local_cfg == cfg ) + { + is_valid = TRUE; + } + break; + default: + break; + } + +#if BTA_HL_DEBUG == TRUE + if (!is_valid) + { + APPL_TRACE_DEBUG2("bta_hl_validate_dch_open_cfg is_valid=%d, cfg=%d", is_valid, cfg ); + } +#endif + return is_valid; +} + +/******************************************************************************* +** +** Function bta_hl_find_cch_cb_indexes +** +** Description This function finds the indexes needed for the CCH state machine +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_cch_cb_indexes(tBTA_HL_DATA *p_msg, + UINT8 *p_app_idx, + UINT8 *p_mcl_idx) +{ + BOOLEAN found = FALSE; + tBTA_HL_MCL_CB *p_mcb; + UINT8 app_idx, mcl_idx; + + switch (p_msg->hdr.event) + { + case BTA_HL_CCH_SDP_OK_EVT: + case BTA_HL_CCH_SDP_FAIL_EVT: + app_idx = p_msg->cch_sdp.app_idx; + mcl_idx = p_msg->cch_sdp.mcl_idx; + found = TRUE; + break; + + case BTA_HL_MCA_CONNECT_IND_EVT: + + if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle, &app_idx)) + { + if (bta_hl_find_mcl_idx(app_idx, p_msg->mca_evt.mca_data.connect_ind.bd_addr, &mcl_idx)) + { + /* local initiated */ + found = TRUE; + } + else if (!bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx)&& + bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) + { + /* remote initiated */ + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + p_mcb->in_use = TRUE; + p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_OPEN; + found = TRUE; + } + } + break; + + case BTA_HL_MCA_DISCONNECT_IND_EVT: + + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx)) + { + found = TRUE; + } + else if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle, &app_idx) && + bta_hl_find_mcl_idx(app_idx, p_msg->mca_evt.mca_data.disconnect_ind.bd_addr, &mcl_idx)) + { + found = TRUE; + } + + if (found) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) + { + p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_CLOSE; + } + } + break; + + case BTA_HL_MCA_RSP_TOUT_IND_EVT: + + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx)) + { + found = TRUE; + } + + if (found) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + if (p_mcb->cch_oper != BTA_HL_CCH_OP_REMOTE_CLOSE) + { + p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE; + } + } + break; + default: + break; + } + + + if (found) + { + *p_app_idx = app_idx; + *p_mcl_idx = mcl_idx; + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG4("bta_hl_find_cch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d", + bta_hl_evt_code(p_msg->hdr.event), found, app_idx, mcl_idx); + } +#endif + + return found; +} + +/******************************************************************************* +** +** Function bta_hl_find_dch_cb_indexes +** +** Description This function finds the indexes needed for the DCH state machine +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_dch_cb_indexes(tBTA_HL_DATA *p_msg, + UINT8 *p_app_idx, + UINT8 *p_mcl_idx, + UINT8 *p_mdl_idx) +{ + BOOLEAN found = FALSE; + tBTA_HL_MCL_CB *p_mcb; + UINT8 app_idx, mcl_idx, mdl_idx; + + switch (p_msg->hdr.event) + { + case BTA_HL_MCA_CREATE_CFM_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) && + bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.create_cfm.mdl_id, &mdl_idx)) + { + found = TRUE; + } + break; + + case BTA_HL_MCA_CREATE_IND_EVT: + case BTA_HL_MCA_RECONNECT_IND_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) && + bta_hl_find_avail_mdl_idx( app_idx, mcl_idx, &mdl_idx)) + { + found = TRUE; + } + break; + + case BTA_HL_MCA_OPEN_CFM_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) && + bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.open_cfm.mdl_id, &mdl_idx)) + { + found = TRUE; + } + break; + + case BTA_HL_MCA_OPEN_IND_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) && + bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.open_ind.mdl_id, &mdl_idx)) + { + found = TRUE; + } + break; + + case BTA_HL_MCA_CLOSE_CFM_EVT: + + if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_cfm.mdl, + &app_idx, &mcl_idx, &mdl_idx)) + { + found = TRUE; + } + break; + case BTA_HL_MCA_CLOSE_IND_EVT: + + if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_ind.mdl, + &app_idx, &mcl_idx, &mdl_idx)) + { + found = TRUE; + } + break; + case BTA_HL_API_SEND_DATA_EVT: + + if (bta_hl_find_mdl_idx_using_handle(p_msg->api_send_data.mdl_handle, + &app_idx, &mcl_idx, &mdl_idx )) + { + found = TRUE; + } + + break; + + case BTA_HL_MCA_CONG_CHG_EVT: + + if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.cong_chg.mdl, + &app_idx, &mcl_idx, &mdl_idx )) + { + found = TRUE; + } + + break; + + case BTA_HL_MCA_RCV_DATA_EVT: + app_idx = p_msg->mca_rcv_data_evt.app_idx; + mcl_idx = p_msg->mca_rcv_data_evt.mcl_idx; + mdl_idx = p_msg->mca_rcv_data_evt.mdl_idx; + found = TRUE; + break; + case BTA_HL_DCH_RECONNECT_EVT: + case BTA_HL_DCH_OPEN_EVT: + case BTA_HL_DCH_ECHO_TEST_EVT: + case BTA_HL_DCH_SDP_FAIL_EVT: + app_idx = p_msg->dch_sdp.app_idx; + mcl_idx = p_msg->dch_sdp.mcl_idx; + mdl_idx = p_msg->dch_sdp.mdl_idx; + found = TRUE; + break; + case BTA_HL_MCA_RECONNECT_CFM_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) && + bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.reconnect_cfm.mdl_id, &mdl_idx)) + { + found = TRUE; + } + break; + + + case BTA_HL_API_DCH_CREATE_RSP_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->api_dch_create_rsp.mcl_handle, &app_idx, &mcl_idx)&& + bta_hl_find_mdl_idx( app_idx, mcl_idx,p_msg->api_dch_create_rsp.mdl_id, &mdl_idx)) + { + found = TRUE; + } + break; + case BTA_HL_MCA_ABORT_IND_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) && + bta_hl_find_mdl_idx( app_idx, mcl_idx,p_msg->mca_evt.mca_data.abort_ind.mdl_id, &mdl_idx)) + { + found = TRUE; + } + break; + case BTA_HL_MCA_ABORT_CFM_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx, &mcl_idx) && + bta_hl_find_mdl_idx( app_idx, mcl_idx, p_msg->mca_evt.mca_data.abort_cfm.mdl_id, &mdl_idx)) + { + found = TRUE; + } + break; + case BTA_HL_CI_GET_TX_DATA_EVT: + case BTA_HL_CI_PUT_RX_DATA_EVT: + if (bta_hl_find_mdl_idx_using_handle(p_msg->ci_get_put_data.mdl_handle, &app_idx, &mcl_idx, &mdl_idx)) + { + found = TRUE; + } + break; + case BTA_HL_CI_GET_ECHO_DATA_EVT: + case BTA_HL_CI_PUT_ECHO_DATA_EVT: + if (bta_hl_find_mcl_idx_using_handle(p_msg->ci_get_put_echo_data.mcl_handle, &app_idx, &mcl_idx)) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + mdl_idx = p_mcb->echo_mdl_idx; + found = TRUE; + } + break; + + default: + break; + + } + + if (found) + { + *p_app_idx = app_idx; + *p_mcl_idx = mcl_idx; + *p_mdl_idx = mdl_idx; + } +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG5("bta_hl_find_dch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d", + bta_hl_evt_code(p_msg->hdr.event), found, *p_app_idx, *p_mcl_idx, *p_mdl_idx ); + } +#endif + + return found; +} + +/******************************************************************************* +** +** Function bta_hl_allocate_mdl_id +** +** Description This function allocates a MDL ID +** +** Returns UINT16 - MDL ID +** +*******************************************************************************/ +UINT16 bta_hl_allocate_mdl_id(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx ) +{ + UINT16 mdl_id=0; + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + BOOLEAN duplicate_id; + UINT8 i, mdl_cfg_idx; + + do + { + duplicate_id = FALSE; + mdl_id = ((mdl_id+1) & 0xFEFF); + /* check mdl_ids that are used for the current conenctions */ + for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++) + { + if (p_mcb->mdl[i].in_use && + (i != mdl_idx) && + (p_mcb->mdl[i].mdl_id == mdl_id) ) + { + duplicate_id = TRUE; + break; + } + } + + if (duplicate_id) + { + /* start from the beginning to get another MDL value*/ + continue; + } + else + { + /* check mdl_ids that are stored in the persistent memory */ + if (bta_hl_find_mdl_cfg_idx(app_idx,mcl_idx, mdl_id, &mdl_cfg_idx)) + { + duplicate_id = TRUE; + } + else + { + /* found a new MDL value */ + break; + } + } + + }while (TRUE); + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_allocate_mdl OK mdl_id=%d", mdl_id); +#endif + return mdl_id; +} +/******************************************************************************* +** +** Function bta_hl_find_mdl_idx +** +** Description This function finds the MDL index based on mdl_id +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, UINT16 mdl_id, + UINT8 *p_mdl_idx) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++) + { + if (p_mcb->mdl[i].in_use && + (mdl_id !=0) && + (p_mcb->mdl[i].mdl_id== mdl_id)) + { + found = TRUE; + *p_mdl_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG3("bta_hl_find_mdl_idx found=%d mdl_id=%d mdl_idx=%d ", + found, mdl_id, i); + } +#endif + + return found; +} + +/******************************************************************************* +** +** Function bta_hl_find_an_active_mdl_idx +** +** Description This function finds an active MDL +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_an_active_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, + UINT8 *p_mdl_idx) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++) + { + if (p_mcb->mdl[i].in_use && + (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPEN_ST)) + { + found = TRUE; + *p_mdl_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (found) + { + APPL_TRACE_DEBUG4("bta_hl_find_an_opened_mdl_idx found=%d app_idx=%d mcl_idx=%d mdl_idx=%d", + found, app_idx, mcl_idx, i); + } +#endif + + return found; +} + +/******************************************************************************* +** +** Function bta_hl_find_dch_setup_mdl_idx +** +** Description This function finds a MDL which in the DCH setup state +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_dch_setup_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, + UINT8 *p_mdl_idx) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++) + { + if (p_mcb->mdl[i].in_use && + (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPENING_ST)) + { + found = TRUE; + *p_mdl_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (found) + { + APPL_TRACE_DEBUG4("bta_hl_find_dch_setup_mdl_idx found=%d app_idx=%d mcl_idx=%d mdl_idx=%d", + found, app_idx, mcl_idx, i); + } +#endif + + return found; +} + +/******************************************************************************* +** +** Function bta_hl_find_an_in_use_mcl_idx +** +** Description This function finds an in-use MCL control block index +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_an_in_use_mcl_idx(UINT8 app_idx, + UINT8 *p_mcl_idx) +{ + tBTA_HL_MCL_CB *p_mcb; + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_MCLS ; i ++) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i); + if (p_mcb->in_use && + (p_mcb->cch_state != BTA_HL_CCH_IDLE_ST)) + { + found = TRUE; + *p_mcl_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (found) + { + APPL_TRACE_DEBUG3("bta_hl_find_an_in_use_mcl_idx found=%d app_idx=%d mcl_idx=%d ", + found, app_idx, i); + } +#endif + + return found; +} + + +/******************************************************************************* +** +** Function bta_hl_find_an_in_use_app_idx +** +** Description This function finds an in-use application control block index +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_an_in_use_app_idx(UINT8 *p_app_idx) +{ + tBTA_HL_APP_CB *p_acb ; + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_APPS ; i ++) + { + p_acb = BTA_HL_GET_APP_CB_PTR(i); + if (p_acb->in_use) + { + found = TRUE; + *p_app_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (found) + { + APPL_TRACE_DEBUG2("bta_hl_find_an_in_use_app_idx found=%d app_idx=%d ", + found, i); + } +#endif + + return found; +} +/******************************************************************************* +** +** Function bta_hl_find_app_idx +** +** Description This function finds the application control block index based on +** the application ID +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_app_idx(UINT8 app_id, UINT8 *p_app_idx) +{ + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_APPS ; i ++) + { + if (bta_hl_cb.acb[i].in_use && + (bta_hl_cb.acb[i].app_id == app_id)) + { + found = TRUE; + *p_app_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG3("bta_hl_find_app_idx found=%d app_id=%d idx=%d ", + found, app_id, i); +#endif + + return found; +} + + +/******************************************************************************* +** +** Function bta_hl_find_app_idx_using_handle +** +** Description This function finds the application control block index based on +** the application handle +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle, + UINT8 *p_app_idx) +{ + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_APPS ; i ++) + { + if (bta_hl_cb.acb[i].in_use && + (bta_hl_cb.acb[i].app_handle == app_handle)) + { + found = TRUE; + *p_app_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG3("bta_hl_find_app_idx_using_mca_handle status=%d handle=%d app_idx=%d ", + found, app_handle , i); + } +#endif + + return found; +} + + +/******************************************************************************* +** +** Function bta_hl_find_mcl_idx_using_handle +** +** Description This function finds the MCL control block index based on +** the MCL handle +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_mcl_idx_using_handle( tBTA_HL_MCL_HANDLE mcl_handle, + UINT8 *p_app_idx, UINT8 *p_mcl_idx) +{ + tBTA_HL_APP_CB *p_acb; + BOOLEAN found=FALSE; + UINT8 i,j; + + for (i=0; i<BTA_HL_NUM_APPS; i++) + { + p_acb = BTA_HL_GET_APP_CB_PTR(i); + if (p_acb->in_use) + { + for (j=0; j < BTA_HL_NUM_MCLS ; j++) + { + if ( p_acb->mcb[j].mcl_handle == mcl_handle ) + { + found = TRUE; + *p_app_idx = i; + *p_mcl_idx = j; + break; + } + } + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG3("bta_hl_find_mcl_idx_using_handle found=%d app_idx=%d mcl_idx=%d", + found, i, j); + } +#endif + return found; +} + +/******************************************************************************* +** +** Function bta_hl_find_mcl_idx +** +** Description This function finds the MCL control block index based on +** the peer BD address +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_mcl_idx(UINT8 app_idx, BD_ADDR p_bd_addr, UINT8 *p_mcl_idx) +{ + BOOLEAN found=FALSE; + UINT8 i; + tBTA_HL_MCL_CB *p_mcb; + + for (i=0; i < BTA_HL_NUM_MCLS ; i ++) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i); + + if (bta_hl_cb.acb[app_idx].mcb[i].in_use && + (!memcmp (bta_hl_cb.acb[app_idx].mcb[i].bd_addr, p_bd_addr, BD_ADDR_LEN))) + { + found = TRUE; + *p_mcl_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG2("bta_hl_find_mcl_idx found=%d idx=%d", + found, i); + } +#endif + return found; +} + + + +/******************************************************************************* +** +** Function bta_hl_find_mdl_idx_using_handle +** +** Description This function finds the MDL control block index based on +** the MDL handle +** +** Returns BOOLEAN TRUE-found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle, + UINT8 *p_app_idx,UINT8 *p_mcl_idx, + UINT8 *p_mdl_idx) +{ + tBTA_HL_APP_CB *p_acb; + tBTA_HL_MCL_CB *p_mcb; + tBTA_HL_MDL_CB *p_dcb; + BOOLEAN found=FALSE; + UINT8 i,j,k; + + for (i=0; i < BTA_HL_NUM_APPS ; i ++) + { + p_acb = BTA_HL_GET_APP_CB_PTR(i); + if (p_acb->in_use) + { + for (j=0; j< BTA_HL_NUM_MCLS; j++) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(i,j); + if (p_mcb->in_use) + { + for (k=0; k< BTA_HL_NUM_MDLS_PER_MCL; k++) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(i,j,k); + if (p_dcb->in_use) + { + if (p_dcb->mdl_handle == mdl_handle) + { + found = TRUE; + *p_app_idx = i; + *p_mcl_idx =j; + *p_mdl_idx = k; + break; + } + } + } + } + } + } + } + + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG2("bta_hl_find_mdl_idx_using_handle found=%d mdl_handle=%d ", + found, mdl_handle); + } +#endif + return found; +} +/******************************************************************************* +** +** Function bta_hl_is_the_first_reliable_existed +** +** Description This function checks whether the first reliable DCH channel +** has been setup on the MCL or not +** +** Returns BOOLEAN - TRUE exist +** FALSE does not exist +** +*******************************************************************************/ +BOOLEAN bta_hl_is_the_first_reliable_existed(UINT8 app_idx, UINT8 mcl_idx ) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + BOOLEAN is_existed =FALSE; + UINT8 i ; + + for (i=0; i< BTA_HL_NUM_MDLS_PER_MCL; i++) + { + if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable) + { + is_existed = TRUE; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_is_the_first_reliable_existed is_existed=%d ",is_existed ); +#endif + return is_existed; +} + +/******************************************************************************* +** +** Function bta_hl_find_non_active_mdl_cfg +** +** Description This function finds a valid MDL configiration index and this +** MDL ID is not active +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_non_active_mdl_cfg(UINT8 app_idx, UINT8 start_mdl_cfg_idx, + UINT8 *p_mdl_cfg_idx) +{ + + tBTA_HL_MCL_CB *p_mcb; + tBTA_HL_MDL_CB *p_dcb; + tBTA_HL_MDL_CFG *p_mdl; + BOOLEAN mdl_in_use; + BOOLEAN found = FALSE; + UINT8 i,j,k; + + for (i = start_mdl_cfg_idx; i< BTA_HL_NUM_MDL_CFGS; i++) + { + mdl_in_use = FALSE; + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i); + for (j=0; j< BTA_HL_NUM_MCLS; j++) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, j); + if (p_mcb->in_use && + !memcmp(p_mdl->peer_bd_addr,p_mcb->bd_addr,BD_ADDR_LEN)) + { + + for (k=0; k<BTA_HL_NUM_MDLS_PER_MCL; k++) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, j, k); + + if (p_dcb->in_use && p_mdl->mdl_id == p_dcb->mdl_id) + { + mdl_in_use = TRUE; + break; + } + } + } + + if (mdl_in_use) + { + break; + } + } + + if (!mdl_in_use) + { + *p_mdl_cfg_idx = i; + found = TRUE; + break; + } + } + + return found; +} + +/******************************************************************************* +** +** Function bta_hl_find_mdl_cfg_idx +** +** Description This function finds an available MDL configiration index +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_avail_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx, + UINT8 *p_mdl_cfg_idx) +{ + tBTA_HL_MDL_CFG *p_mdl, *p_mdl1, *p_mdl2; + UINT8 i; + BOOLEAN found=FALSE; + UINT8 first_mdl_cfg_idx, second_mdl_cfg_idx, older_mdl_cfg_idx; + BOOLEAN done; + + + for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++) + { + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i); + if (!p_mdl->active ) + { + /* found an unused space to store mdl cfg*/ + found=TRUE; + *p_mdl_cfg_idx =i; + break; + } + } + + if (!found) + { + /* all available mdl cfg spaces are in use so we need to find the mdl cfg which is + not currently in use and has the the oldest time stamp to remove*/ + + found = TRUE; + if (bta_hl_find_non_active_mdl_cfg(app_idx,0, &first_mdl_cfg_idx)) + { + if (bta_hl_find_non_active_mdl_cfg(app_idx,(UINT8) (first_mdl_cfg_idx+1), &second_mdl_cfg_idx)) + { + done = FALSE; + while (!done) + { + p_mdl1 = BTA_HL_GET_MDL_CFG_PTR(app_idx, first_mdl_cfg_idx); + p_mdl2 = BTA_HL_GET_MDL_CFG_PTR(app_idx, second_mdl_cfg_idx); + + if (p_mdl1->time < p_mdl2->time) + { + older_mdl_cfg_idx = first_mdl_cfg_idx; + } + else + { + older_mdl_cfg_idx = second_mdl_cfg_idx; + } + + if (bta_hl_find_non_active_mdl_cfg(app_idx,(UINT8) (second_mdl_cfg_idx+1), &second_mdl_cfg_idx)) + { + first_mdl_cfg_idx = older_mdl_cfg_idx; + } + else + { + done = TRUE; + } + } + + *p_mdl_cfg_idx = older_mdl_cfg_idx; + + } + else + { + *p_mdl_cfg_idx = first_mdl_cfg_idx; + } + + } + else + { + found = FALSE; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG2("bta_hl_find_avail_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",found, *p_mdl_cfg_idx ); + } +#endif + + return found; + + +} + +/******************************************************************************* +** +** Function bta_hl_find_mdl_cfg_idx +** +** Description This function finds the MDL configuration index based on +** the MDL ID +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_mdl_cfg_idx(UINT8 app_idx, UINT8 mcl_idx, + tBTA_HL_MDL_ID mdl_id, UINT8 *p_mdl_cfg_idx) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CFG *p_mdl; + UINT8 i ; + BOOLEAN found=FALSE; + for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++) + { + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i); + if (p_mdl->active && + (!memcmp (p_mcb->bd_addr, p_mdl->peer_bd_addr, BD_ADDR_LEN))&& + (p_mdl->mdl_id == mdl_id)) + { + found=TRUE; + *p_mdl_cfg_idx =i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG2("bta_hl_find_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",found, i ); + } +#endif + + return found; + + +} + + +/******************************************************************************* +** +** Function bta_hl_get_cur_time +** +** Description This function get the cuurent time value +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_get_cur_time(UINT8 app_idx, UINT8 *p_cur_time) +{ + tBTA_HL_MDL_CFG *p_mdl; + UINT8 i, j, time_latest, time; + BOOLEAN found=FALSE, result=TRUE; + + for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++) + { + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i); + if (p_mdl->active) + { + found=TRUE; + time_latest = p_mdl->time; + for (j=(i+1); j< BTA_HL_NUM_MDL_CFGS; j++ ) + { + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, j); + if (p_mdl->active) + { + time = p_mdl->time; + if (time > time_latest) + { + time_latest = time; + } + } + } + break; + } + } + + + if (found) + { + if (time_latest < BTA_HL_MAX_TIME) + { + *p_cur_time = time_latest+1; + } + else + { + /* need to wrap around */ + result = FALSE; + } + } + else + { + *p_cur_time = BTA_HL_MIN_TIME; + } + +#if BTA_HL_DEBUG == TRUE + if (!result) + { + APPL_TRACE_DEBUG2("bta_hl_get_cur_time result=%s cur_time=%d", + (result?"OK":"FAIL"), *p_cur_time); + } +#endif + + return result; +} + +/******************************************************************************* +** +** Function bta_hl_sort_cfg_time_idx +** +** Description This function sort the mdl configuration idx stored in array a +** based on decending time value +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +void bta_hl_sort_cfg_time_idx(UINT8 app_idx, UINT8 *a, UINT8 n) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + UINT8 temp_time, temp_idx; + INT16 i, j; + for (i = 1; i < n; ++i) + { + temp_idx = a[i]; + temp_time = p_acb->mdl_cfg[temp_idx].time; + j = i - 1; + while ((j >= 0) && (temp_time < p_acb->mdl_cfg[a[j]].time)) + { + a[j + 1] = a[j]; + --j; + } + a[j + 1] = temp_idx; + } +} + +/******************************************************************************* +** +** Function bta_hl_compact_mdl_cfg_time +** +** Description This function finds the MDL configuration index based on +** the MDL ID +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +void bta_hl_compact_mdl_cfg_time(UINT8 app_idx) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MDL_CFG *p_mdl; + UINT8 i, time_min, cnt=0; + UINT8 s_arr[BTA_HL_NUM_MDL_CFGS]; + + + for (i=0; i< BTA_HL_NUM_MDL_CFGS; i++) + { + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i); + if (p_mdl->active ) + { + s_arr[cnt]= i; + cnt++; + } + } + + + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_compact_mdl_cfg_time cnt=%d ",cnt ); +#endif + + + if (cnt) + { + bta_hl_sort_cfg_time_idx(app_idx, s_arr, cnt); + time_min = BTA_HL_MIN_TIME; + for (i=0;i<cnt; i++) + { + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, s_arr[i]); + p_mdl->time = time_min + i; + bta_hl_co_save_mdl(p_acb->app_id, s_arr[i], p_mdl); + } + } + + +} + + + +/******************************************************************************* +** +** Function bta_hl_is_mdl_exsit_in_mcl +** +** Description This function checks whether the MDL ID +** has already existed in teh MCL or not +** +** Returns BOOLEAN - TRUE exist +** FALSE does not exist +** +*******************************************************************************/ +BOOLEAN bta_hl_is_mdl_exsit_in_mcl(UINT8 app_idx, BD_ADDR bd_addr, + tBTA_HL_MDL_ID mdl_id) +{ + tBTA_HL_MDL_CFG *p_mdl; + BOOLEAN found = FALSE; + UINT8 i; + + for (i = 0; i< BTA_HL_NUM_MDL_CFGS; i++) + { + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i); + if (p_mdl->active && + !memcmp(p_mdl->peer_bd_addr, bd_addr,BD_ADDR_LEN)) + { + if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) + { + if (p_mdl->mdl_id == mdl_id) + { + found = TRUE; + break; + } + } + else + { + found = TRUE; + break; + } + } + } + + return found; +} + +/******************************************************************************* +** +** Function bta_hl_delete_mdl_cfg +** +** Description This function delete the specified MDL ID +** +** Returns BOOLEAN - TRUE Success +** FALSE Failed +** +*******************************************************************************/ +BOOLEAN bta_hl_delete_mdl_cfg(UINT8 app_idx, BD_ADDR bd_addr, + tBTA_HL_MDL_ID mdl_id) +{ + tBTA_HL_MDL_CFG *p_mdl; + BOOLEAN success = FALSE; + UINT8 i; + tBTA_HL_APP_CB *p_acb= BTA_HL_GET_APP_CB_PTR(app_idx); + UINT8 app_id = p_acb->app_id; + + for (i = 0; i< BTA_HL_NUM_MDL_CFGS; i++) + { + p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i); + if (p_mdl->active && + !memcmp(p_mdl->peer_bd_addr, bd_addr,BD_ADDR_LEN)) + { + if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) + { + if (p_mdl->mdl_id == mdl_id) + { + bta_hl_co_delete_mdl(app_id, i); + memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG)); + success = TRUE; + break; + } + } + else + { + bta_hl_co_delete_mdl(app_id, i); + memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG)); + success = TRUE; + } + } + } + + return success; +} + + +/******************************************************************************* +** +** Function bta_hl_is_mdl_value_valid +** +** +** Description This function checks the specified MDL ID is in valid range or not +** +** Returns BOOLEAN - TRUE Success +** FALSE Failed +** +** note: mdl_id range 0x0000 reserved, +** 0x0001-oxFEFF dynamic range, +** 0xFF00-0xFFFE reserved, +** 0xFFFF indicates all MDLs (for delete operation only) +** +*******************************************************************************/ +BOOLEAN bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id) +{ + BOOLEAN status = TRUE; + + if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) + { + if (mdl_id != 0) + { + if (mdl_id > BTA_HL_MAX_MDL_VAL ) + { + status = FALSE; + } + } + else + { + status = FALSE; + } + } + + return status; +} + +/******************************************************************************* +** +** Function bta_hl_find_mdep_cfg_idx +** +** Description This function finds the MDEP configuration index based +** on the local MDEP ID +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_mdep_cfg_idx(UINT8 app_idx, tBTA_HL_MDEP_ID local_mdep_id, + UINT8 *p_mdep_cfg_idx) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_SUP_FEATURE *p_sup_feature= &p_acb->sup_feature; + BOOLEAN found =FALSE; + UINT8 i; + + for (i=0; i< p_sup_feature->num_of_mdeps; i++) + { + if ( p_sup_feature->mdep[i].mdep_id == local_mdep_id) + { + found = TRUE; + *p_mdep_cfg_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG3("bta_hl_find_mdep_cfg_idx found=%d mdep_idx=%d local_mdep_id=%d ", + found,i, local_mdep_id ); + } +#endif + return found; +} + + +/******************************************************************************* +** +** Function bta_hl_find_rxtx_apdu_size +** +** Description This function finds the maximum APDU rx and tx sizes based on +** the MDEP configuration data +** +** Returns void +** +*******************************************************************************/ +void bta_hl_find_rxtx_apdu_size(UINT8 app_idx, UINT8 mdep_cfg_idx, + UINT16 *p_rx_apu_size, + UINT16 *p_tx_apu_size) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MDEP_CFG *p_mdep_cfg; + UINT8 i; + UINT16 max_rx_apdu_size=0, max_tx_apdu_size=0; + + p_mdep_cfg = &p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg; + + + for (i=0; i< p_mdep_cfg->num_of_mdep_data_types ; i++) + { + + if (max_rx_apdu_size < p_mdep_cfg->data_cfg[i].max_rx_apdu_size) + { + max_rx_apdu_size = p_mdep_cfg->data_cfg[i].max_rx_apdu_size; + } + + if (max_tx_apdu_size < p_mdep_cfg->data_cfg[i].max_tx_apdu_size) + { + max_tx_apdu_size = p_mdep_cfg->data_cfg[i].max_tx_apdu_size; + } + } + + + *p_rx_apu_size = max_rx_apdu_size; + *p_tx_apu_size = max_tx_apdu_size; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG2("bta_hl_find_rxtx_apdu_size max_rx_apdu_size=%d max_tx_apdu_size=%d ", + max_rx_apdu_size, max_tx_apdu_size ); +#endif + + +} + +/******************************************************************************* +** +** Function bta_hl_validate_peer_cfg +** +** Description This function validates the peer DCH configuration +** +** Returns BOOLEAN - TRUE validation is successful +** FALSE validation failed +** +*******************************************************************************/ +BOOLEAN bta_hl_validate_peer_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx, + tBTA_HL_MDEP_ID peer_mdep_id, + tBTA_HL_MDEP_ROLE peer_mdep_role, + UINT8 sdp_idx) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + tBTA_HL_SDP_REC *p_rec; + BOOLEAN peer_found =FALSE; + UINT8 i; + + APPL_TRACE_DEBUG1("bta_hl_validate_peer_cfg sdp_idx=%d", sdp_idx); + + + if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) + { + return TRUE; + } + + p_rec = &p_mcb->sdp.sdp_rec[sdp_idx]; + for (i=0; i< p_rec->num_mdeps; i++) + { + if ( (p_rec->mdep_cfg[i].mdep_id == peer_mdep_id) && + (p_rec->mdep_cfg[i].mdep_role == peer_mdep_role)) + { + peer_found = TRUE; + + break; + } + } + + +#if BTA_HL_DEBUG == TRUE + if (!peer_found) + { + APPL_TRACE_DEBUG1("bta_hl_validate_peer_cfg failed num_mdeps=%d",p_rec->num_mdeps); + } +#endif + return peer_found; +} + + +/******************************************************************************* +** +** Function bta_hl_chk_local_cfg +** +** Description This function check whether the local DCH configuration is OK or not +** +** Returns tBTA_HL_STATUS - OK - local DCH configuration is OK +** NO_FIRST_RELIABLE - the streaming DCH configuration +** is not OK and it needs to use +** reliable DCH configuration +** +*******************************************************************************/ +tBTA_HL_STATUS bta_hl_chk_local_cfg(UINT8 app_idx, UINT8 mcl_idx, + UINT8 mdep_cfg_idx, + tBTA_HL_DCH_CFG local_cfg) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + + if ( mdep_cfg_idx && + (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE) && + (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) && + (local_cfg != BTA_HL_DCH_CFG_RELIABLE)) + { + status = BTA_HL_STATUS_NO_FIRST_RELIABLE; + APPL_TRACE_ERROR0("BTA_HL_STATUS_INVALID_DCH_CFG"); + } + + return status; +} + + +/******************************************************************************* +** +** Function bta_hl_validate_reconnect_params +** +** Description This function validates the reconnect parameters +** +** Returns BOOLEAN - TRUE validation is successful +** FALSE validation failed +*******************************************************************************/ +BOOLEAN bta_hl_validate_reconnect_params(UINT8 app_idx, UINT8 mcl_idx, + tBTA_HL_API_DCH_RECONNECT *p_reconnect, + UINT8 *p_mdep_cfg_idx, UINT8 *p_mdl_cfg_idx) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_SUP_FEATURE *p_sup_feature = &p_acb->sup_feature; + UINT8 num_mdeps; + UINT8 mdl_cfg_idx; + BOOLEAN local_mdep_id_found =FALSE; + BOOLEAN mdl_cfg_found =FALSE; + BOOLEAN status=FALSE; + UINT8 i, in_use_mdl_idx; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_validate_reconnect_params mdl_id=%d", p_reconnect->mdl_id); +#endif + if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect->mdl_id, &mdl_cfg_idx)) + { + mdl_cfg_found = TRUE; + } + +#if BTA_HL_DEBUG == TRUE + if (!mdl_cfg_found) + { + APPL_TRACE_DEBUG0("mdl_cfg_found not found"); + } +#endif + + + if (mdl_cfg_found) + { + num_mdeps = p_sup_feature->num_of_mdeps; + for (i=0; i< num_mdeps ; i++) + { + if ( p_sup_feature->mdep[i].mdep_id == p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id) + { + local_mdep_id_found = TRUE; + *p_mdep_cfg_idx =i; + *p_mdl_cfg_idx = mdl_cfg_idx; + break; + } + } + } + +#if BTA_HL_DEBUG == TRUE + if (!local_mdep_id_found) + { + APPL_TRACE_DEBUG0("local_mdep_id not found"); + } +#endif + + + if (local_mdep_id_found) + { + if (!bta_hl_find_mdl_idx(app_idx,mcl_idx, p_reconnect->mdl_id, &in_use_mdl_idx)) + { + status= TRUE; + } + else + { + APPL_TRACE_ERROR1("mdl_id=%d is curreltly in use",p_reconnect->mdl_id); + } + } + +#if BTA_HL_DEBUG == TRUE + if (!status) + { + APPL_TRACE_DEBUG3("Reconnect validation failed local_mdep_id found=%d mdl_cfg_idx found=%d in_use_mdl_idx=%d ", + local_mdep_id_found, mdl_cfg_found, in_use_mdl_idx); + } +#endif + return status; +} + +/******************************************************************************* +** +** Function bta_hl_find_avail_mcl_idx +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_avail_mcl_idx(UINT8 app_idx, UINT8 *p_mcl_idx) +{ + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_MCLS ; i ++) + { + if (!bta_hl_cb.acb[app_idx].mcb[i].in_use) + { + found = TRUE; + *p_mcl_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG2("bta_hl_find_avail_mcl_idx found=%d idx=%d", + found, i); + } +#endif + return found; +} + + + +/******************************************************************************* +** +** Function bta_hl_find_avail_mdl_idx +** +** Description This function finds an available MDL control block index +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_avail_mdl_idx(UINT8 app_idx, UINT8 mcl_idx, + UINT8 *p_mdl_idx) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_MDLS_PER_MCL ; i ++) + { + if (!p_mcb->mdl[i].in_use) + { + memset((void *)&p_mcb->mdl[i],0, sizeof(tBTA_HL_MDL_CB)); + found = TRUE; + *p_mdl_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG2("bta_hl_find_avail_mdl_idx found=%d idx=%d", + found, i); + } +#endif + return found; +} + +/******************************************************************************* +** +** Function bta_hl_is_a_duplicate_id +** +** Description This function finds the application has been used or not +** +** Returns BOOLEAN - TRUE the app_id is a duplicate ID +** FALSE not a duplicate ID +*******************************************************************************/ +BOOLEAN bta_hl_is_a_duplicate_id(UINT8 app_id) +{ + BOOLEAN is_duplicate=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_APPS ; i ++) + { + if (bta_hl_cb.acb[i].in_use && + (bta_hl_cb.acb[i].app_id == app_id)) + { + is_duplicate = TRUE; + + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (is_duplicate) + { + + APPL_TRACE_DEBUG2("bta_hl_is_a_duplicate_id app_id=%d is_duplicate=%d", + app_id, is_duplicate); + } +#endif + + return is_duplicate; +} + + +/******************************************************************************* +** +** Function bta_hl_find_avail_app_idx +** +** Description This function finds an available application control block index +** +** Returns BOOLEAN - TRUE found +** FALSE not found +** +*******************************************************************************/ +BOOLEAN bta_hl_find_avail_app_idx(UINT8 *p_idx) +{ + BOOLEAN found=FALSE; + UINT8 i; + + for (i=0; i < BTA_HL_NUM_APPS ; i ++) + { + if (!bta_hl_cb.acb[i].in_use) + { + found = TRUE; + *p_idx = i; + break; + } + } + +#if BTA_HL_DEBUG == TRUE + if (!found) + { + APPL_TRACE_DEBUG2("bta_hl_find_avail_app_idx found=%d app_idx=%d", + found, i); + } +#endif + return found; +} + +/******************************************************************************* +** +** Function bta_hl_app_registration +** +** Description This function registers an HDP application MCAP and DP +** +** Returns tBTA_HL_STATUS -registration status +** +*******************************************************************************/ +tBTA_HL_STATUS bta_hl_app_registration(UINT8 app_idx) +{ + tBTA_HL_STATUS status = BTA_HL_STATUS_OK; + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tMCA_REG reg; + tMCA_CS mca_cs; + UINT8 i, num_of_mdeps; + + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("bta_hl_app_registration app_idx=%d", app_idx); +#endif + + reg.ctrl_psm = p_acb->ctrl_psm; + reg.data_psm = p_acb->data_psm; + reg.sec_mask = p_acb->sec_mask; + reg.rsp_tout = BTA_HL_MCAP_RSP_TOUT; + + if ( (p_acb->app_handle = (tBTA_HL_APP_HANDLE) MCA_Register(®, bta_hl_mcap_ctrl_cback))!=0) + { + mca_cs.type = MCA_TDEP_ECHO; + mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP; + mca_cs.p_data_cback = bta_hl_mcap_data_cback; + + if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle, + &(p_acb->sup_feature.mdep[0].mdep_id), + &mca_cs) == MCA_SUCCESS) + { + if (p_acb->sup_feature.mdep[0].mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) + { + status = BTA_HL_STATUS_MCAP_REG_FAIL; + APPL_TRACE_ERROR1("BAD MDEP ID for echo test mdep_id=%d", + p_acb->sup_feature.mdep[0].mdep_id ); + } + } + else + { + status = BTA_HL_STATUS_MCAP_REG_FAIL; + APPL_TRACE_ERROR0("MCA_CreateDep for echo test(mdep_id=0) failed"); + } + + + if ((status == BTA_HL_STATUS_OK) && + bta_hl_co_get_num_of_mdep(p_acb->app_id, &num_of_mdeps)) + { + p_acb->sup_feature.num_of_mdeps = num_of_mdeps+1; + + for (i=1; i<p_acb->sup_feature.num_of_mdeps; i++) + { + mca_cs.type = MCA_TDEP_DATA; + mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP; + mca_cs.p_data_cback = bta_hl_mcap_data_cback; + + if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle, + &(p_acb->sup_feature.mdep[i].mdep_id), &mca_cs) == MCA_SUCCESS) + { + if (bta_hl_co_get_mdep_config(p_acb->app_id, + i, + p_acb->sup_feature.mdep[i].mdep_id, + &p_acb->sup_feature.mdep[i].mdep_cfg)) + { + if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE) + { + p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE; + } + else if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SINK) + { + p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK; + } + else + { + status = BTA_HL_STATUS_MDEP_CO_FAIL; + break; + } + } + else + { + status = BTA_HL_STATUS_MDEP_CO_FAIL; + break; + } + } + else + { + status = BTA_HL_STATUS_MCAP_REG_FAIL; + break; + } + } + + + + if ((status == BTA_HL_STATUS_OK) && + (p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE)) + { + /* this is a source only applciation */ + p_acb->sup_feature.advertize_source_sdp = + bta_hl_co_advrtise_source_sdp(p_acb->app_id); + } + + if ((status == BTA_HL_STATUS_OK)&& + (!bta_hl_co_get_echo_config(p_acb->app_id, &p_acb->sup_feature.echo_cfg))) + { + status = BTA_HL_STATUS_ECHO_CO_FAIL; + } + + if ((status == BTA_HL_STATUS_OK)&& + (!bta_hl_co_load_mdl_config(p_acb->app_id, BTA_HL_NUM_MDL_CFGS, &p_acb->mdl_cfg[0]))) + { + status = BTA_HL_STATUS_MDL_CFG_CO_FAIL; + } + } + else + { + status = BTA_HL_STATUS_MDEP_CO_FAIL; + } + } + else + { + status = BTA_HL_STATUS_MCAP_REG_FAIL; + } + + if (status == BTA_HL_STATUS_OK) + { + status = bta_hl_sdp_register(app_idx); + } + + return status; +} + + +/******************************************************************************* +** +** Function bta_hl_discard_data +** +** Description This function discard an HDP event +** +** Returns void +** +*******************************************************************************/ +void bta_hl_discard_data(UINT16 event, tBTA_HL_DATA *p_data) +{ + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_ERROR1("BTA HL Discard event=%s",bta_hl_evt_code(event)); + +#endif + + switch (event) + { + case BTA_HL_API_SEND_DATA_EVT: + break; + + case BTA_HL_MCA_RCV_DATA_EVT: + utl_freebuf((void**)&p_data->mca_rcv_data_evt.p_pkt); + break; + + default: + /*Nothing to free*/ + break; + } +} + +/******************************************************************************* +** +** Function bta_hl_save_mdl_cfg +** +** Description This function saves the MDL configuration +** +** Returns void +** +*******************************************************************************/ +void bta_hl_save_mdl_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx ) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + UINT8 mdl_cfg_idx; + tBTA_HL_MDL_ID mdl_id; + BOOLEAN found=TRUE; + tBTA_HL_MDL_CFG mdl_cfg; + tBTA_HL_MDEP *p_mdep_cfg; + tBTA_HL_L2CAP_CFG_INFO l2cap_cfg; + UINT8 time_val; + mdl_id = p_dcb->mdl_id; + if (!bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx)) + { + if (!bta_hl_find_avail_mdl_cfg_idx(app_idx, mcl_idx, &mdl_cfg_idx)) + { + APPL_TRACE_ERROR0("No space to save the MDL config"); + found= FALSE; /*no space available*/ + } + } + + if (found) + { + bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg); + if (!bta_hl_get_cur_time(app_idx, &time_val )) + { + bta_hl_compact_mdl_cfg_time(app_idx); + bta_hl_get_cur_time(app_idx, &time_val); + } + mdl_cfg.active = TRUE; + mdl_cfg.time = time_val; + mdl_cfg.mdl_id = p_dcb->mdl_id; + mdl_cfg.dch_mode = p_dcb->dch_mode; + mdl_cfg.mtu = l2cap_cfg.mtu; + mdl_cfg.fcs = l2cap_cfg.fcs; + + bdcpy(mdl_cfg.peer_bd_addr, p_mcb->bd_addr); + mdl_cfg.local_mdep_id= p_dcb->local_mdep_id; + p_mdep_cfg = &p_acb->sup_feature.mdep[p_dcb->local_mdep_cfg_idx]; + mdl_cfg.local_mdep_role= p_mdep_cfg->mdep_cfg.mdep_role; + memcpy(&p_acb->mdl_cfg[mdl_cfg_idx], &mdl_cfg, sizeof(tBTA_HL_MDL_CFG)); + bta_hl_co_save_mdl(p_acb->app_id, mdl_cfg_idx, &mdl_cfg); + } + +#if BTA_HL_DEBUG == TRUE + if (found) + { + if (p_dcb->mtu != l2cap_cfg.mtu) + { + APPL_TRACE_WARNING2("MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap mtu=%d", + p_dcb->mtu, l2cap_cfg.mtu); + } + APPL_TRACE_DEBUG1("bta_hl_save_mdl_cfg saved=%d", found); + APPL_TRACE_DEBUG4("Saved. L2cap cfg mdl_id=%d mtu=%d fcs=%d dch_mode=%d", + mdl_cfg.mdl_id, mdl_cfg.mtu, mdl_cfg.fcs, mdl_cfg.dch_mode); + } +#endif + + + +} + +/******************************************************************************* +** +** Function bta_hl_set_dch_chan_cfg +** +** Description This function setups the L2CAP DCH channel configuration +** +** Returns void +*******************************************************************************/ +void bta_hl_set_dch_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx,tBTA_HL_DATA *p_data) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + UINT8 l2cap_mode = L2CAP_FCR_ERTM_MODE; + tBTA_HL_SUP_FEATURE *p_sup_feature= &p_acb->sup_feature; + UINT8 local_mdep_cfg_idx = p_dcb->local_mdep_cfg_idx; + + switch (p_dcb->dch_oper) + { + case BTA_HL_DCH_OP_LOCAL_RECONNECT: + case BTA_HL_DCH_OP_REMOTE_RECONNECT: + if (p_dcb->dch_mode == BTA_HL_DCH_MODE_STREAMING) + l2cap_mode = L2CAP_FCR_STREAM_MODE; + break; + case BTA_HL_DCH_OP_LOCAL_OPEN: + if (p_data->mca_evt.mca_data.create_cfm.cfg == BTA_HL_DCH_CFG_STREAMING) + l2cap_mode = L2CAP_FCR_STREAM_MODE; + break; + case BTA_HL_DCH_OP_REMOTE_OPEN: + if (p_dcb->local_cfg == BTA_HL_DCH_CFG_STREAMING ) + l2cap_mode = L2CAP_FCR_STREAM_MODE; + break; + default: + APPL_TRACE_ERROR1("Invalid dch oper=%d for set dch chan cfg", p_dcb->dch_oper); + break; + } + p_dcb->chnl_cfg.fcr_opt.mode = l2cap_mode; + p_dcb->chnl_cfg.fcr_opt.mps = bta_hl_set_mps(p_dcb->max_rx_apdu_size); + p_dcb->chnl_cfg.fcr_opt.tx_win_sz = bta_hl_set_tx_win_size(p_dcb->max_rx_apdu_size, + p_dcb->chnl_cfg.fcr_opt.mps); + p_dcb->chnl_cfg.fcr_opt.max_transmit= BTA_HL_L2C_MAX_TRANSMIT; + p_dcb->chnl_cfg.fcr_opt.rtrans_tout = BTA_HL_L2C_RTRANS_TOUT; + p_dcb->chnl_cfg.fcr_opt.mon_tout = BTA_HL_L2C_MON_TOUT; + + p_dcb->chnl_cfg.user_rx_pool_id = bta_hl_set_user_rx_pool_id(p_dcb->max_rx_apdu_size); + p_dcb->chnl_cfg.user_tx_pool_id = bta_hl_set_user_tx_pool_id(p_dcb->max_tx_apdu_size); + p_dcb->chnl_cfg.fcr_rx_pool_id = BTA_HL_L2C_FCR_RX_POOL_ID; + p_dcb->chnl_cfg.fcr_tx_pool_id = BTA_HL_L2C_FCR_TX_POOL_ID; + p_dcb->chnl_cfg.data_mtu = p_dcb->max_rx_apdu_size; + + p_dcb->chnl_cfg.fcs = BTA_HL_MCA_NO_FCS; + if (local_mdep_cfg_idx != BTA_HL_ECHO_TEST_MDEP_CFG_IDX) + { + if (p_sup_feature->mdep[local_mdep_cfg_idx].mdep_cfg.mdep_role == + BTA_HL_MDEP_ROLE_SOURCE) + { + p_dcb->chnl_cfg.fcs = BTA_HL_DEFAULT_SOURCE_FCS; + } + } + else + { + p_dcb->chnl_cfg.fcs = BTA_HL_MCA_USE_FCS; + } + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG1("L2CAP Params l2cap_mode[3-ERTM 4-STREAM]=%d", l2cap_mode); + APPL_TRACE_DEBUG2("Use FCS =%s mtu=%d", ((p_dcb->chnl_cfg.fcs & 1)?"YES":"NO"), + p_dcb->chnl_cfg.data_mtu); + APPL_TRACE_DEBUG5("tx_win_sz=%d, max_transmit=%d, rtrans_tout=%d, mon_tout=%d, mps=%d", + p_dcb->chnl_cfg.fcr_opt.tx_win_sz, + p_dcb->chnl_cfg.fcr_opt.max_transmit, + p_dcb->chnl_cfg.fcr_opt.rtrans_tout, + p_dcb->chnl_cfg.fcr_opt.mon_tout, + p_dcb->chnl_cfg.fcr_opt.mps); + + APPL_TRACE_DEBUG4("USER rx_pool_id=%d, tx_pool_id=%d, FCR rx_pool_id=%d, tx_pool_id=%d", + p_dcb->chnl_cfg.user_rx_pool_id, + p_dcb->chnl_cfg.user_tx_pool_id, + p_dcb->chnl_cfg.fcr_rx_pool_id, + p_dcb->chnl_cfg.fcr_tx_pool_id); + +#endif + + + + + + + + +} + +/******************************************************************************* +** +** Function bta_hl_get_l2cap_cfg +** +** Description This function get the current L2CAP channel configuration +** +** Returns BOOLEAN - TRUE - operation is successful +*******************************************************************************/ +BOOLEAN bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd, tBTA_HL_L2CAP_CFG_INFO *p_cfg) +{ + BOOLEAN success = FALSE; + UINT16 lcid; + tL2CAP_CFG_INFO *p_our_cfg; + tL2CAP_CH_CFG_BITS our_cfg_bits; + tL2CAP_CFG_INFO *p_peer_cfg; + tL2CAP_CH_CFG_BITS peer_cfg_bits; + + lcid = MCA_GetL2CapChannel((tMCA_DL) mdl_hnd); + if ( lcid && + L2CA_GetCurrentConfig(lcid, &p_our_cfg, &our_cfg_bits, &p_peer_cfg, + &peer_cfg_bits)) + { + p_cfg->fcs = BTA_HL_MCA_NO_FCS; + if (our_cfg_bits & L2CAP_CH_CFG_MASK_FCS) + { + p_cfg->fcs |= p_our_cfg->fcs; + } + else + { + p_cfg->fcs = BTA_HL_MCA_USE_FCS; + } + + if (p_cfg->fcs != BTA_HL_MCA_USE_FCS ) + { + if (peer_cfg_bits & L2CAP_CH_CFG_MASK_FCS) + { + p_cfg->fcs |= p_peer_cfg->fcs; + } + else + { + p_cfg->fcs = BTA_HL_MCA_USE_FCS; + } + } + + p_cfg->mtu =0; + if (peer_cfg_bits & L2CAP_CH_CFG_MASK_MTU) + { + p_cfg->mtu = p_peer_cfg->mtu; + } + else + { + p_cfg->mtu = L2CAP_DEFAULT_MTU; + } + success = TRUE; + } + +#if BTA_HL_DEBUG == TRUE + if (!success) + { + APPL_TRACE_DEBUG3("bta_hl_get_l2cap_cfg success=%d mdl=%d lcid=%d", success, mdl_hnd, lcid); + APPL_TRACE_DEBUG2("l2cap mtu=%d fcs=%d", p_cfg->mtu, p_cfg->fcs); + } +#endif + + return success; +} + +/******************************************************************************* +** +** Function bta_hl_validate_chan_cfg +** +** Description This function validates the L2CAP channel configuration +** +** Returns BOOLEAN - TRUE - validation is successful +*******************************************************************************/ +BOOLEAN bta_hl_validate_chan_cfg(UINT8 app_idx, UINT8 mcl_idx, UINT8 mdl_idx) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MDL_CB *p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + BOOLEAN success = FALSE; + UINT8 mdl_cfg_idx; + tBTA_HL_L2CAP_CFG_INFO l2cap_cfg; + + + if (bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg) && + bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_dcb->mdl_id, &mdl_cfg_idx)) + { + if ((p_acb->mdl_cfg[mdl_cfg_idx].mtu <= l2cap_cfg.mtu) && + (p_acb->mdl_cfg[mdl_cfg_idx].fcs == l2cap_cfg.fcs) && + (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode == p_dcb->dch_mode)) + { + success = TRUE; + } + } + + +#if BTA_HL_DEBUG == TRUE + + if (p_dcb->mtu != l2cap_cfg.mtu) + { + APPL_TRACE_WARNING2("MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap mtu=%d", + p_dcb->mtu, l2cap_cfg.mtu); + } + + if (!success) + { + APPL_TRACE_DEBUG4("bta_hl_validate_chan_cfg success=%d app_idx=%d mcl_idx=%d mdl_idx=%d",success, app_idx, mcl_idx, mdl_idx); + APPL_TRACE_DEBUG3("Cur. L2cap cfg mtu=%d fcs=%d dch_mode=%d", l2cap_cfg.mtu, l2cap_cfg.fcs, p_dcb->dch_mode); + APPL_TRACE_DEBUG3("From saved: L2cap cfg mtu=%d fcs=%d dch_mode=%d", p_acb->mdl_cfg[mdl_cfg_idx].mtu, + p_acb->mdl_cfg[mdl_cfg_idx].fcs , p_acb->mdl_cfg[mdl_cfg_idx].dch_mode); + } +#endif + + return success; +} + + +/******************************************************************************* +** +** Function bta_hl_is_cong_on +** +** Description This function checks whether the congestion condition is on or not +** +** Returns BOOLEAN - TRUE DCH is congested +** FALSE not congested +** +*******************************************************************************/ +BOOLEAN bta_hl_is_cong_on(UINT8 app_id, BD_ADDR bd_addr, tBTA_HL_MDL_ID mdl_id) + +{ + tBTA_HL_MDL_CB *p_dcb; + UINT8 app_idx, mcl_idx, mdl_idx; + BOOLEAN cong_status = TRUE; + + if (bta_hl_find_app_idx(app_id, &app_idx)) + { + if (bta_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx )) + { + if (bta_hl_find_mdl_idx(app_idx, mcl_idx, mdl_id, &mdl_idx )) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + cong_status = p_dcb->cong; + } + } + } + + return cong_status; +} + +/******************************************************************************* +** +** Function bta_hl_check_cch_close +** +** Description This function checks whether there is a pending CCH close request +** or not +** +** Returns void +*******************************************************************************/ +void bta_hl_check_cch_close(UINT8 app_idx, UINT8 mcl_idx, tBTA_HL_DATA *p_data, BOOLEAN check_dch_setup ) +{ + tBTA_HL_MCL_CB *p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + tBTA_HL_MDL_CB *p_dcb; + UINT8 mdl_idx; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG1("bta_hl_check_cch_close cch_close_dch_oper=%d",p_mcb->cch_close_dch_oper ); +#endif + + if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE) + { + if (check_dch_setup && bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx)) + { + p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx); + if (!p_mcb->rsp_tout) + { + p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_ABORT; + + if (!p_dcb->abort_oper) + { + p_dcb->abort_oper |= BTA_HL_ABORT_CCH_CLOSE_MASK; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT, p_data); + } + } + else + { + p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT, p_data); + } + } + else if (bta_hl_find_an_active_mdl_idx(app_idx, mcl_idx,&mdl_idx)) + { + p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE; + bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT, p_data); + } + else + { + p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_NONE; + bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_hl_clean_app +** +** Description Cleans up the HDP application resources and control block +** +** Returns void +** +*******************************************************************************/ +void bta_hl_clean_app(UINT8 app_idx) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + int i, num_act_apps=0; + +#if BTA_HL_DEBUG == TRUE + APPL_TRACE_DEBUG0("bta_hl_clean_app"); +#endif + MCA_Deregister((tMCA_HANDLE)p_acb->app_handle); + + if (p_acb->sdp_handle) SDP_DeleteRecord(p_acb->sdp_handle); + + memset((void *) p_acb, 0, sizeof(tBTA_HL_APP_CB)); + + /* check any application is still active */ + for (i=0; i < BTA_HL_NUM_APPS ; i ++) + { + p_acb = BTA_HL_GET_APP_CB_PTR(i); + if (p_acb->in_use) num_act_apps++; + } + + if (!num_act_apps) + { + bta_sys_remove_uuid(UUID_SERVCLASS_HDP_PROFILE); + } +} + +/******************************************************************************* +** +** Function bta_hl_check_deregistration +** +** Description This function checks whether there is a pending deregistration +** request or not +** +** Returns void +*******************************************************************************/ +void bta_hl_check_deregistration(UINT8 app_idx, tBTA_HL_DATA *p_data ) +{ + tBTA_HL_APP_CB *p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + tBTA_HL_MCL_CB *p_mcb; + UINT8 mcl_idx; + tBTA_HL evt_data; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_check_deregistration"); +#endif + + if (p_acb->deregistering) + { + if (bta_hl_find_an_in_use_mcl_idx(app_idx, &mcl_idx)) + { + p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx); + if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) + { + p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE; + bta_hl_check_cch_close(app_idx,mcl_idx,p_data, TRUE); + } + } + else + { + /* all cchs are closed */ + evt_data.dereg_cfm.app_handle = p_acb->app_handle; + evt_data.dereg_cfm.status = BTA_HL_STATUS_OK; + p_acb->p_cback(BTA_HL_DEREGISTER_CFM_EVT, (tBTA_HL *) &evt_data ); + bta_hl_clean_app(app_idx); + bta_hl_check_disable(p_data); + } + } +} + + +/******************************************************************************* +** +** Function bta_hl_check_disable +** +** Description This function checks whether there is a pending disable +** request or not +** +** Returns void +** +*******************************************************************************/ +void bta_hl_check_disable(tBTA_HL_DATA *p_data ) +{ + tBTA_HL_CB *p_cb= &bta_hl_cb; + tBTA_HL_APP_CB *p_acb; + UINT8 app_idx; + tBTA_HL_CTRL evt_data; + +#if (BTA_HL_DEBUG == TRUE) + APPL_TRACE_DEBUG0("bta_hl_check_disable"); +#endif + + if (bta_hl_cb.disabling) + { + if (bta_hl_find_an_in_use_app_idx(&app_idx)) + { + p_acb = BTA_HL_GET_APP_CB_PTR(app_idx); + if (!p_acb->deregistering) + { + p_acb->deregistering = TRUE; + bta_hl_check_deregistration(app_idx, p_data); + } + } + else + { + /* all apps are deregistered */ + bta_sys_deregister(BTA_ID_HL); + evt_data.disable_cfm.status = BTA_HL_STATUS_OK; + if (p_cb->p_ctrl_cback) p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT, (tBTA_HL_CTRL *) &evt_data); + memset((void *) p_cb, 0, sizeof(tBTA_HL_CB)); + } + } +} + +/******************************************************************************* +** +** Function bta_hl_build_abort_cfm +** +** Description This function builds the abort confirmation event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_abort_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status) +{ + p_evt_data->dch_abort_cfm.status = status; + p_evt_data->dch_abort_cfm.mcl_handle = mcl_handle; + p_evt_data->dch_abort_cfm.app_handle = app_handle; +} + +/******************************************************************************* +** +** Function bta_hl_build_abort_ind +** +** Description This function builds the abort indication event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_abort_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle) +{ + p_evt_data->dch_abort_ind.mcl_handle = mcl_handle; + p_evt_data->dch_abort_ind.app_handle = app_handle; +} +/******************************************************************************* +** +** Function bta_hl_build_close_cfm +** +** Description This function builds the close confirmation event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_dch_close_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_STATUS status) +{ + p_evt_data->dch_close_cfm.status = status; + p_evt_data->dch_close_cfm.mdl_handle = mdl_handle; + p_evt_data->dch_close_cfm.mcl_handle = mcl_handle; + p_evt_data->dch_close_cfm.app_handle = app_handle; +} + +/******************************************************************************* +** +** Function bta_hl_build_dch_close_ind +** +** Description This function builds the close indication event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_dch_close_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle, + BOOLEAN intentional) +{ + p_evt_data->dch_close_ind.mdl_handle = mdl_handle; + p_evt_data->dch_close_ind.mcl_handle = mcl_handle; + p_evt_data->dch_close_ind.app_handle = app_handle; + p_evt_data->dch_close_ind.intentional = intentional; +} + +/******************************************************************************* +** +** Function bta_hl_build_send_data_cfm +** +** Description This function builds the send data confirmation event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_send_data_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_STATUS status ) +{ + + p_evt_data->dch_send_data_cfm.mdl_handle = mdl_handle; + p_evt_data->dch_send_data_cfm.mcl_handle = mcl_handle; + p_evt_data->dch_send_data_cfm.app_handle = app_handle; + p_evt_data->dch_send_data_cfm.status = status; +} + +/******************************************************************************* +** +** Function bta_hl_build_rcv_data_ind +** +** Description This function builds the received data indication event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_rcv_data_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle) +{ + p_evt_data->dch_rcv_data_ind.mdl_handle = mdl_handle; + p_evt_data->dch_rcv_data_ind.mcl_handle = mcl_handle; + p_evt_data->dch_rcv_data_ind.app_handle = app_handle; +} + + +/******************************************************************************* +** +** Function bta_hl_build_cch_open_cfm +** +** Description This function builds the CCH open confirmation event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_cch_open_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + BD_ADDR bd_addr, + tBTA_HL_STATUS status ) +{ + + p_evt_data->cch_open_cfm.app_handle = app_handle; + p_evt_data->cch_open_cfm.mcl_handle = mcl_handle; + bdcpy(p_evt_data->cch_open_cfm.bd_addr, bd_addr); + p_evt_data->cch_open_cfm.status = status; +} + +/******************************************************************************* +** +** Function bta_hl_build_cch_open_ind +** +** Description This function builds the CCH open indication event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_cch_open_ind(tBTA_HL *p_evt_data, tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + BD_ADDR bd_addr ) +{ + + p_evt_data->cch_open_ind.app_handle = app_handle; + p_evt_data->cch_open_ind.mcl_handle = mcl_handle; + bdcpy(p_evt_data->cch_open_ind.bd_addr, bd_addr); +} + +/******************************************************************************* +** +** Function bta_hl_build_cch_close_cfm +** +** Description This function builds the CCH close confirmation event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_cch_close_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status ) +{ + p_evt_data->cch_close_cfm.mcl_handle = mcl_handle; + p_evt_data->cch_close_cfm.app_handle = app_handle; + p_evt_data->cch_close_cfm.status = status; +} + + +/******************************************************************************* +** +** Function bta_hl_build_cch_close_ind +** +** Description This function builds the CCH colse indication event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_cch_close_ind(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + BOOLEAN intentional) +{ + p_evt_data->cch_close_ind.mcl_handle = mcl_handle; + p_evt_data->cch_close_ind.app_handle = app_handle; + p_evt_data->cch_close_ind.intentional = intentional; +} + +/******************************************************************************* +** +** Function bta_hl_build_dch_open_cfm +** +** Description This function builds the DCH open confirmation event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_dch_open_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_MDEP_ID local_mdep_id, + tBTA_HL_MDL_ID mdl_id, + tBTA_HL_DCH_MODE dch_mode, + BOOLEAN first_reliable, + UINT16 mtu, + tBTA_HL_STATUS status) + +{ + p_evt_data->dch_open_cfm.mdl_handle = mdl_handle; + p_evt_data->dch_open_cfm.mcl_handle = mcl_handle; + p_evt_data->dch_open_cfm.app_handle = app_handle; + p_evt_data->dch_open_cfm.local_mdep_id = local_mdep_id; + p_evt_data->dch_open_cfm.mdl_id = mdl_id; + p_evt_data->dch_open_cfm.dch_mode = dch_mode; + p_evt_data->dch_open_cfm.first_reliable = first_reliable; + p_evt_data->dch_open_cfm.mtu = mtu; + p_evt_data->dch_open_cfm.status = status; +} + + +/******************************************************************************* +** +** Function bta_hl_build_sdp_query_cfm +** +** Description This function builds the SDP query indication event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_sdp_query_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + BD_ADDR bd_addr, + tBTA_HL_SDP *p_sdp, + tBTA_HL_STATUS status) + +{ + p_evt_data->sdp_query_cfm.app_handle = app_handle; + bdcpy(p_evt_data->sdp_query_cfm.bd_addr, bd_addr); + p_evt_data->sdp_query_cfm.p_sdp = p_sdp; + p_evt_data->sdp_query_cfm.status = status; +} + + +/******************************************************************************* +** +** Function bta_hl_build_delete_mdl_cfm +** +** Description This function builds the delete MDL confirmation event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_delete_mdl_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_ID mdl_id, + tBTA_HL_STATUS status) + +{ + p_evt_data->delete_mdl_cfm.mcl_handle = mcl_handle; + p_evt_data->delete_mdl_cfm.app_handle = app_handle; + p_evt_data->delete_mdl_cfm.mdl_id = mdl_id; + p_evt_data->delete_mdl_cfm.status = status; +} + +/******************************************************************************* +** +** Function bta_hl_build_echo_test_cfm +** +** Description This function builds the echo test confirmation event data +** +** Returns None +** +*******************************************************************************/ +void bta_hl_build_echo_test_cfm(tBTA_HL *p_evt_data, + tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status ) +{ + p_evt_data->echo_test_cfm.mcl_handle = mcl_handle; + p_evt_data->echo_test_cfm.app_handle = app_handle; + p_evt_data->echo_test_cfm.status = status; +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if (BTA_HL_DEBUG == TRUE) + +/******************************************************************************* +** +** Function bta_hl_status_code +** +** Description get the status string pointer +** +** Returns char * - status string pointer +** +*******************************************************************************/ +char *bta_hl_status_code(tBTA_HL_STATUS status) +{ + switch (status) + { + case BTA_HL_STATUS_OK: + return "BTA_HL_STATUS_OK"; + case BTA_HL_STATUS_FAIL: + return "BTA_HL_STATUS_FAIL"; + case BTA_HL_STATUS_ABORTED: + return "BTA_HL_STATUS_ABORTED"; + case BTA_HL_STATUS_NO_RESOURCE: + return "BTA_HL_STATUS_NO_RESOURCE"; + case BTA_HL_STATUS_LAST_ITEM: + return "BTA_HL_STATUS_LAST_ITEM"; + case BTA_HL_STATUS_DUPLICATE_APP_ID: + return "BTA_HL_STATUS_DUPLICATE_APP_ID"; + case BTA_HL_STATUS_INVALID_APP_HANDLE: + return "BTA_HL_STATUS_INVALID_APP_HANDLE"; + case BTA_HL_STATUS_INVALID_MCL_HANDLE: + return "BTA_HL_STATUS_INVALID_MCL_HANDLE"; + case BTA_HL_STATUS_MCAP_REG_FAIL: + return "BTA_HL_STATUS_MCAP_REG_FAIL"; + case BTA_HL_STATUS_MDEP_CO_FAIL: + return "BTA_HL_STATUS_MDEP_CO_FAIL"; + case BTA_HL_STATUS_ECHO_CO_FAIL: + return "BTA_HL_STATUS_ECHO_CO_FAIL"; + case BTA_HL_STATUS_MDL_CFG_CO_FAIL: + return "BTA_HL_STATUS_MDL_CFG_CO_FAIL"; + case BTA_HL_STATUS_SDP_NO_RESOURCE: + return "BTA_HL_STATUS_SDP_NO_RESOURCE"; + case BTA_HL_STATUS_SDP_FAIL: + return "BTA_HL_STATUS_SDP_FAIL"; + case BTA_HL_STATUS_NO_CCH: + return "BTA_HL_STATUS_NO_CCH"; + case BTA_HL_STATUS_NO_MCL: + return "BTA_HL_STATUS_NO_MCL"; + + case BTA_HL_STATUS_NO_FIRST_RELIABLE: + return "BTA_HL_STATUS_NO_FIRST_RELIABLE"; + case BTA_HL_STATUS_INVALID_DCH_CFG: + return "BTA_HL_STATUS_INVALID_DCH_CFG"; + case BTA_HL_STATUS_INVALID_BD_ADDR: + return "BTA_HL_STATUS_INVALID_BD_ADDR"; + case BTA_HL_STATUS_INVALID_RECONNECT_CFG: + return "BTA_HL_STATUS_INVALID_RECONNECT_CFG"; + case BTA_HL_STATUS_ECHO_TEST_BUSY: + return "BTA_HL_STATUS_ECHO_TEST_BUSY"; + case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID: + return "BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID"; + case BTA_HL_STATUS_INVALID_MDL_ID: + return "BTA_HL_STATUS_INVALID_MDL_ID"; + case BTA_HL_STATUS_NO_MDL_ID_FOUND: + return "BTA_HL_STATUS_NO_MDL_ID_FOUND"; + case BTA_HL_STATUS_DCH_BUSY: + return "BTA_HL_STATUS_DCH_BUSY"; + default: + return "Unknown status code"; + } +} +/******************************************************************************* +** +** Function bta_hl_evt_code +** +** Description Maps HL event code to the corresponding event string +** +** Returns string pointer for the associated event name +** +*******************************************************************************/ +char *bta_hl_evt_code(tBTA_HL_INT_EVT evt_code) +{ + switch (evt_code) + { + case BTA_HL_CCH_OPEN_EVT: + return "BTA_HL_CCH_OPEN_EVT"; + case BTA_HL_CCH_SDP_OK_EVT: + return "BTA_HL_CCH_SDP_OK_EVT"; + case BTA_HL_CCH_SDP_FAIL_EVT: + return "BTA_HL_CCH_SDP_FAIL_EVT"; + case BTA_HL_MCA_CONNECT_IND_EVT: + return "BTA_HL_MCA_CONNECT_IND_EVT"; + case BTA_HL_MCA_DISCONNECT_IND_EVT: + return "BTA_HL_MCA_DISCONNECT_IND_EVT"; + + case BTA_HL_CCH_CLOSE_EVT: + return "BTA_HL_CCH_CLOSE_EVT"; + case BTA_HL_CCH_CLOSE_CMPL_EVT: + return "BTA_HL_CCH_CLOSE_CMPL_EVT"; + case BTA_HL_DCH_OPEN_EVT: + return "BTA_HL_DCH_OPEN_EVT"; + case BTA_HL_MCA_CREATE_IND_EVT: + return "BTA_HL_MCA_CREATE_IND_EVT"; + case BTA_HL_MCA_CREATE_CFM_EVT: + return "BTA_HL_MCA_CREATE_CFM_EVT"; + case BTA_HL_MCA_OPEN_IND_EVT: + return "BTA_HL_MCA_OPEN_IND_EVT"; + case BTA_HL_MCA_OPEN_CFM_EVT: + return "BTA_HL_MCA_OPEN_CFM_EVT"; + case BTA_HL_DCH_CLOSE_EVT: + return "BTA_HL_DCH_CLOSE_EVT"; + case BTA_HL_MCA_CLOSE_IND_EVT: + return "BTA_HL_MCA_CLOSE_IND_EVT"; + case BTA_HL_MCA_CLOSE_CFM_EVT: + return "BTA_HL_MCA_CLOSE_CFM_EVT"; + case BTA_HL_API_SEND_DATA_EVT: + return "BTA_HL_API_SEND_DATA_EVT"; + case BTA_HL_MCA_RCV_DATA_EVT: + return "BTA_HL_MCA_RCV_DATA_EVT"; + case BTA_HL_DCH_CLOSE_CMPL_EVT: + return "BTA_HL_DCH_CLOSE_CMPL_EVT"; + + case BTA_HL_API_ENABLE_EVT: + return "BTA_HL_API_ENABLE_EVT"; + case BTA_HL_API_DISABLE_EVT: + return "BTA_HL_API_DISABLE_EVT"; + case BTA_HL_API_REGISTER_EVT: + return "BTA_HL_API_REGISTER_EVT"; + case BTA_HL_API_DEREGISTER_EVT: + return "BTA_HL_API_DEREGISTER_EVT"; + + case BTA_HL_API_CCH_OPEN_EVT: + return "BTA_HL_API_CCH_OPEN_EVT"; + + case BTA_HL_API_CCH_CLOSE_EVT: + return "BTA_HL_API_CCH_CLOSE_EVT"; + case BTA_HL_API_DCH_OPEN_EVT: + return "BTA_HL_API_DCH_OPEN_EVT"; + + case BTA_HL_API_DCH_RECONNECT_EVT: + return "BTA_HL_API_DCH_RECONNECT_EVT"; + case BTA_HL_API_DCH_CLOSE_EVT: + return "BTA_HL_API_DCH_CLOSE_EVT"; + case BTA_HL_API_DELETE_MDL_EVT: + return "BTA_HL_API_DELETE_MDL_EVT"; + case BTA_HL_API_DCH_ABORT_EVT: + return "BTA_HL_API_DCH_ABORT_EVT"; + + case BTA_HL_DCH_RECONNECT_EVT: + return "BTA_HL_DCH_RECONNECT_EVT"; + case BTA_HL_DCH_SDP_INIT_EVT: + return "BTA_HL_DCH_SDP_INIT_EVT"; + case BTA_HL_DCH_SDP_FAIL_EVT: + return "BTA_HL_DCH_SDP_FAIL_EVT"; + case BTA_HL_API_DCH_ECHO_TEST_EVT: + return "BTA_HL_API_DCH_ECHO_TEST_EVT"; + case BTA_HL_DCH_CLOSE_ECHO_TEST_EVT: + return "BTA_HL_DCH_CLOSE_ECHO_TEST_EVT"; + case BTA_HL_MCA_RECONNECT_IND_EVT: + return "BTA_HL_MCA_RECONNECT_IND_EVT"; + case BTA_HL_MCA_RECONNECT_CFM_EVT: + return "BTA_HL_MCA_RECONNECT_CFM_EVT"; + case BTA_HL_API_DCH_CREATE_RSP_EVT: + return "BTA_HL_API_DCH_CREATE_RSP_EVT"; + case BTA_HL_DCH_ABORT_EVT: + return "BTA_HL_DCH_ABORT_EVT"; + case BTA_HL_MCA_ABORT_IND_EVT: + return "BTA_HL_MCA_ABORT_IND_EVT"; + case BTA_HL_MCA_ABORT_CFM_EVT: + return "BTA_HL_MCA_ABORT_CFM_EVT"; + case BTA_HL_MCA_DELETE_IND_EVT: + return "BTA_HL_MCA_DELETE_IND_EVT"; + case BTA_HL_MCA_DELETE_CFM_EVT: + return "BTA_HL_MCA_DELETE_CFM_EVT"; + case BTA_HL_MCA_CONG_CHG_EVT: + return "BTA_HL_MCA_CONG_CHG_EVT"; + case BTA_HL_CI_GET_TX_DATA_EVT: + return "BTA_HL_CI_GET_TX_DATA_EVT"; + case BTA_HL_CI_PUT_RX_DATA_EVT: + return "BTA_HL_CI_PUT_RX_DATA_EVT"; + case BTA_HL_CI_GET_ECHO_DATA_EVT: + return "BTA_HL_CI_GET_ECHO_DATA_EVT"; + case BTA_HL_DCH_ECHO_TEST_EVT: + return "BTA_HL_DCH_ECHO_TEST_EVT"; + case BTA_HL_CI_PUT_ECHO_DATA_EVT: + return "BTA_HL_CI_PUT_ECHO_DATA_EVT"; + case BTA_HL_API_SDP_QUERY_EVT: + return "BTA_HL_API_SDP_QUERY_EVT"; + case BTA_HL_SDP_QUERY_OK_EVT: + return "BTA_HL_SDP_QUERY_OK_EVT"; + case BTA_HL_SDP_QUERY_FAIL_EVT: + return "BTA_HL_SDP_QUERY_FAIL_EVT"; + case BTA_HL_MCA_RSP_TOUT_IND_EVT: + return "BTA_HL_MCA_RSP_TOUT_IND_EVT"; + + default: + return "Unknown HL event code"; + } +} + +#endif /* Debug Functions */ +#endif // HL_INCLUDED + + + + + + + + diff --git a/bta/include/bd.h b/bta/include/bd.h new file mode 100644 index 0000000..33c3de1 --- /dev/null +++ b/bta/include/bd.h @@ -0,0 +1,102 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * BD address services. + * + ******************************************************************************/ +#ifndef BD_H +#define BD_H + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* bd addr length and type */ +#ifndef BD_ADDR_LEN +#define BD_ADDR_LEN 6 +typedef UINT8 BD_ADDR[BD_ADDR_LEN]; +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* global constant for "any" bd addr */ +extern const BD_ADDR bd_addr_any; +extern const BD_ADDR bd_addr_null; +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function bdcpy +** +** Description Copy bd addr b to a. +** +** +** Returns void +** +*******************************************************************************/ +extern void bdcpy(BD_ADDR a, const BD_ADDR b); + +/******************************************************************************* +** +** Function bdcmp +** +** Description Compare bd addr b to a. +** +** +** Returns Zero if b==a, nonzero otherwise (like memcmp). +** +*******************************************************************************/ +extern int bdcmp(const BD_ADDR a, const BD_ADDR b); + +/******************************************************************************* +** +** Function bdcmpany +** +** Description Compare bd addr to "any" bd addr. +** +** +** Returns Zero if a equals bd_addr_any. +** +*******************************************************************************/ +extern int bdcmpany(const BD_ADDR a); + +/******************************************************************************* +** +** Function bdsetany +** +** Description Set bd addr to "any" bd addr. +** +** +** Returns void +** +*******************************************************************************/ +extern void bdsetany(BD_ADDR a); + +#ifdef __cplusplus +} +#endif + +#endif /* BD_H */ + diff --git a/bta/include/bta_ag_api.h b/bta/include/bta_ag_api.h new file mode 100644 index 0000000..f16687c --- /dev/null +++ b/bta/include/bta_ag_api.h @@ -0,0 +1,514 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 public interface file for the audio gateway (AG) subsystem + * of BTA, Broadcom's Bluetooth application layer for mobile phones. + * + ******************************************************************************/ +#ifndef BTA_AG_API_H +#define BTA_AG_API_H + +#include "bta_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* AG feature masks */ +#define BTA_AG_FEAT_3WAY 0x00000001 /* Three-way calling */ +#define BTA_AG_FEAT_ECNR 0x00000002 /* Echo cancellation and/or noise reduction */ +#define BTA_AG_FEAT_VREC 0x00000004 /* Voice recognition */ +#define BTA_AG_FEAT_INBAND 0x00000008 /* In-band ring tone */ +#define BTA_AG_FEAT_VTAG 0x00000010 /* Attach a phone number to a voice tag */ +#define BTA_AG_FEAT_REJECT 0x00000020 /* Ability to reject incoming call */ +#define BTA_AG_FEAT_ECS 0x00000040 /* Enhanced Call Status */ +#define BTA_AG_FEAT_ECC 0x00000080 /* Enhanced Call Control */ +#define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */ +#define BTA_AG_FEAT_CODEC 0x00000200 /* Codec Negotiation */ +#define BTA_AG_FEAT_VOIP 0x00000400 /* VoIP call */ +/* Proprietary features: using 31 ~ 16 bits */ +#define BTA_AG_FEAT_BTRH 0x00010000 /* CCAP incoming call hold */ +#define BTA_AG_FEAT_UNAT 0x00020000 /* Pass unknown AT commands to application */ +#define BTA_AG_FEAT_NOSCO 0x00040000 /* No SCO control performed by BTA AG */ +#define BTA_AG_FEAT_NO_ESCO 0x00080000 /* Do not allow or use eSCO */ + +typedef UINT32 tBTA_AG_FEAT; + +/* AG parse mode */ +#define BTA_AG_PARSE 0 /* Perform AT command parsing in AG */ +#define BTA_AG_PASS_THROUGH 1 /* Pass data directly to phone’s AT command interpreter */ + +typedef UINT8 tBTA_AG_PARSE_MODE; + +/* AG open status */ +#define BTA_AG_SUCCESS 0 /* Connection successfully opened */ +#define BTA_AG_FAIL_SDP 1 /* Open failed due to SDP */ +#define BTA_AG_FAIL_RFCOMM 2 /* Open failed due to RFCOMM */ +#define BTA_AG_FAIL_RESOURCES 3 /* out of resources failure */ + +typedef UINT8 tBTA_AG_STATUS; + +/* handle values used with BTA_AgResult */ +#define BTA_AG_HANDLE_NONE 0 +#define BTA_AG_HANDLE_ALL 0xFFFF +/* It is safe to use the same value as BTA_AG_HANDLE_ALL + * HANDLE_ALL is used for delivering indication + * SCO_NO_CHANGE is used for changing sco behavior + * They donot interfere with each other + */ +#define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF + +/* AG result codes used with BTA_AgResult */ +#define BTA_AG_SPK_RES 0 /* Update speaker volume */ +#define BTA_AG_MIC_RES 1 /* Update microphone volume */ +#define BTA_AG_INBAND_RING_RES 2 /* Update inband ring state */ +#define BTA_AG_CIND_RES 3 /* Send indicator response for AT+CIND */ +#define BTA_AG_BINP_RES 4 /* Send phone number for voice tag for AT+BINP */ +#define BTA_AG_IND_RES 5 /* Update an indicator value */ +#define BTA_AG_BVRA_RES 6 /* Update voice recognition state */ +#define BTA_AG_CNUM_RES 7 /* Send subscriber number response for AT+CNUM */ +#define BTA_AG_BTRH_RES 8 /* Send CCAP incoming call hold */ +#define BTA_AG_CLCC_RES 9 /* Query list of calls */ +#define BTA_AG_COPS_RES 10 /* Read network operator */ +#define BTA_AG_IN_CALL_RES 11 /* Indicate incoming phone call */ +#define BTA_AG_IN_CALL_CONN_RES 12 /* Incoming phone call connected */ +#define BTA_AG_CALL_WAIT_RES 13 /* Call waiting notification */ +#define BTA_AG_OUT_CALL_ORIG_RES 14 /* Outgoing phone call origination */ +#define BTA_AG_OUT_CALL_ALERT_RES 15 /* Outgoing phone call alerting remote party */ +#define BTA_AG_OUT_CALL_CONN_RES 16 /* Outgoing phone call connected */ +#define BTA_AG_CALL_CANCEL_RES 17 /* Incoming/outgoing 3-way canceled before connected */ +#define BTA_AG_END_CALL_RES 18 /* End call */ +#define BTA_AG_IN_CALL_HELD_RES 19 /* Incoming call held */ +#define BTA_AG_UNAT_RES 20 /* Response to unknown AT command event */ + +typedef UINT8 tBTA_AG_RES; + +/* HFP peer features */ +#define BTA_AG_PEER_FEAT_ECNR 0x0001 /* Echo cancellation and/or noise reduction */ +#define BTA_AG_PEER_FEAT_3WAY 0x0002 /* Call waiting and three-way calling */ +#define BTA_AG_PEER_FEAT_CLI 0x0004 /* Caller ID presentation capability */ +#define BTA_AG_PEER_FEAT_VREC 0x0008 /* Voice recognition activation */ +#define BTA_AG_PEER_FEAT_VOL 0x0010 /* Remote volume control */ +#define BTA_AG_PEER_FEAT_ECS 0x0020 /* Enhanced Call Status */ +#define BTA_AG_PEER_FEAT_ECC 0x0040 /* Enhanced Call Control */ +#define BTA_AG_PEER_FEAT_CODEC 0x0080 /* Codec Negotiation */ +#define BTA_AG_PEER_FEAT_VOIP 0x0100 /* VoIP call */ + +typedef UINT16 tBTA_AG_PEER_FEAT; + +/* HFP peer supported codec masks */ +#define BTA_AG_CODEC_NONE BTM_SCO_CODEC_NONE +#define BTA_AG_CODEC_CVSD BTM_SCO_CODEC_CVSD /* CVSD */ +#define BTA_AG_CODEC_MSBC BTM_SCO_CODEC_MSBC /* mSBC */ +typedef UINT16 tBTA_AG_PEER_CODEC; + +/* HFP errcode - Set when BTA_AG_OK_ERROR is returned in 'ok_flag' */ +#define BTA_AG_ERR_PHONE_FAILURE 0 /* Phone Failure */ +#define BTA_AG_ERR_NO_CONN_PHONE 1 /* No connection to phone */ +#define BTA_AG_ERR_OP_NOT_ALLOWED 3 /* Operation not allowed */ +#define BTA_AG_ERR_OP_NOT_SUPPORTED 4 /* Operation not supported */ +#define BTA_AG_ERR_PHSIM_PIN_REQ 5 /* PH-SIM PIN required */ +#define BTA_AG_ERR_SIM_NOT_INSERTED 10 /* SIM not inserted */ +#define BTA_AG_ERR_SIM_PIN_REQ 11 /* SIM PIN required */ +#define BTA_AG_ERR_SIM_PUK_REQ 12 /* SIM PUK required */ +#define BTA_AG_ERR_SIM_FAILURE 13 /* SIM failure */ +#define BTA_AG_ERR_SIM_BUSY 14 /* SIM busy */ +#define BTA_AG_ERR_INCORRECT_PWD 16 /* Incorrect password */ +#define BTA_AG_ERR_SIM_PIN2_REQ 17 /* SIM PIN2 required */ +#define BTA_AG_ERR_SIM_PUK2_REQ 18 /* SIM PUK2 required */ +#define BTA_AG_ERR_MEMORY_FULL 20 /* Memory full */ +#define BTA_AG_ERR_INVALID_INDEX 21 /* Invalid index */ +#define BTA_AG_ERR_MEMORY_FAILURE 23 /* Memory failure */ +#define BTA_AG_ERR_TEXT_TOO_LONG 24 /* Text string too long */ +#define BTA_AG_ERR_INV_CHAR_IN_TSTR 25 /* Invalid characters in text string */ +#define BTA_AG_ERR_DSTR_TOO_LONG 26 /* Dial string too long */ +#define BTA_AG_ERR_INV_CHAR_IN_DSTR 27 /* Invalid characters in dial string */ +#define BTA_AG_ERR_NO_NETWORK_SERV 30 /* No network service */ +#define BTA_AG_ERR_NETWORK_TIME_OUT 31 /* Network timeout */ +#define BTA_AG_ERR_NO_NET_EMG_ONLY 32 /* Network not allowed - emergency service only */ +#define BTA_AG_ERR_VOIP_CS_CALLS 33 /* AG cannot create simultaneous VoIP and CS calls */ +#define BTA_AG_ERR_NOT_FOR_VOIP 34 /* Not supported on this call type(VoIP) */ +#define BTA_AG_ERR_SIP_RESP_CODE 35 /* SIP 3 digit response code */ + +#if 0 /* Not Used in Bluetooth HFP 1.5 Specification */ +#define BTA_AG_ERR_PHADAP_LNK_RES 2 /* Phone-adapter link reserved */ +#define BTA_AG_ERR_PHFSIM_PIN_REQ 6 /* PH-FSIM PIN required */ +#define BTA_AG_ERR_PHFSIM_PUK_REQ 7 /* PH-FSIM PUK required */ +#define BTA_AG_ERR_SIM_WRONG 15 /* SIM wrong */ +#define BTA_AG_ERR_NOT_FOUND 22 /* Not found */ +#define BTA_AG_ERR_NETWORK_TIMEOUT 31 /* Network timeout */ +#define BTA_AG_ERR_NET_PIN_REQ 40 /* Network personalization PIN required */ +#define BTA_AG_ERR_NET_PUK_REQ 41 /* Network personalization PUK required */ +#define BTA_AG_ERR_SUBSET_PIN_REQ 42 /* Network subset personalization PIN required */ +#define BTA_AG_ERR_SUBSET_PUK_REQ 43 /* Network subset personalization PUK required */ +#define BTA_AG_ERR_SERVPRO_PIN_REQ 44 /* Service provider personalization PIN required */ +#define BTA_AG_ERR_SERVPRO_PUK_REQ 45 /* Service provider personalization PUK required */ +#define BTA_AG_ERR_CORP_PIN_REQ 46 /* Corporate personalization PIN required */ +#define BTA_AG_ERR_CORP_PUK_REQ 47 /* Corporate personalization PUK required */ +#define BTA_AG_ERR_UNKNOWN 100 /* Unknown error */ +/* GPRS-related errors */ +#define BTA_AG_ERR_ILL_MS 103 /* Illegal MS (#3) */ +#define BTA_AG_ERR_ILL_ME 106 /* Illegal ME (#6) */ +#define BTA_AG_ERR_GPRS_NOT_ALLOWED 107 /* GPRS services not allowed (#7) */ +#define BTA_AG_ERR_PLMN_NOT_ALLOWED 111 /* PLMN services not allowed (#11) */ +#define BTA_AG_ERR_LOC_NOT_ALLOWED 112 /* Location area not allowed (#12) */ +#define BTA_AG_ERR_ROAM_NOT_ALLOWED 113 /* Roaming not allowed in this location area (#13) */ +/* Errors related to a failure to Activate a Context */ +#define BTA_AG_ERR_OPT_NOT_SUPP 132 /* Service option not supported (#32) */ +#define BTA_AG_ERR_OPT_NOT_SUBSCR 133 /* Requested service option not subscribed (#33) */ +#define BTA_AG_ERR_OPT_OUT_OF_ORDER 134 /* Service option temporarily out of order (#34) */ +#define BTA_AG_ERR_PDP_AUTH_FAILURE 149 /* PDP authentication failure */ +/* Other GPRS errors */ +#define BTA_AG_ERR_INV_MOBILE_CLASS 150 /* Invalid mobile class */ +#define BTA_AG_ERR_UNSPEC_GPRS_ERR 148 /* Unspecified GPRS error */ +#endif /* Unused error codes */ + + +/* HFP result data 'ok_flag' */ +#define BTA_AG_OK_CONTINUE 0 /* Send out response (more responses coming) */ +#define BTA_AG_OK_DONE 1 /* Send out response followed by OK (finished) */ +#define BTA_AG_OK_ERROR 2 /* Error response */ + +/* BTRH values */ +#define BTA_AG_BTRH_SET_HOLD 0 /* Put incoming call on hold */ +#define BTA_AG_BTRH_SET_ACC 1 /* Accept incoming call on hold */ +#define BTA_AG_BTRH_SET_REJ 2 /* Reject incoming call on hold */ +#define BTA_AG_BTRH_READ 3 /* Read the current value */ +#define BTA_AG_BTRH_NO_RESP 4 /* Not in RH States (reply to read) */ + +/* ASCII character string of arguments to the AT command or result */ +#ifndef BTA_AG_AT_MAX_LEN +#define BTA_AG_AT_MAX_LEN 256 +#endif + +/* data associated with BTA_AG_IND_RES */ +typedef struct +{ + UINT16 id; + UINT16 value; +} tBTA_AG_IND; + +/* data type for BTA_AgResult() */ +typedef struct +{ + char str[BTA_AG_AT_MAX_LEN+1]; + tBTA_AG_IND ind; + UINT16 num; + UINT16 audio_handle; + UINT16 errcode; /* Valid only if 'ok_flag' is set to BTA_AG_OK_ERROR */ + UINT8 ok_flag; /* Indicates if response is finished, and if error occurred */ + BOOLEAN state; +} tBTA_AG_RES_DATA; + +/* AG callback events */ +#define BTA_AG_ENABLE_EVT 0 /* AG enabled */ +#define BTA_AG_REGISTER_EVT 1 /* AG registered */ +#define BTA_AG_OPEN_EVT 2 /* AG connection open */ +#define BTA_AG_CLOSE_EVT 3 /* AG connection closed */ +#define BTA_AG_CONN_EVT 4 /* Service level connection opened */ +#define BTA_AG_AUDIO_OPEN_EVT 5 /* Audio connection open */ +#define BTA_AG_AUDIO_CLOSE_EVT 6 /* Audio connection closed */ +#define BTA_AG_SPK_EVT 7 /* Speaker volume changed */ +#define BTA_AG_MIC_EVT 8 /* Microphone volume changed */ +#define BTA_AG_AT_CKPD_EVT 9 /* CKPD from the HS */ +#define BTA_AG_DISABLE_EVT 30 /* AG disabled */ + +/* Values below are for HFP only */ +#define BTA_AG_AT_A_EVT 10 /* Answer a call */ +#define BTA_AG_AT_D_EVT 11 /* Place a call using number or memory dial */ +#define BTA_AG_AT_CHLD_EVT 12 /* Call hold */ +#define BTA_AG_AT_CHUP_EVT 13 /* Hang up a call */ +#define BTA_AG_AT_CIND_EVT 14 /* Read indicator settings */ +#define BTA_AG_AT_VTS_EVT 15 /* Transmit DTMF tone */ +#define BTA_AG_AT_BINP_EVT 16 /* Retrieve number from voice tag */ +#define BTA_AG_AT_BLDN_EVT 17 /* Place call to last dialed number */ +#define BTA_AG_AT_BVRA_EVT 18 /* Enable/disable voice recognition */ +#define BTA_AG_AT_NREC_EVT 19 /* Disable echo canceling */ +#define BTA_AG_AT_CNUM_EVT 20 /* Retrieve subscriber number */ +#define BTA_AG_AT_BTRH_EVT 21 /* CCAP-style incoming call hold */ +#define BTA_AG_AT_CLCC_EVT 22 /* Query list of current calls */ +#define BTA_AG_AT_COPS_EVT 23 /* Query list of current calls */ +#define BTA_AG_AT_UNAT_EVT 24 /* Unknown AT command */ +#define BTA_AG_AT_CBC_EVT 25 /* Battery Level report from HF */ +#define BTA_AG_AT_BAC_EVT 26 /* Codec select */ +#define BTA_AG_AT_BCS_EVT 27 /* Codec select */ + +typedef UINT8 tBTA_AG_EVT; + +/* data associated with most non-AT events */ +typedef struct +{ + UINT16 handle; + UINT8 app_id; +} tBTA_AG_HDR; + +/* data associated with BTA_AG_REGISTER_EVT */ +typedef struct +{ + tBTA_AG_HDR hdr; + tBTA_AG_STATUS status; +} tBTA_AG_REGISTER; + +/* data associated with BTA_AG_OPEN_EVT */ +typedef struct +{ + tBTA_AG_HDR hdr; + BD_ADDR bd_addr; + tBTA_SERVICE_ID service_id; + tBTA_AG_STATUS status; +} tBTA_AG_OPEN; + +/* data associated with BTA_AG_CONN_EVT */ +typedef struct +{ + tBTA_AG_HDR hdr; + tBTA_AG_PEER_FEAT peer_feat; + tBTA_AG_PEER_CODEC peer_codec; +} tBTA_AG_CONN; + +/* data associated with AT command event */ +typedef struct +{ + tBTA_AG_HDR hdr; + char str[BTA_AG_AT_MAX_LEN+1]; + UINT16 num; + UINT8 idx; /* call number used by CLCC and CHLD */ +} tBTA_AG_VAL; + +/* union of data associated with AG callback */ +typedef union +{ + tBTA_AG_HDR hdr; + tBTA_AG_REGISTER reg; + tBTA_AG_OPEN open; + tBTA_AG_CONN conn; + tBTA_AG_VAL val; +} tBTA_AG; + +/* AG callback */ +typedef void (tBTA_AG_CBACK)(tBTA_AG_EVT event, tBTA_AG *p_data); + +/* indicator constants HFP 1.1 and later */ +#define BTA_AG_IND_CALL 1 /* position of call indicator */ +#define BTA_AG_IND_CALLSETUP 2 /* position of callsetup indicator */ +#define BTA_AG_IND_SERVICE 3 /* position of service indicator */ + +/* indicator constants HFP 1.5 and later */ +#define BTA_AG_IND_SIGNAL 4 /* position of signal strength indicator */ +#define BTA_AG_IND_ROAM 5 /* position of roaming indicator */ +#define BTA_AG_IND_BATTCHG 6 /* position of battery charge indicator */ +#define BTA_AG_IND_CALLHELD 7 /* position of callheld indicator */ +#define BTA_AG_IND_BEARER 8 /* position of bearer indicator */ + +/* call indicator values */ +#define BTA_AG_CALL_INACTIVE 0 /* Phone call inactive */ +#define BTA_AG_CALL_ACTIVE 1 /* Phone call active */ + +/* callsetup indicator values */ +#define BTA_AG_CALLSETUP_NONE 0 /* Not currently in call set up */ +#define BTA_AG_CALLSETUP_INCOMING 1 /* Incoming call process ongoing */ +#define BTA_AG_CALLSETUP_OUTGOING 2 /* Outgoing call set up is ongoing */ +#define BTA_AG_CALLSETUP_ALERTING 3 /* Remote party being alerted in an outgoing call */ + +/* service indicator values */ +#define BTA_AG_SERVICE_NONE 0 /* Neither CS nor VoIP service is available */ +#define BTA_AG_SERVICE_CS 1 /* Only CS service is available */ +#define BTA_AG_SERVICE_VOIP 2 /* Only VoIP service is available */ +#define BTA_AG_SERVICE_CS_VOIP 3 /* Both CS and VoIP services available */ + +/* callheld indicator values */ +#define BTA_AG_CALLHELD_INACTIVE 0 /* No held calls */ +#define BTA_AG_CALLHELD_ACTIVE 1 /* Call held and call active */ +#define BTA_AG_CALLHELD_NOACTIVE 2 /* Call held and no call active */ + +/* signal strength indicator values */ +#define BTA_AG_ROAMING_INACTIVE 0 /* Phone call inactive */ +#define BTA_AG_ROAMING_ACTIVE 1 /* Phone call active */ + +/* bearer indicator values */ +#define BTA_AG_BEARER_WLAN 0 /* WLAN */ +#define BTA_AG_BEARER_BLUETOOTH 1 /* Bluetooth */ +#define BTA_AG_BEARER_WIRED 2 /* Wired */ +#define BTA_AG_BEARER_2G3G 3 /* 2G 3G */ +#define BTA_AG_BEARER_WIMAX 4 /* WIMAX */ +#define BTA_AG_BEARER_RES1 5 /* Reserved */ +#define BTA_AG_BEARER_RES2 6 /* Reserved */ +#define BTA_AG_BEARER_RES3 7 /* Reserved */ + +/* AG configuration structure */ +typedef struct +{ + char *cind_info; + INT32 conn_tout; + UINT16 sco_pkt_types; + char *chld_val_ecc; + char *chld_val; +} tBTA_AG_CFG; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function BTA_AgEnable +** +** Description Enable the audio gateway service. When the enable +** operation is complete the callback function will be +** called with a BTA_AG_ENABLE_EVT. This function must +** be called before other function in the AG API are +** called. +** +** Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise. +** +*******************************************************************************/ +BTA_API tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_AgDisable +** +** Description Disable the audio gateway service +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgDisable(void); + +/******************************************************************************* +** +** Function BTA_AgRegister +** +** Description Register an Audio Gateway service. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask, + tBTA_AG_FEAT features, char *p_service_names[], UINT8 app_id); + +/******************************************************************************* +** +** Function BTA_AgDeregister +** +** Description Deregister an audio gateway service. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgDeregister(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_AgOpen +** +** Description Opens a connection to a headset or hands-free device. +** When connection is open callback function is called +** with a BTA_AG_OPEN_EVT. Only the data connection is +** opened. The audio connection is not opened. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services); + +/******************************************************************************* +** +** Function BTA_AgClose +** +** Description Close the current connection to a headset or a handsfree +** Any current audio connection will also be closed +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgClose(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_AgAudioOpen +** +** Description Opens an audio connection to the currently connected +** headset or hnadsfree +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgAudioOpen(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_AgAudioClose +** +** Description Close the currently active audio connection to a headset +** or hnadsfree. The data connection remains open +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgAudioClose(UINT16 handle); + +/******************************************************************************* +** +** Function BTA_AgResult +** +** Description Send an AT result code to a headset or hands-free device. +** This function is only used when the AG parse mode is set +** to BTA_AG_PARSE. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data); + +/******************************************************************************* +** +** Function BTA_AgSetCodec +** +** Description Specify the codec type to be used for the subsequent +** audio connection. +** +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec); + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_AG_API_H */ + + diff --git a/bta/include/bta_ag_ci.h b/bta/include/bta_ag_ci.h new file mode 100644 index 0000000..3bc0e53 --- /dev/null +++ b/bta/include/bta_ag_ci.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 interface file for audio gateway call-in functions. + * + ******************************************************************************/ +#ifndef BTA_AG_CI_H +#define BTA_AG_CI_H + +#include "bta_ag_api.h" + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_ag_ci_rx_write +** +** Description This function is called to send data to the AG when the AG +** is configured for AT command pass-through. The function +** copies data to an event buffer and sends it. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len); + +/****************************************************************************** +** +** Function bta_ag_ci_slc_ready +** +** Description This function is called to notify AG that SLC is up at +** the application. This funcion is only used when the app +** is running in pass-through mode. +** +** Returns void +** +******************************************************************************/ +BTA_API extern void bta_ag_ci_slc_ready(UINT16 handle); + +// btla-specific ++ +/****************************************************************************** +** +** Function bta_ag_ci_wbs_command +** +** Description This function is called to notify AG that a WBS command is +** received +** +** Returns void +** +******************************************************************************/ +BTA_API extern void bta_ag_ci_wbs_command (UINT16 handle, char *p_data, UINT16 len); +// btla-specific -- + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_AG_CI_H */ + diff --git a/bta/include/bta_ag_co.h b/bta/include/bta_ag_co.h new file mode 100644 index 0000000..c6a3392 --- /dev/null +++ b/bta/include/bta_ag_co.h @@ -0,0 +1,112 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 interface file for audio gateway call-out functions. + * + ******************************************************************************/ +#ifndef BTA_AG_CO_H +#define BTA_AG_CO_H + +#include "bta_ag_api.h" + +/* Definitions for audio state callout function "state" parameter */ +#define BTA_AG_CO_AUD_STATE_OFF 0 +#define BTA_AG_CO_AUD_STATE_OFF_XFER 1 /* Closed pending transfer of audio */ +#define BTA_AG_CO_AUD_STATE_ON 2 +#define BTA_AG_CO_AUD_STATE_SETUP 3 + +/******************************************************************************* +** +** 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. +** +*******************************************************************************/ +BTA_API extern void bta_ag_co_init(void); + +/******************************************************************************* +** +** 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 is closed pending transfer +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_ag_co_audio_state(UINT16 handle, UINT8 app_id, UINT8 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 +** +*******************************************************************************/ +BTA_API extern void bta_ag_co_data_open(UINT16 handle, tBTA_SERVICE_ID service); + +/******************************************************************************* +** +** Function bta_ag_co_data_close +** +** Description This function is called by AG when a service level +** connection is closed +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_ag_co_data_close(UINT16 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 phone’s memory. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_ag_co_tx_write(UINT16 handle, UINT8 *p_data, UINT16 len); + +#endif /* BTA_AG_CO_H */ + diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h new file mode 100644 index 0000000..81dff39 --- /dev/null +++ b/bta/include/bta_api.h @@ -0,0 +1,1730 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 public interface file for BTA, Broadcom's Bluetooth + * application layer for mobile phones. + * + ******************************************************************************/ +#ifndef BTA_API_H +#define BTA_API_H + +#include "data_types.h" +#include "bt_target.h" +#include "bt_types.h" +#include "btm_api.h" +#include "uipc_msg.h" + +#if BLE_INCLUDED == TRUE +#include "btm_ble_api.h" +#endif + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* Status Return Value */ +#define BTA_SUCCESS 0 /* Successful operation. */ +#define BTA_FAILURE 1 /* Generic failure. */ +#define BTA_PENDING 2 /* API cannot be completed right now */ +#define BTA_BUSY 3 +#define BTA_NO_RESOURCES 4 +#define BTA_WRONG_MODE 5 + +typedef UINT8 tBTA_STATUS; + +/* + * Service ID + * + * NOTES: When you add a new Service ID for BTA AND require to change the value of BTA_MAX_SERVICE_ID, + * make sure that the correct security ID of the new service from Security service definitions (btm_api.h) + * should be added to bta_service_id_to_btm_srv_id_lkup_tbl table in bta_dm_act.c. + */ + +#define BTA_RES_SERVICE_ID 0 /* Reserved */ +#define BTA_SPP_SERVICE_ID 1 /* Serial port profile. */ +#define BTA_DUN_SERVICE_ID 2 /* Dial-up networking profile. */ +#define BTA_A2DP_SOURCE_SERVICE_ID 3 /* A2DP Source profile. */ +#define BTA_LAP_SERVICE_ID 4 /* LAN access profile. */ +#define BTA_HSP_SERVICE_ID 5 /* Headset profile. */ +#define BTA_HFP_SERVICE_ID 6 /* Hands-free profile. */ +#define BTA_OPP_SERVICE_ID 7 /* Object push */ +#define BTA_FTP_SERVICE_ID 8 /* File transfer */ +#define BTA_CTP_SERVICE_ID 9 /* Cordless Terminal */ +#define BTA_ICP_SERVICE_ID 10 /* Intercom Terminal */ +#define BTA_SYNC_SERVICE_ID 11 /* Synchronization */ +#define BTA_BPP_SERVICE_ID 12 /* Basic printing profile */ +#define BTA_BIP_SERVICE_ID 13 /* Basic Imaging profile */ +#define BTA_PANU_SERVICE_ID 14 /* PAN User */ +#define BTA_NAP_SERVICE_ID 15 /* PAN Network access point */ +#define BTA_GN_SERVICE_ID 16 /* PAN Group Ad-hoc networks */ +#define BTA_SAP_SERVICE_ID 17 /* SIM Access profile */ +#define BTA_A2DP_SERVICE_ID 18 /* A2DP Sink */ +#define BTA_AVRCP_SERVICE_ID 19 /* A/V remote control */ +#define BTA_HID_SERVICE_ID 20 /* HID */ +#define BTA_VDP_SERVICE_ID 21 /* Video distribution */ +#define BTA_PBAP_SERVICE_ID 22 /* PhoneBook Access Server*/ +#define BTA_HSP_HS_SERVICE_ID 23 /* HFP HS role */ +#define BTA_HFP_HS_SERVICE_ID 24 /* HSP HS role */ +#define BTA_MAP_SERVICE_ID 25 /* Message Access Profile */ +#define BTA_MN_SERVICE_ID 26 /* Message Notification Service */ +#define BTA_HDP_SERVICE_ID 27 /* Health Device Profile */ +#define BTA_PCE_SERVICE_ID 28 /* PhoneBook Access Client*/ + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE +/* BLE profile service ID */ +#define BTA_BLE_SERVICE_ID 29 /* GATT profile */ + +// btla-specific ++ +#define BTA_USER_SERVICE_ID 30 /* User requested UUID */ + +#define BTA_MAX_SERVICE_ID 31 +// btla-specific -- +#else +#define BTA_USER_SERVICE_ID 29 /* User requested UUID */ +#define BTA_MAX_SERVICE_ID 30 +#endif +/* service IDs (BTM_SEC_SERVICE_FIRST_EMPTY + 1) to (BTM_SEC_MAX_SERVICES - 1) + * are used by BTA JV */ +#define BTA_FIRST_JV_SERVICE_ID (BTM_SEC_SERVICE_FIRST_EMPTY + 1) +#define BTA_LAST_JV_SERVICE_ID (BTM_SEC_MAX_SERVICES - 1) + +typedef UINT8 tBTA_SERVICE_ID; + +/* Service ID Mask */ +#define BTA_RES_SERVICE_MASK 0x00000001 /* Reserved */ +#define BTA_SPP_SERVICE_MASK 0x00000002 /* Serial port profile. */ +#define BTA_DUN_SERVICE_MASK 0x00000004 /* Dial-up networking profile. */ +#define BTA_FAX_SERVICE_MASK 0x00000008 /* Fax profile. */ +#define BTA_LAP_SERVICE_MASK 0x00000010 /* LAN access profile. */ +#define BTA_HSP_SERVICE_MASK 0x00000020 /* HSP AG role. */ +#define BTA_HFP_SERVICE_MASK 0x00000040 /* HFP AG role */ +#define BTA_OPP_SERVICE_MASK 0x00000080 /* Object push */ +#define BTA_FTP_SERVICE_MASK 0x00000100 /* File transfer */ +#define BTA_CTP_SERVICE_MASK 0x00000200 /* Cordless Terminal */ +#define BTA_ICP_SERVICE_MASK 0x00000400 /* Intercom Terminal */ +#define BTA_SYNC_SERVICE_MASK 0x00000800 /* Synchronization */ +#define BTA_BPP_SERVICE_MASK 0x00001000 /* Print server */ +#define BTA_BIP_SERVICE_MASK 0x00002000 /* Basic Imaging */ +#define BTA_PANU_SERVICE_MASK 0x00004000 /* PAN User */ +#define BTA_NAP_SERVICE_MASK 0x00008000 /* PAN Network access point */ +#define BTA_GN_SERVICE_MASK 0x00010000 /* PAN Group Ad-hoc networks */ +#define BTA_SAP_SERVICE_MASK 0x00020000 /* PAN Group Ad-hoc networks */ +#define BTA_A2DP_SERVICE_MASK 0x00040000 /* Advanced audio distribution */ +#define BTA_AVRCP_SERVICE_MASK 0x00080000 /* A/V remote control */ +#define BTA_HID_SERVICE_MASK 0x00100000 /* HID */ +#define BTA_VDP_SERVICE_MASK 0x00200000 /* Video distribution */ +#define BTA_PBAP_SERVICE_MASK 0x00400000 /* Phone Book Server */ +#define BTA_HSP_HS_SERVICE_MASK 0x00800000 /* HFP HS role */ +#define BTA_HFP_HS_SERVICE_MASK 0x01000000 /* HSP HS role */ +#define BTA_MAS_SERVICE_MASK 0x02000000 /* Message Access Profile */ +#define BTA_MN_SERVICE_MASK 0x04000000 /* Message Notification Profile */ +#define BTA_HL_SERVICE_MASK 0x08000000 /* Health Device Profile */ +#define BTA_PCE_SERVICE_MASK 0x10000000 /* Phone Book Client */ + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE +#define BTA_BLE_SERVICE_MASK 0x20000000 /* GATT based service */ +// btla-specific ++ +#define BTA_USER_SERVICE_MASK 0x40000000 /* Message Notification Profile */ +// btla-specific -- +#else +// btla-specific ++ +#define BTA_USER_SERVICE_MASK 0x20000000 /* Message Notification Profile */ +// btla-specific -- +#endif + +#if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE +#define BTA_ALL_SERVICE_MASK 0x3FFFFFFF /* All services supported by BTA. */ +#else +#define BTA_ALL_SERVICE_MASK 0x1FFFFFFF /* All services supported by BTA. */ +#endif + +typedef UINT32 tBTA_SERVICE_MASK; + +/* extended service mask, including mask with one or more GATT UUID */ +typedef struct +{ + tBTA_SERVICE_MASK srvc_mask; + UINT8 num_uuid; + tBT_UUID *p_uuid; +}tBTA_SERVICE_MASK_EXT; + +/* Security Setting Mask */ +#define BTA_SEC_NONE BTM_SEC_NONE /* No security. */ +#define BTA_SEC_AUTHORIZE (BTM_SEC_IN_AUTHORIZE ) /* Authorization required (only needed for out going connection )*/ +#define BTA_SEC_AUTHENTICATE (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE) /* Authentication required. */ +#define BTA_SEC_ENCRYPT (BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT) /* Encryption required. */ + +typedef UINT8 tBTA_SEC; + +/* Ignore for Discoverable, Connectable, Pairable and Connectable Paired only device modes */ + +#define BTA_DM_IGNORE 0xFF + + +/* Discoverable Modes */ +#define BTA_DM_NON_DISC BTM_NON_DISCOVERABLE /* Device is not discoverable. */ +#define BTA_DM_GENERAL_DISC BTM_GENERAL_DISCOVERABLE /* General discoverable. */ +#define BTA_DM_LIMITED_DISC BTM_LIMITED_DISCOVERABLE /* Limited discoverable. */ + +// btla-specific ++ +typedef UINT16 tBTA_DM_DISC; +// btla-specific -- + +/* Connectable Modes */ +#define BTA_DM_NON_CONN BTM_NON_CONNECTABLE /* Device is not connectable. */ +#define BTA_DM_CONN BTM_CONNECTABLE /* Device is connectable. */ + +// btla-specific ++ +typedef UINT16 tBTA_DM_CONN; +// btla-specific -- + +/* Pairable Modes */ +#define BTA_DM_PAIRABLE 1 +#define BTA_DM_NON_PAIRABLE 0 + +/* Connectable Paired Only Mode */ +#define BTA_DM_CONN_ALL 0 +#define BTA_DM_CONN_PAIRED 1 + +/* Inquiry Modes */ +#define BTA_DM_GENERAL_INQUIRY BTM_GENERAL_INQUIRY /* Perform general inquiry. */ +#define BTA_DM_LIMITED_INQUIRY BTM_LIMITED_INQUIRY /* Perform limited inquiry. */ + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +#define BTA_BLE_INQUIRY_NONE BTM_BLE_INQUIRY_NONE +#define BTA_BLE_GENERAL_INQUIRY BTM_BLE_GENERAL_INQUIRY /* Perform LE general inquiry. */ +#define BTA_BLE_LIMITED_INQUIRY BTM_BLE_LIMITED_INQUIRY /* Perform LE limited inquiry. */ +#endif +typedef UINT8 tBTA_DM_INQ_MODE; + +/* Inquiry Filter Type */ +#define BTA_DM_INQ_CLR BTM_CLR_INQUIRY_FILTER /* Clear inquiry filter. */ +#define BTA_DM_INQ_DEV_CLASS BTM_FILTER_COND_DEVICE_CLASS /* Filter on device class. */ +#define BTA_DM_INQ_BD_ADDR BTM_FILTER_COND_BD_ADDR /* Filter on a specific BD address. */ + +typedef UINT8 tBTA_DM_INQ_FILT; + +/* Authorize Response */ +#define BTA_DM_AUTH_PERM 0 /* Authorized for future connections to the service */ +#define BTA_DM_AUTH_TEMP 1 /* Authorized for current connection only */ +#define BTA_DM_NOT_AUTH 2 /* Not authorized for the service */ + +typedef UINT8 tBTA_AUTH_RESP; + +/* M/S preferred roles */ +#define BTA_ANY_ROLE 0x00 +#define BTA_MASTER_ROLE_PREF 0x01 +#define BTA_MASTER_ROLE_ONLY 0x02 + +typedef UINT8 tBTA_PREF_ROLES; + +enum +{ + + BTA_DM_NO_SCATTERNET, /* Device doesn't support scatternet, it might + support "role switch during connection" for + an incoming connection, when it already has + another connection in master role */ + BTA_DM_PARTIAL_SCATTERNET, /* Device supports partial scatternet. It can have + simulateous connection in Master and Slave roles + for short period of time */ + BTA_DM_FULL_SCATTERNET /* Device can have simultaneous connection in master + and slave roles */ + +}; + + +/* Inquiry filter device class condition */ +typedef struct +{ + DEV_CLASS dev_class; /* device class of interest */ + DEV_CLASS dev_class_mask; /* mask to determine the bits of device class of interest */ +} tBTA_DM_COD_COND; + + +/* Inquiry Filter Condition */ +typedef union +{ + BD_ADDR bd_addr; /* BD address of device to filter. */ + tBTA_DM_COD_COND dev_class_cond; /* Device class filter condition */ +} tBTA_DM_INQ_COND; + +/* Inquiry Parameters */ +typedef struct +{ + tBTA_DM_INQ_MODE mode; /* Inquiry mode, limited or general. */ + UINT8 duration; /* Inquiry duration in 1.28 sec units. */ + UINT8 max_resps; /* Maximum inquiry responses. Set to zero for unlimited responses. */ + BOOLEAN report_dup; /* report duplicated inquiry response with higher RSSI value */ + tBTA_DM_INQ_FILT filter_type; /* Filter condition type. */ + tBTA_DM_INQ_COND filter_cond; /* Filter condition data. */ +} tBTA_DM_INQ; + +typedef struct +{ + UINT8 bta_dm_eir_min_name_len; /* minimum length of local name when it is shortened */ +#if (BTA_EIR_CANNED_UUID_LIST == TRUE) + UINT8 bta_dm_eir_uuid16_len; /* length of 16-bit UUIDs */ + UINT8 *bta_dm_eir_uuid16; /* 16-bit UUIDs */ +#else + UINT32 uuid_mask[BTM_EIR_SERVICE_ARRAY_SIZE]; /* mask of UUID list in EIR */ +#endif + INT8 *bta_dm_eir_inq_tx_power; /* Inquiry TX power */ + UINT8 bta_dm_eir_flag_len; /* length of flags in bytes */ + UINT8 *bta_dm_eir_flags; /* flags for EIR */ + UINT8 bta_dm_eir_manufac_spec_len; /* length of manufacturer specific in bytes */ + UINT8 *bta_dm_eir_manufac_spec; /* manufacturer specific */ +} tBTA_DM_EIR_CONF; + +#if BLE_INCLUDED == TRUE +/* ADV data flag bit definition used for BTM_BLE_AD_TYPE_FLAG */ +#define BTA_BLE_LIMIT_DISC_FLAG BTM_BLE_LIMIT_DISC_FLAG +#define BTA_BLE_GEN_DISC_FLAG BTM_BLE_GEN_DISC_FLAG +#define BTA_BLE_BREDR_NOT_SPT BTM_BLE_BREDR_NOT_SPT +#define BTA_BLE_NON_LIMIT_DISC_FLAG BTM_BLE_NON_LIMIT_DISC_FLAG +#define BTA_BLE_ADV_FLAG_MASK BTM_BLE_ADV_FLAG_MASK +#define BTA_BLE_LIMIT_DISC_MASK BTM_BLE_LIMIT_DISC_MASK + +#define BTA_BLE_AD_BIT_DEV_NAME BTM_BLE_AD_BIT_DEV_NAME +#define BTA_BLE_AD_BIT_FLAGS BTM_BLE_AD_BIT_FLAGS +#define BTA_BLE_AD_BIT_MANU BTM_BLE_AD_BIT_MANU +#define BTA_BLE_AD_BIT_TX_PWR BTM_BLE_AD_BIT_TX_PWR +#define BTA_BLE_AD_BIT_ATTR BTM_BLE_AD_BIT_ATTR +#define BTA_BLE_AD_BIT_INT_RANGE BTM_BLE_AD_BIT_INT_RANGE +#define BTA_BLE_AD_BIT_SERVICE BTM_BLE_AD_BIT_SERVICE +#define BTA_BLE_AD_BIT_SERVICE_SOL BTM_BLE_AD_BIT_SERVICE_SOL +#define BTA_BLE_AD_BIT_SERVICE_DATA BTM_BLE_AD_BIT_SERVICE_DATA +#define BTA_BLE_AD_BIT_SIGN_DATA BTM_BLE_AD_BIT_SIGN_DATA +typedef UINT16 tBTA_BLE_AD_MASK; + +/* slave preferred connection interval range */ +typedef struct +{ + UINT16 low; + UINT16 hi; + +}tBTA_BLE_INT_RANGE; + +/* Service tag supported in the device */ +typedef struct +{ + UINT8 num_service; + BOOLEAN list_cmpl; + UINT16 *p_uuid; +}tBTA_BLE_SERVICE; + +/* attribute data */ +typedef struct +{ + UINT16 uuid; + UINT16 data_len; + UINT8 *p_data; +}tBTA_BLE_ATTR; + +#define BTA_BLE_NUM_AD_ATTR_MAX BTM_BLE_NUM_AD_ATTR_MAX + +/* attribute list contained in adv data */ +typedef struct +{ + UINT8 num_attr; + tBTA_BLE_ATTR attr_list[BTA_BLE_NUM_AD_ATTR_MAX]; +}tBTA_BLE_ATTR_DATA; + +typedef struct +{ + UINT8 len; + UINT8 *p_val; +}tBTA_BLE_MANU; + +typedef struct +{ + tBTA_BLE_MANU manu; /* manufactuer data */ + tBTA_BLE_INT_RANGE int_range; /* slave prefered conn interval range */ + tBTA_BLE_SERVICE services; /* services */ + tBTA_BLE_ATTR_DATA attr; /* attribute data */ + UINT8 flag; +}tBTA_BLE_ADV_DATA; + +/* These are the fields returned in each device adv packet. It +** is returned in the results callback if registered. +*/ +typedef struct +{ + UINT8 conn_mode; + tBTA_BLE_AD_MASK ad_mask; /* mask of the valid adv data field */ + UINT8 flag; + UINT8 tx_power_level; + UINT8 remote_name_len; + UINT8 *p_remote_name; + tBTA_BLE_ATTR_DATA attr_data; + tBTA_BLE_SERVICE service; +} tBTA_BLE_INQ_DATA; +#endif + +typedef INT8 tBTA_DM_RSSI_VALUE; +typedef UINT8 tBTA_DM_LINK_QUALITY_VALUE; + + +/* signal strength mask */ +#define BTA_SIG_STRENGTH_RSSI_MASK 1 +#define BTA_SIG_STRENGTH_LINK_QUALITY_MASK 2 + +typedef UINT8 tBTA_SIG_STRENGTH_MASK; + + +/* Security Callback Events */ +#define BTA_DM_ENABLE_EVT 0 /* Enable Event */ +#define BTA_DM_DISABLE_EVT 1 /* Disable Event */ +#define BTA_DM_PIN_REQ_EVT 2 /* PIN request. */ +#define BTA_DM_AUTH_CMPL_EVT 3 /* Authentication complete indication. */ +#define BTA_DM_AUTHORIZE_EVT 4 /* Authorization request. */ +#define BTA_DM_LINK_UP_EVT 5 /* Connection UP event */ +#define BTA_DM_LINK_DOWN_EVT 6 /* Connection DOWN event */ +#define BTA_DM_SIG_STRENGTH_EVT 7 /* Signal strength for bluetooth connection */ +#define BTA_DM_BUSY_LEVEL_EVT 8 /* System busy level */ +#define BTA_DM_BOND_CANCEL_CMPL_EVT 9 /* Bond cancel complete indication */ +#define BTA_DM_SP_CFM_REQ_EVT 10 /* Simple Pairing User Confirmation request. */ +#define BTA_DM_SP_KEY_NOTIF_EVT 11 /* Simple Pairing Passkey Notification */ +#define BTA_DM_SP_RMT_OOB_EVT 12 /* Simple Pairing Remote OOB Data request. */ +#define BTA_DM_SP_KEYPRESS_EVT 13 /* Key press notification event. */ +#define BTA_DM_ROLE_CHG_EVT 14 /* Role Change event. */ +#define BTA_DM_BLE_KEY_EVT 15 /* BLE SMP key event for peer device keys */ +#define BTA_DM_BLE_SEC_REQ_EVT 16 /* BLE SMP security request */ +#define BTA_DM_BLE_PASSKEY_NOTIF_EVT 17 /* SMP passkey notification event */ +#define BTA_DM_BLE_PASSKEY_REQ_EVT 18 /* SMP passkey request event */ +#define BTA_DM_BLE_OOB_REQ_EVT 19 /* SMP OOB request event */ +#define BTA_DM_BLE_LOCAL_IR_EVT 20 /* BLE local IR event */ +#define BTA_DM_BLE_LOCAL_ER_EVT 21 /* BLE local ER event */ +// btla-specific ++ +#define BTA_DM_BLE_AUTH_CMPL_EVT 22 /* BLE Auth complete */ +// btla-specific -- +#define BTA_DM_DEV_UNPAIRED_EVT 23 +#define BTA_DM_HW_ERROR_EVT 24 /* BT Chip H/W error */ +typedef UINT8 tBTA_DM_SEC_EVT; + +/* Structure associated with BTA_DM_ENABLE_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address of local device. */ + tBTA_STATUS status; +} tBTA_DM_ENABLE; + +/* Structure associated with BTA_DM_PIN_REQ_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + DEV_CLASS dev_class; /* Class of Device */ +} tBTA_DM_PIN_REQ; + +/* BLE related definition */ + +#define BTA_DM_AUTH_FAIL_BASE (HCI_ERR_MAX_ERR + 10) +#define BTA_DM_AUTH_CONVERT_SMP_CODE(x) (BTA_DM_AUTH_FAIL_BASE + (x)) +#define BTA_DM_AUTH_SMP_PASSKEY_FAIL BTA_DM_AUTH_CONVERT_SMP_CODE (SMP_PASSKEY_ENTRY_FAIL) +#define BTA_DM_AUTH_SMP_OOB_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_OOB_FAIL) +#define BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_AUTH_FAIL) +#define BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_VALUE_ERR) +#define BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_NOT_SUPPORT) +#define BTA_DM_AUTH_SMP_ENC_KEY_SIZE (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_KEY_SIZE) +#define BTA_DM_AUTH_SMP_INVALID_CMD (BTA_DM_AUTH_FAIL_BASE + SMP_INVALID_CMD) +#define BTA_DM_AUTH_SMP_UNKNOWN_ERR (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_FAIL_UNKNOWN) +#define BTA_DM_AUTH_SMP_REPEATED_ATTEMPT (BTA_DM_AUTH_FAIL_BASE + SMP_REPEATED_ATTEMPTS) +#define BTA_DM_AUTH_SMP_INTERNAL_ERR (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_INTERNAL_ERR) +#define BTA_DM_AUTH_SMP_UNKNOWN_IO (BTA_DM_AUTH_FAIL_BASE + SMP_UNKNOWN_IO_CAP) +#define BTA_DM_AUTH_SMP_INIT_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_INIT_FAIL) +#define BTA_DM_AUTH_SMP_CONFIRM_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_FAIL) +#define BTA_DM_AUTH_SMP_BUSY (BTA_DM_AUTH_FAIL_BASE + SMP_BUSY) +#define BTA_DM_AUTH_SMP_ENC_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_FAIL) +#define BTA_DM_AUTH_SMP_RSP_TIMEOUT (BTA_DM_AUTH_FAIL_BASE + SMP_RSP_TIMEOUT) + +/* connection parameter boundary value and dummy value */ +#define BTA_DM_BLE_SCAN_INT_MIN BTM_BLE_SCAN_INT_MIN +#define BTA_DM_BLE_SCAN_INT_MAX BTM_BLE_SCAN_INT_MAX +#define BTA_DM_BLE_SCAN_WIN_MIN BTM_BLE_SCAN_WIN_MIN +#define BTA_DM_BLE_SCAN_WIN_MAX BTM_BLE_SCAN_WIN_MAX +#define BTA_DM_BLE_CONN_INT_MIN BTM_BLE_CONN_INT_MIN +#define BTA_DM_BLE_CONN_INT_MAX BTM_BLE_CONN_INT_MAX +#define BTA_DM_BLE_CONN_LATENCY_MAX BTM_BLE_CONN_LATENCY_MAX +#define BTA_DM_BLE_CONN_SUP_TOUT_MIN BTM_BLE_CONN_SUP_TOUT_MIN +#define BTA_DM_BLE_CONN_SUP_TOUT_MAX BTM_BLE_CONN_SUP_TOUT_MAX +#define BTA_DM_BLE_CONN_PARAM_UNDEF BTM_BLE_CONN_PARAM_UNDEF /* use this value when a specific value not to be overwritten */ + + +#define BTA_LE_KEY_PENC BTM_LE_KEY_PENC /* encryption information of peer device */ +#define BTA_LE_KEY_PID BTM_LE_KEY_PID /* identity key of the peer device */ +#define BTA_LE_KEY_PCSRK BTM_LE_KEY_PCSRK /* peer SRK */ +#define BTA_LE_KEY_LENC BTM_LE_KEY_LENC /* master role security information:div */ +#define BTA_LE_KEY_LID BTM_LE_KEY_LID /* master device ID key */ +#define BTA_LE_KEY_LCSRK BTM_LE_KEY_LCSRK /* local CSRK has been deliver to peer */ +typedef UINT8 tBTA_LE_KEY_TYPE; /* can be used as a bit mask */ + + +typedef tBTM_LE_PENC_KEYS tBTA_LE_PENC_KEYS ; +typedef tBTM_LE_PCSRK_KEYS tBTA_LE_PCSRK_KEYS; +typedef tBTM_LE_LENC_KEYS tBTA_LE_LENC_KEYS ; +typedef tBTM_LE_LCSRK_KEYS tBTA_LE_LCSRK_KEYS ; + +typedef union +{ + tBTA_LE_PENC_KEYS penc_key; /* received peer encryption key */ + tBTA_LE_PCSRK_KEYS psrk_key; /* received peer device SRK */ + BT_OCTET16 pid_key; /* peer device ID key */ + tBTA_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/ + tBTA_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/ +}tBTA_LE_KEY_VALUE; + +#define BTA_BLE_LOCAL_KEY_TYPE_ID 1 +#define BTA_BLE_LOCAL_KEY_TYPE_ER 2 +typedef UINT8 tBTA_DM_BLE_LOCAL_KEY_MASK; + +typedef struct +{ + BT_OCTET16 ir; + BT_OCTET16 irk; + BT_OCTET16 dhk; +}tBTA_BLE_LOCAL_ID_KEYS; + +#define BTA_DM_SEC_GRANTED BTA_SUCCESS +#define BTA_DM_SEC_PAIR_NOT_SPT BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT +#define BTA_DM_SEC_REP_ATTEMPTS BTA_DM_AUTH_SMP_REPEATED_ATTEMPT +typedef UINT8 tBTA_DM_BLE_SEC_GRANT; + + +#define BTA_DM_BLE_ONN_NONE BTM_BLE_CONN_NONE +#define BTA_DM_BLE_CONN_AUTO BTM_BLE_CONN_AUTO +#define BTA_DM_BLE_CONN_SELECTIVE BTM_BLE_CONN_SELECTIVE +typedef UINT8 tBTA_DM_BLE_CONN_TYPE; + +typedef BOOLEAN (tBTA_DM_BLE_SEL_CBACK)(BD_ADDR random_bda, UINT8 *p_remote_name); + +/* Structure associated with BTA_DM_BLE_SEC_REQ_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + BD_NAME bd_name; /* peer device name */ +} tBTA_DM_BLE_SEC_REQ; + +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + tBTM_LE_KEY_TYPE key_type; + tBTM_LE_KEY_VALUE key_value; +}tBTA_DM_BLE_KEY; + +/* Structure associated with BTA_DM_AUTH_CMPL_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + BOOLEAN key_present; /* Valid link key value in key element */ + LINK_KEY key; /* Link key associated with peer device. */ + UINT8 key_type; /* The type of Link Key */ + BOOLEAN success; /* TRUE of authentication succeeded, FALSE if failed. */ + UINT8 fail_reason; /* The HCI reason/error code for when success=FALSE */ + +} tBTA_DM_AUTH_CMPL; + + +/* Structure associated with BTA_DM_AUTHORIZE_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + tBTA_SERVICE_ID service; /* Service ID to authorize. */ +// btla-specific ++ + DEV_CLASS dev_class; +// btla-specific -- +} tBTA_DM_AUTHORIZE; + +/* Structure associated with BTA_DM_LINK_UP_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ +} tBTA_DM_LINK_UP; + +/* Structure associated with BTA_DM_LINK_DOWN_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + UINT8 status; /* connection open/closed */ +} tBTA_DM_LINK_DOWN; + +/* Structure associated with BTA_DM_ROLE_CHG_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + UINT8 new_role; /* the new connection role */ +} tBTA_DM_ROLE_CHG; + +/* Structure associated with BTA_DM_SIG_STRENGTH_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + tBTA_SIG_STRENGTH_MASK mask; /* mask for the values that are valid */ + tBTA_DM_RSSI_VALUE rssi_value; + tBTA_DM_LINK_QUALITY_VALUE link_quality_value; + +} tBTA_DM_SIG_STRENGTH; + +/* Structure associated with BTA_DM_BUSY_LEVEL_EVT */ +typedef struct +{ + UINT8 level; /* when paging or inquiring, level is 10. + Otherwise, the number of ACL links */ +} tBTA_DM_BUSY_LEVEL; + +#define BTA_IO_CAP_OUT BTM_IO_CAP_OUT /* DisplayOnly */ +#define BTA_IO_CAP_IO BTM_IO_CAP_IO /* DisplayYesNo */ +#define BTA_IO_CAP_IN BTM_IO_CAP_IN /* KeyboardOnly */ +#define BTA_IO_CAP_NONE BTM_IO_CAP_NONE /* NoInputNoOutput */ +typedef tBTM_IO_CAP tBTA_IO_CAP; + +#define BTA_AUTH_SP_NO BTM_AUTH_SP_NO /* 0 MITM Protection Not Required - Single Profile/non-bonding + Numeric comparison with automatic accept allowed */ +#define BTA_AUTH_SP_YES BTM_AUTH_SP_YES /* 1 MITM Protection Required - Single Profile/non-bonding + Use IO Capabilities to determine authentication procedure */ +#define BTA_AUTH_AP_NO BTM_AUTH_AP_NO /* 2 MITM Protection Not Required - All Profiles/dedicated bonding + Numeric comparison with automatic accept allowed */ +#define BTA_AUTH_AP_YES BTM_AUTH_AP_YES /* 3 MITM Protection Required - All Profiles/dedicated bonding + Use IO Capabilities to determine authentication procedure */ +#define BTA_AUTH_SPGB_NO BTM_AUTH_SPGB_NO /* 4 MITM Protection Not Required - Single Profiles/general bonding + Numeric comparison with automatic accept allowed */ +#define BTA_AUTH_SPGB_YES BTM_AUTH_SPGB_YES /* 5 MITM Protection Required - Single Profiles/general bonding + Use IO Capabilities to determine authentication procedure */ +typedef tBTM_AUTH_REQ tBTA_AUTH_REQ; + +#define BTA_AUTH_DD_BOND BTM_AUTH_DD_BOND /* 2 this bit is set for dedicated bonding */ +#define BTA_AUTH_GEN_BOND BTM_AUTH_SPGB_NO /* 4 this bit is set for general bonding */ +#define BTA_AUTH_BONDS BTM_AUTH_BONDS /* 6 the general/dedicated bonding bits */ + +#define BTA_LE_AUTH_NO_BOND BTM_LE_AUTH_REQ_NO_BOND /* 0*/ +#define BTA_LE_AUTH_BOND BTM_LE_AUTH_REQ_BOND /* 1 << 0 */ +#define BTA_LE_AUTH_REQ_MITM BTM_LE_AUTH_REQ_MITM /* 1 << 2 */ +typedef tBTM_LE_AUTH_REQ tBTA_LE_AUTH_REQ; /* combination of the above bit pattern */ + +#define BTA_OOB_NONE BTM_OOB_NONE +#define BTA_OOB_PRESENT BTM_OOB_PRESENT +#if BTM_OOB_INCLUDED == TRUE +#define BTA_OOB_UNKNOWN BTM_OOB_UNKNOWN +#endif +typedef tBTM_OOB_DATA tBTA_OOB_DATA; + +/* Structure associated with BTA_DM_SP_CFM_REQ_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ + UINT32 num_val; /* the numeric value for comparison. If just_works, do not show this number to UI */ + BOOLEAN just_works; /* TRUE, if "Just Works" association model */ + tBTA_AUTH_REQ loc_auth_req; /* Authentication required for local device */ + tBTA_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */ + tBTA_IO_CAP loc_io_caps; /* IO Capabilities of local device */ + tBTA_AUTH_REQ rmt_io_caps; /* IO Capabilities of remote device */ +} tBTA_DM_SP_CFM_REQ; + +enum +{ + BTA_SP_KEY_STARTED, /* passkey entry started */ + BTA_SP_KEY_ENTERED, /* passkey digit entered */ + BTA_SP_KEY_ERASED, /* passkey digit erased */ + BTA_SP_KEY_CLEARED, /* passkey cleared */ + BTA_SP_KEY_COMPLT /* passkey entry completed */ +}; +typedef UINT8 tBTA_SP_KEY_TYPE; + +/* Structure associated with BTA_DM_SP_KEYPRESS_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + tBTA_SP_KEY_TYPE notif_type; +}tBTA_DM_SP_KEY_PRESS; + +/* Structure associated with BTA_DM_SP_KEY_NOTIF_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ + UINT32 passkey; /* the numeric value for comparison. If just_works, do not show this number to UI */ +} tBTA_DM_SP_KEY_NOTIF; + +/* Structure associated with BTA_DM_SP_RMT_OOB_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* peer address */ + DEV_CLASS dev_class; /* peer CoD */ + BD_NAME bd_name; /* peer device name */ +} tBTA_DM_SP_RMT_OOB; + +/* Structure associated with BTA_DM_BOND_CANCEL_CMPL_EVT */ +typedef struct +{ + tBTA_STATUS result; /* TRUE of bond cancel succeeded, FALSE if failed. */ +} tBTA_DM_BOND_CANCEL_CMPL; + +/* Union of all security callback structures */ +typedef union +{ + tBTA_DM_ENABLE enable; /* BTA enabled */ + tBTA_DM_PIN_REQ pin_req; /* PIN request. */ + tBTA_DM_AUTH_CMPL auth_cmpl; /* Authentication complete indication. */ + tBTA_DM_AUTHORIZE authorize; /* Authorization request. */ + tBTA_DM_LINK_UP link_up; /* ACL connection down event */ + tBTA_DM_LINK_DOWN link_down; /* ACL connection down event */ + tBTA_DM_SIG_STRENGTH sig_strength; /* rssi and link quality value */ + tBTA_DM_BUSY_LEVEL busy_level; /* System busy level */ + tBTA_DM_SP_CFM_REQ cfm_req; /* user confirm request */ + tBTA_DM_SP_KEY_NOTIF key_notif; /* passkey notification */ + tBTA_DM_SP_RMT_OOB rmt_oob; /* remote oob */ + tBTA_DM_BOND_CANCEL_CMPL bond_cancel_cmpl; /* Bond Cancel Complete indication */ + tBTA_DM_SP_KEY_PRESS key_press; /* key press notification event */ + tBTA_DM_ROLE_CHG role_chg; /* role change event */ + tBTA_DM_BLE_SEC_REQ ble_req; /* BLE SMP related request */ + tBTA_DM_BLE_KEY ble_key; /* BLE SMP keys used when pairing */ + tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */ + BT_OCTET16 ble_er; /* ER event data */ +} tBTA_DM_SEC; + +/* Security callback */ +typedef void (tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data); + +/* Vendor Specific Command Callback */ +typedef tBTM_VSC_CMPL_CB tBTA_VENDOR_CMPL_CBACK; + +/* Search callback events */ +#define BTA_DM_INQ_RES_EVT 0 /* Inquiry result for a peer device. */ +#define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */ +#define BTA_DM_DISC_RES_EVT 2 /* Discovery result for a peer device. */ +#define BTA_DM_DISC_BLE_RES_EVT 3 /* Discovery result for BLE GATT based servoce on a peer device. */ +#define BTA_DM_DISC_CMPL_EVT 4 /* Discovery complete. */ +#define BTA_DM_DI_DISC_CMPL_EVT 5 /* Discovery complete. */ +#define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */ + +typedef UINT8 tBTA_DM_SEARCH_EVT; + +#define BTA_DM_INQ_RES_IGNORE_RSSI BTM_INQ_RES_IGNORE_RSSI /* 0x7f RSSI value not supplied (ignore it) */ + +/* Structure associated with BTA_DM_INQ_RES_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + DEV_CLASS dev_class; /* Device class of peer device. */ + BOOLEAN remt_name_not_required; /* Application sets this flag if it already knows the name of the device */ + /* If the device name is known to application BTA skips the remote name request */ + BOOLEAN is_limited; /* TRUE, if the limited inquiry bit is set in the CoD */ + INT8 rssi; /* The rssi value */ + UINT8 *p_eir; /* received EIR */ +#if (BLE_INCLUDED == TRUE) + UINT8 inq_result_type; + UINT8 ble_addr_type; + tBTM_BLE_EVT_TYPE ble_evt_type; + tBT_DEVICE_TYPE device_type; +#endif + +} tBTA_DM_INQ_RES; + +/* Structure associated with BTA_DM_INQ_CMPL_EVT */ +typedef struct +{ + UINT8 num_resps; /* Number of inquiry responses. */ +} tBTA_DM_INQ_CMPL; + +/* Structure associated with BTA_DM_DI_DISC_CMPL_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + UINT8 num_record; /* Number of DI record */ + tBTA_STATUS result; +} tBTA_DM_DI_DISC_CMPL; + +/* Structure associated with BTA_DM_DISC_RES_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + tBTA_SERVICE_MASK services; /* Services found on peer device. */ +// btla-specific ++ + UINT8 * p_raw_data; /* Raw data for discovery DB */ + UINT32 raw_data_size; /* size of raw data */ + tBT_DEVICE_TYPE device_type; /* device type in case it is BLE device */ + UINT32 num_uuids; + UINT8 *p_uuid_list; +// btla-specific -- + tBTA_STATUS result; +} tBTA_DM_DISC_RES; + +/* Structure associated with tBTA_DM_DISC_BLE_RES */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address peer device. */ + BD_NAME bd_name; /* Name of peer device. */ + tBT_UUID service; /* GATT based Services UUID found on peer device. */ +} tBTA_DM_DISC_BLE_RES; + + +/* Union of all search callback structures */ +typedef union +{ + tBTA_DM_INQ_RES inq_res; /* Inquiry result for a peer device. */ + tBTA_DM_INQ_CMPL inq_cmpl; /* Inquiry complete. */ + tBTA_DM_DISC_RES disc_res; /* Discovery result for a peer device. */ + tBTA_DM_DISC_BLE_RES disc_ble_res; /* discovery result for GATT based service */ + tBTA_DM_DI_DISC_CMPL di_disc; /* DI discovery result for a peer device */ + +} tBTA_DM_SEARCH; + +/* Search callback */ +typedef void (tBTA_DM_SEARCH_CBACK)(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data); + +/* Execute call back */ +typedef void (tBTA_DM_EXEC_CBACK) (void * p_param); + +/* Encryption callback*/ +typedef void (tBTA_DM_ENCRYPT_CBACK) (BD_ADDR bd_addr, tBTA_STATUS result); + +#if BLE_INCLUDED == TRUE +#define BTA_DM_BLE_SEC_NONE BTM_BLE_SEC_NONE +#define BTA_DM_BLE_SEC_ENCRYPT BTM_BLE_SEC_ENCRYPT +#define BTA_DM_BLE_SEC_NO_MITM BTM_BLE_SEC_ENCRYPT_NO_MITM +#define BTA_DM_BLE_SEC_MITM BTM_BLE_SEC_ENCRYPT_MITM +typedef tBTM_BLE_SEC_ACT tBTA_DM_BLE_SEC_ACT; +#else +typedef UINT8 tBTA_DM_BLE_SEC_ACT; +#endif + +/* Maximum service name length */ +#define BTA_SERVICE_NAME_LEN 35 +#define BTA_SERVICE_DESP_LEN BTA_SERVICE_NAME_LEN +#define BTA_PROVIDER_NAME_LEN BTA_SERVICE_NAME_LEN + + +/* link policy masks */ +#define BTA_DM_LP_SWITCH HCI_ENABLE_MASTER_SLAVE_SWITCH +#define BTA_DM_LP_HOLD HCI_ENABLE_HOLD_MODE +#define BTA_DM_LP_SNIFF HCI_ENABLE_SNIFF_MODE +#define BTA_DM_LP_PARK HCI_ENABLE_PARK_MODE +typedef UINT16 tBTA_DM_LP_MASK; + +/* power mode actions */ +#define BTA_DM_PM_NO_ACTION 0x00 /* no change to the current pm setting */ +#define BTA_DM_PM_PARK 0x10 /* prefers park mode */ +#define BTA_DM_PM_SNIFF 0x20 /* prefers sniff mode */ +#define BTA_DM_PM_SNIFF1 0x21 /* prefers sniff1 mode */ +#define BTA_DM_PM_SNIFF2 0x22 /* prefers sniff2 mode */ +#define BTA_DM_PM_SNIFF3 0x23 /* prefers sniff3 mode */ +#define BTA_DM_PM_SNIFF4 0x24 /* prefers sniff4 mode */ +#define BTA_DM_PM_SNIFF5 0x25 /* prefers sniff5 mode */ +#define BTA_DM_PM_SNIFF6 0x26 /* prefers sniff6 mode */ +#define BTA_DM_PM_SNIFF7 0x27 /* prefers sniff7 mode */ +#define BTA_DM_PM_SNIFF_USER0 0x28 /* prefers user-defined sniff0 mode (testtool only) */ +#define BTA_DM_PM_SNIFF_USER1 0x29 /* prefers user-defined sniff1 mode (testtool only) */ +#define BTA_DM_PM_ACTIVE 0x40 /* prefers active mode */ +#define BTA_DM_PM_RETRY 0x80 /* retry power mode based on current settings */ +#define BTA_DM_PM_NO_PREF 0x01 /* service has no prefernce on power mode setting. eg. connection to service got closed */ + +typedef UINT8 tBTA_DM_PM_ACTTION; + +/* index to bta_dm_ssr_spec */ +#define BTA_DM_PM_SSR0 0 +#define BTA_DM_PM_SSR1 1 +#define BTA_DM_PM_SSR2 2 +#define BTA_DM_PM_SSR3 3 +#define BTA_DM_PM_SSR4 4 +#define BTA_DM_PM_SSR5 5 +#define BTA_DM_PM_SSR6 6 + +#define BTA_DM_PM_NUM_EVTS 9 + +#ifndef BTA_DM_PM_PARK_IDX +#define BTA_DM_PM_PARK_IDX 5 /* the actual index to bta_dm_pm_md[] for PARK mode */ +#endif + +#define BTA_DM_SW_BB_TO_MM BTM_SW_BB_TO_MM +#define BTA_DM_SW_MM_TO_BB BTM_SW_MM_TO_BB +#define BTA_DM_SW_BB_TO_BTC BTM_SW_BB_TO_BTC +#define BTA_DM_SW_BTC_TO_BB BTM_SW_BTC_TO_BB + +typedef tBTM_SW_DIR tBTA_DM_SW_DIR; + +/* Switch callback events */ +#define BTA_DM_SWITCH_CMPL_EVT 0 /* Completion of the Switch API */ + +typedef UINT8 tBTA_DM_SWITCH_EVT; +typedef void (tBTA_DM_SWITCH_CBACK)(tBTA_DM_SWITCH_EVT event, tBTA_STATUS status); + +/* Audio routing out configuration */ +#define BTA_DM_ROUTE_NONE 0x00 /* No Audio output */ +#define BTA_DM_ROUTE_DAC 0x01 /* routing over analog output */ +#define BTA_DM_ROUTE_I2S 0x02 /* routing over digital (I2S) output */ +#define BTA_DM_ROUTE_BT_MONO 0x04 /* routing over SCO */ +#define BTA_DM_ROUTE_BT_STEREO 0x08 /* routing over BT Stereo */ +#define BTA_DM_ROUTE_HOST 0x10 /* routing over Host */ +#define BTA_DM_ROUTE_FMTX 0x20 /* routing over FMTX */ +#define BTA_DM_ROUTE_FMRX 0x40 /* routing over FMRX */ +#define BTA_DM_ROUTE_BTSNK 0x80 /* routing over BT SNK */ + +typedef UINT8 tBTA_DM_ROUTE_PATH; + + +/* Device Identification (DI) data structure +*/ +/* Used to set the DI record */ +typedef tSDP_DI_RECORD tBTA_DI_RECORD; +/* Used to get the DI record */ +typedef tSDP_DI_GET_RECORD tBTA_DI_GET_RECORD; +/* SDP discovery database */ +typedef tSDP_DISCOVERY_DB tBTA_DISCOVERY_DB; + +#ifndef BTA_DI_NUM_MAX +#define BTA_DI_NUM_MAX 3 +#endif + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function BTA_EnableBluetooth +** +** Description This function initializes BTA and prepares BTA and the +** Bluetooth protocol stack for use. This function is +** typically called at startup or when Bluetooth services +** are required by the phone. This function must be called +** before calling any other API function. +** +** +** Returns BTA_SUCCESS if successful. +** BTA_FAIL if internal failure. +** +*******************************************************************************/ +BTA_API extern tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_DisableBluetooth +** +** Description This function disables BTA and the Bluetooth protocol +** stack. It is called when BTA is no longer being used +** by any application in the system. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern tBTA_STATUS BTA_DisableBluetooth(void); + +/******************************************************************************* +** +** Function BTA_EnableTestMode +** +** Description Enables bluetooth device under test mode +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +BTA_API extern tBTA_STATUS BTA_EnableTestMode(void); + +/******************************************************************************* +** +** Function BTA_DisableTestMode +** +** Description Disable bluetooth device under test mode +** +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_DisableTestMode(void); + +/******************************************************************************* +** +** Function BTA_DmIsDeviceUp +** +** Description This function tests whether the Bluetooth module is up +** and ready. This is a direct execution function that +** may lock task scheduling on some platforms. +** +** +** Returns TRUE if the module is ready. +** FALSE if the module is not ready. +** +*******************************************************************************/ +BTA_API extern BOOLEAN BTA_DmIsDeviceUp(void); + +/******************************************************************************* +** +** Function BTA_DmSetDeviceName +** +** Description This function sets the Bluetooth name of the local device. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetDeviceName(char *p_name); + +/******************************************************************************* +** +** Function BTA_DmSetVisibility +** +** Description This function sets the Bluetooth connectable,discoverable, +** pairable and conn paired only modesmodes of the local device. +** This controls whether other Bluetooth devices can find and connect to +** the local device. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, UINT8 pairable_mode, UINT8 conn_filter); + +/******************************************************************************* +** +** Function BTA_DmSetScanParam +** +** Description This function sets the parameters for page scan and +** inquiry scan. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetScanParam (UINT16 page_scan_interval, UINT16 page_scan_window, + UINT16 inquiry_scan_interval, UINT16 inquiry_scan_window); + +/******************************************************************************* +** +** Function BTA_DmSetAfhChannels +** +** Description This function sets the AFH first and +** last disable channel, so channels within +** that range are disabled. +** In order to use this API, BTM_BYPASS_AMP_AUTO_AFH must be set +** to be TRUE +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetAfhChannels(UINT8 first, UINT8 last); + + +/******************************************************************************* +** +** Function BTA_DmVendorSpecificCommand +** +** Description This function sends the vendor specific command +** to the controller +** +** +** Returns tBTA_STATUS +** +*******************************************************************************/ +BTA_API extern tBTA_STATUS BTA_DmVendorSpecificCommand (UINT16 opcode, UINT8 param_len,UINT8 *p_param_buf, tBTA_VENDOR_CMPL_CBACK *p_cback); + + +/******************************************************************************* +** +** Function BTA_DmSearch +** +** Description This function searches for peer Bluetooth devices. It +** first performs an inquiry; for each device found from the +** inquiry it gets the remote name of the device. If +** parameter services is nonzero, service discovery will be +** performed on each device for the services specified. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, + tBTA_DM_SEARCH_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_DmSearchCancel +** +** Description This function cancels a search that has been initiated +** by calling BTA_DmSearch(). +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSearchCancel(void); + +/******************************************************************************* +** +** Function BTA_DmDiscover +** +** Description This function performs service discovery for the services +** of a particular peer device. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search); + +// btla-specific ++ +/******************************************************************************* +** +** Function BTA_DmDiscoverUUID +** +** Description This function performs service discovery for the services +** of a particular peer device. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID *uuid, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search); + +/******************************************************************************* +** +** Function BTA_DmGetCachedRemoteName +** +** Description Retieve cached remote name if available +** +** Returns BTA_SUCCESS if cached name was retrieved +** BTA_FAILURE if cached name is not available +** +*******************************************************************************/ +tBTA_STATUS BTA_DmGetCachedRemoteName(BD_ADDR remote_device, UINT8 **pp_cached_name); +// btla-specific -- + +/******************************************************************************* +** +** Function BTA_DmIsMaster +** +** Description This function checks if the local device is the master of +** the link to the given device +** +** Returns TRUE if master. +** FALSE if not. +** +*******************************************************************************/ +BTA_API extern BOOLEAN BTA_DmIsMaster(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_DmBond +** +** Description This function initiates a bonding procedure with a peer +** device. The bonding procedure enables authentication +** and optionally encryption on the Bluetooth link. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmBond(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_DmBondCancel +** +** Description This function cancels a bonding procedure with a peer +** device. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmBondCancel(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_DmPinReply +** +** Description This function provides a PIN when one is requested by DM +** during a bonding procedure. The application should call +** this function after the security callback is called with +** a BTA_DM_PIN_REQ_EVT. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmPinReply(BD_ADDR bd_addr, BOOLEAN accept, UINT8 pin_len, + UINT8 *p_pin); + +/******************************************************************************* +** +** Function BTA_DmLinkPolicy +** +** Description This function sets/clears the link policy mask to the given +** bd_addr. +** If clearing the sniff or park mode mask, the link is put +** in active mode. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmLinkPolicy(BD_ADDR bd_addr, tBTA_DM_LP_MASK policy_mask, + BOOLEAN set); + +#if (BTM_OOB_INCLUDED == TRUE) +/******************************************************************************* +** +** Function BTA_DmLocalOob +** +** Description This function retrieves the OOB data from local controller. +** The result is reported by bta_dm_co_loc_oob(). +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmLocalOob(void); +#endif /* BTM_OOB_INCLUDED */ + +/******************************************************************************* +** +** Function BTA_DmConfirm +** +** Description This function accepts or rejects the numerical value of the +** Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmConfirm(BD_ADDR bd_addr, BOOLEAN accept); + +/******************************************************************************* +** +** Function BTA_DmPasskeyCancel +** +** Description This function is called to cancel the simple pairing process +** reported by BTA_DM_SP_KEY_NOTIF_EVT +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmPasskeyCancel(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_DmAddDevice +** +** Description This function adds a device to the security database list +** of peer devices. This function would typically be called +** at system startup to initialize the security database with +** known peer devices. This is a direct execution function +** that may lock task scheduling on some platforms. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, + LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask, + BOOLEAN is_trusted, UINT8 key_type, + tBTA_IO_CAP io_cap); + +/******************************************************************************* +** +** Function BTA_DmAddDevWithName +** +** Description This function is newer version of BTA_DmAddDevice() +** which added bd_name and features as input parameters. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmAddDevWithName (BD_ADDR bd_addr, DEV_CLASS dev_class, + BD_NAME bd_name, BD_FEATURES features, + LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask, + BOOLEAN is_trusted, UINT8 key_type, tBTA_IO_CAP io_cap); + +/******************************************************************************* +** +** Function BTA_DmRemoveDevice +** +** Description This function removes a device from the security database. +** This is a direct execution function that may lock task +** scheduling on some platforms. +** +** +** Returns BTA_SUCCESS if successful. +** BTA_FAIL if operation failed. +** +*******************************************************************************/ +BTA_API extern tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_DmAuthorizeReply +** +** Description This function provides an authorization reply when +** authorization is requested by BTA. The application calls +** this function after the security callback is called with +** a BTA_DM_AUTHORIZE_EVT. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmAuthorizeReply(BD_ADDR bd_addr, tBTA_SERVICE_ID service, + tBTA_AUTH_RESP response); + +/******************************************************************************* +** +** Function BTA_DmSignalStrength +** +** Description This function initiates RSSI and channnel quality +** measurments. BTA_DM_SIG_STRENGTH_EVT is sent to +** application with the values of RSSI and channel +** quality +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSignalStrength(tBTA_SIG_STRENGTH_MASK mask, UINT16 period, BOOLEAN start); + +/******************************************************************************* +** +** Function BTA_DmWriteInqTxPower +** +** Description This command is used to write the inquiry transmit power level +** used to transmit the inquiry (ID) data packets. +** +** Parameters tx_power - tx inquiry power to use, valid value is -70 ~ 20 + +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmWriteInqTxPower(INT8 tx_power); + +/******************************************************************************* +** +** Function BTA_DmEirAddUUID +** +** Description This function is called to add UUID into EIR. +** +** Parameters tBT_UUID - UUID +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_DmEirAddUUID (tBT_UUID *p_uuid); + +/******************************************************************************* +** +** Function BTA_DmEirRemoveUUID +** +** Description This function is called to remove UUID from EIR. +** +** Parameters tBT_UUID - UUID +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_DmEirRemoveUUID (tBT_UUID *p_uuid); + +/******************************************************************************* +** +** Function BTA_DmSetEIRConfig +** +** Description This function is called to override the BTA default EIR parameters. +** This funciton is only valid in a system where BTU & App task +** are in the same memory space. +** +** Parameters Pointer to User defined EIR config +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetEIRConfig (tBTA_DM_EIR_CONF *p_eir_cfg); + +/******************************************************************************* +** +** Function BTA_CheckEirData +** +** Description This function is called to get EIR data from significant part. +** +** Parameters p_eir - pointer of EIR significant part +** type - finding EIR data type +** p_length - return the length of EIR data +** +** Returns pointer of EIR data +** +*******************************************************************************/ +BTA_API extern UINT8 *BTA_CheckEirData( UINT8 *p_eir, UINT8 tag, UINT8 *p_length ); + +/******************************************************************************* +** +** Function BTA_GetEirService +** +** Description This function is called to get BTA service mask from EIR. +** +** Parameters p_eir - pointer of EIR significant part +** p_services - return the BTA service mask +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GetEirService( UINT8 *p_eir, tBTA_SERVICE_MASK *p_services ); + +/******************************************************************************* +** +** Function BTA_DmUseSsr +** +** Description This function is called to check if the connected peer device +** supports SSR or not. +** +** Returns TRUE, if SSR is supported +** +*******************************************************************************/ +BTA_API extern BOOLEAN BTA_DmUseSsr( BD_ADDR bd_addr ); + + +/******************************************************************************* +** +** Function BTA_DmSetLocalDiRecord +** +** Description This function adds a DI record to the local SDP database. +** +** Returns BTA_SUCCESS if record set sucessfully, otherwise error code. +** +*******************************************************************************/ +BTA_API extern tBTA_STATUS BTA_DmSetLocalDiRecord( tBTA_DI_RECORD *p_device_info, + UINT32 *p_handle ); + +/******************************************************************************* +** +** Function BTA_DmGetLocalDiRecord +** +** Description Get a specified DI record to the local SDP database. If no +** record handle is provided, the primary DI record will be +** returned. +** +** Returns BTA_SUCCESS if record set sucessfully, otherwise error code. +** +*******************************************************************************/ +BTA_API extern tBTA_STATUS BTA_DmGetLocalDiRecord( tBTA_DI_GET_RECORD *p_device_info, + UINT32 *p_handle ); + +/******************************************************************************* +** +** Function BTA_DmDiDiscover +** +** Description This function queries a remote device for DI information. +** +** Returns None. +** +*******************************************************************************/ +BTA_API extern void BTA_DmDiDiscover( BD_ADDR remote_device, tBTA_DISCOVERY_DB *p_db, + UINT32 len, tBTA_DM_SEARCH_CBACK *p_cback ); + +/******************************************************************************* +** +** Function BTA_DmGetDiRecord +** +** Description This function retrieves a remote device's DI record from +** the specified database. +** +** Returns None. +** +*******************************************************************************/ +BTA_API extern tBTA_STATUS BTA_DmGetDiRecord( UINT8 get_record_index, tBTA_DI_GET_RECORD *p_device_info, + tBTA_DISCOVERY_DB *p_db ); + +/******************************************************************************* +** +** Function BTA_SysFeatures +** +** Description This function is called to set system features. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_SysFeatures (UINT16 sys_features); + +/******************************************************************************* +** +** Function bta_dmexecutecallback +** +** Description This function will request BTA to execute a call back in the context of BTU task +** This API was named in lower case because it is only intended +** for the internal customers(like BTIF). +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_dmexecutecallback (tBTA_DM_EXEC_CBACK* p_callback, void * p_param); + +#if (BTM_SCO_HCI_INCLUDED == TRUE) +/******************************************************************************* +** +** Function BTA_DmPcmInitSamples +** +** Description initialize the down sample converter. +** +** src_sps: original samples per second (source audio data) +** (ex. 44100, 48000) +** bits: number of bits per pcm sample (16) +** n_channels: number of channels (i.e. mono(1), stereo(2)...) +** +** Returns none +** +*******************************************************************************/ +BTA_API extern void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels); + +/************************************************************************************** +** Function BTA_DmPcmResample +** +** Description Down sampling utility to convert higher sampling rate into 8K/16bits +** PCM samples. +** +** Parameters p_src: pointer to the buffer where the original sampling PCM +** are stored. +** in_bytes: Length of the input PCM sample buffer in byte. +** p_dst: pointer to the buffer which is to be used to store +** the converted PCM samples. +** +** +** Returns INT32: number of samples converted. +** +**************************************************************************************/ +BTA_API extern INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst); +#endif + +#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) +/* BLE related API functions */ +/******************************************************************************* +** +** Function BTA_DmBleSecurityGrant +** +** Description Grant security request access. +** +** Parameters: bd_addr - BD address of the peer +** res - security grant status. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res); + + + +/******************************************************************************* +** +** Function BTA_DmBleSetBgConnType +** +** Description This function is called to set BLE connectable mode for a +** peripheral device. +** +** Parameters bg_conn_type: it can be auto connection, or selective connection. +** p_select_cback: callback function when selective connection procedure +** is being used. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback); + +/******************************************************************************* +** +** Function BTA_DmBlePasskeyReply +** +** Description Send BLE SMP passkey reply. +** +** Parameters: bd_addr - BD address of the peer +** accept - passkey entry sucessful or declined. +** passkey - passkey value, must be a 6 digit number, +** can be lead by 0. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, BOOLEAN accept, UINT32 passkey); + +/******************************************************************************* +** +** Function BTA_DmAddBleDevice +** +** Description Add a BLE device. This function will be normally called +** during host startup to restore all required information +** for a LE device stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** dev_type - Remote device's device type. +** addr_type - LE device address type. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, + tBT_DEVICE_TYPE dev_type); + + +/******************************************************************************* +** +** Function BTA_DmAddBleKey +** +** Description Add/modify LE device information. This function will be +** normally called during host startup to restore all required +** information stored in the NVRAM. +** +** Parameters: bd_addr - BD address of the peer +** p_le_key - LE key values. +** key_type - LE SMP key type. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmAddBleKey (BD_ADDR bd_addr, tBTA_LE_KEY_VALUE *p_le_key, + tBTA_LE_KEY_TYPE key_type); + +/******************************************************************************* +** +** Function BTA_DmSetBlePrefConnParams +** +** Description This function is called to set the preferred connection +** parameters when default connection parameter is not desired. +** +** Parameters: bd_addr - BD address of the peripheral +** min_conn_int - minimum preferred connection interval +** max_conn_int - maximum preferred connection interval +** slave_latency - preferred slave latency +** supervision_tout - preferred supervision timeout +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetBlePrefConnParams(BD_ADDR bd_addr, + UINT16 min_conn_int, UINT16 max_conn_int, + UINT16 slave_latency, UINT16 supervision_tout ); + +/******************************************************************************* +** +** Function BTA_DmSetBleConnScanParams +** +** Description This function is called to set scan parameters used in +** BLE connection request +** +** Parameters: bd_addr - BD address of the peripheral +** scan_interval - scan interval +** scan_window - scan window +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetBleConnScanParams(UINT16 scan_interval, + UINT16 scan_window ); + +/******************************************************************************* +** +** Function BTA_DmSearchExt +** +** Description This function searches for peer Bluetooth devices. It performs +** an inquiry and gets the remote name for devices. Service +** discovery is done if services is non zero +** +** Parameters p_dm_inq: inquiry conditions +** services: if service is not empty, service discovery will be done. +** for all GATT based service condition, put num_uuid, and +** p_uuid is the pointer to the list of UUID values. +** p_cback: callback functino when search is completed. +** +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmSearchExt(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_DmDiscoverExt +** +** Description This function does service discovery for services of a +** peer device. When services.num_uuid is 0, it indicates all +** GATT based services are to be searched; other wise a list of +** UUID of interested services should be provided through +** services.p_uuid. +** +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT *p_services, + tBTA_DM_SEARCH_CBACK *p_cback, BOOLEAN sdp_search); + + +/******************************************************************************* +** +** Function BTA_DmSetEncryption +** +** Description This function is called to ensure that connection is +** encrypted. Should be called only on an open connection. +** Typically only needed for connections that first want to +** bring up unencrypted links, then later encrypt them. +** +** Parameters: bd_addr - Address of the peer device +** p_callback - Pointer to callback function to indicat the +** link encryption status +** sec_act - This is the security action to indicate +** what knid of BLE security level is required for +** the BLE link if the BLE is supported +** Note: This parameter is ignored for the BR/EDR link +** or the BLE is not supported +** +** Returns void +** +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_DM_ENCRYPT_CBACK *p_callback, + tBTA_DM_BLE_SEC_ACT sec_act); + +#endif + +// btla-specific ++ +/******************************************************************************* +** +** Function BTA_DmSetAfhChannelAssessment +** +** Description This function is called to set the channel assessment mode on or off +** +** Returns status +** +*******************************************************************************/ +BTA_API extern void BTA_DmSetAfhChannelAssessment (BOOLEAN enable_or_disable); +// btla-specific -- + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_API_H */ + diff --git a/bta/include/bta_ar_api.h b/bta/include/bta_ar_api.h new file mode 100644 index 0000000..b451cb4 --- /dev/null +++ b/bta/include/bta_ar_api.h @@ -0,0 +1,140 @@ +/****************************************************************************** + * + * 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 public interface file for the simulatenous advanced + * audio/video streaming (AV) source and sink of BTA, Broadcom's Bluetooth + * application layer for mobile phones. + * + ******************************************************************************/ +#ifndef BTA_AR_API_H +#define BTA_AR_API_H + +#include "avdt_api.h" +#include "avct_api.h" +#include "avrc_api.h" +#include "sdp_api.h" +#include "bta_av_api.h" +#include "bta_sys.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/* This event signal to AR user that other profile is connected */ +#define BTA_AR_AVDT_CONN_EVT (AVDT_MAX_EVT + 1) + +/******************************************************************************* +** +** Function bta_ar_init +** +** Description This function is called from bta_sys_init(). +** to initialize the control block +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_init(void); + +/******************************************************************************* +** +** Function bta_ar_reg_avdt +** +** Description This function is called to register to AVDTP. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_reg_avdt(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback, tBTA_SYS_ID sys_id); + +/******************************************************************************* +** +** Function bta_ar_dereg_avdt +** +** Description This function is called to de-register from AVDTP. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id); + +/******************************************************************************* +** +** Function bta_ar_avdt_conn +** +** Description This function is called to let ar know that some AVDTP profile +** is connected for this sys_id. +** If the other sys modules started a timer for PENDING_EVT, +** the timer can be stopped now. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function bta_ar_reg_avct +** +** Description This function is called to register to AVCTP. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_reg_avct(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask, tBTA_SYS_ID sys_id); + +/******************************************************************************* +** +** Function bta_ar_dereg_avct +** +** Description This function is called to deregister from AVCTP. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_dereg_avct(tBTA_SYS_ID sys_id); + +/****************************************************************************** +** +** Function bta_ar_reg_avrc +** +** Description This function is called to register an SDP record for AVRCP. +** +** Returns void +** +******************************************************************************/ +extern void bta_ar_reg_avrc(UINT16 service_uuid, char *p_service_name, + char *p_provider_name, UINT16 categories, tBTA_SYS_ID sys_id); + +/****************************************************************************** +** +** Function bta_ar_dereg_avrc +** +** Description This function is called to de-register/delete an SDP record for AVRCP. +** +** Returns void +** +******************************************************************************/ +extern void bta_ar_dereg_avrc(UINT16 service_uuid, tBTA_SYS_ID sys_id); + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_AR_API_H */ diff --git a/bta/include/bta_av_api.h b/bta/include/bta_av_api.h new file mode 100644 index 0000000..eb77279 --- /dev/null +++ b/bta/include/bta_av_api.h @@ -0,0 +1,765 @@ +/****************************************************************************** + * + * 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 public interface file for the advanced audio/video streaming + * (AV) subsystem of BTA, Broadcom's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ +#ifndef BTA_AV_API_H +#define BTA_AV_API_H + +#include "avrc_api.h" +#include "avdt_api.h" +#include "a2d_api.h" +#include "bta_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/* Set to TRUE if seperate authorization prompt desired for AVCTP besides A2DP authorization */ +/* Typically FALSE when AVRCP is used in conjunction with A2DP */ +#ifndef BTA_AV_WITH_AVCTP_AUTHORIZATION +#define BTA_AV_WITH_AVCTP_AUTHORIZATION FALSE +#endif + +/* AV status values */ +#define BTA_AV_SUCCESS 0 /* successful operation */ +#define BTA_AV_FAIL 1 /* generic failure */ +#define BTA_AV_FAIL_SDP 2 /* service not found */ +#define BTA_AV_FAIL_STREAM 3 /* stream connection failed */ +#define BTA_AV_FAIL_RESOURCES 4 /* no resources */ +#define BTA_AV_FAIL_ROLE 5 /* failed due to role management related issues */ + +typedef UINT8 tBTA_AV_STATUS; + +/* AV features masks */ +#define BTA_AV_FEAT_RCTG 0x0001 /* remote control target */ +#define BTA_AV_FEAT_RCCT 0x0002 /* remote control controller */ +#define BTA_AV_FEAT_PROTECT 0x0004 /* streaming media contect protection */ +#define BTA_AV_FEAT_VENDOR 0x0008 /* remote control vendor dependent commands */ +#define BTA_AV_FEAT_REPORT 0x0020 /* use reporting service for VDP */ +#define BTA_AV_FEAT_METADATA 0x0040 /* remote control Metadata Transfer command/response */ +#define BTA_AV_FEAT_MULTI_AV 0x0080 /* use multi-av, if controller supports it */ +#define BTA_AV_FEAT_BROWSE 0x0010 /* use browsing channel */ +#define BTA_AV_FEAT_MASTER 0x0100 /* stream only as master role */ +#define BTA_AV_FEAT_ADV_CTRL 0x0200 /* remote control Advanced Control command/response */ +#define BTA_AV_FEAT_DELAY_RPT 0x0400 /* allow delay reporting */ +#define BTA_AV_FEAT_ACP_START 0x0800 /* start stream when 2nd SNK was accepted */ + +/* Internal features */ +#define BTA_AV_FEAT_NO_SCO_SSPD 0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */ + +typedef UINT16 tBTA_AV_FEAT; + +/* AV channel values */ +#define BTA_AV_CHNL_MSK 0xC0 +#define BTA_AV_CHNL_AUDIO 0x40 /* audio channel */ +#define BTA_AV_CHNL_VIDEO 0x80 /* video channel */ +typedef UINT8 tBTA_AV_CHNL; + + +#define BTA_AV_HNDL_MSK 0x3F +typedef UINT8 tBTA_AV_HNDL; +/* handle index to mask */ +#define BTA_AV_HNDL_TO_MSK(h) ((UINT8)(1 << (h))) + +/* tBTA_AV_HNDL to mask */ +#define BTA_AV_HNDL_TYPE_TO_MSK(h) ((UINT8)(1 << (h&BTA_AV_HNDL_MSK))) + +/* offset of codec type in codec info byte array */ +#define BTA_AV_CODEC_TYPE_IDX AVDT_CODEC_TYPE_INDEX /* 2 */ + + + +/* maximum number of streams created: 1 for audio, 1 for video */ +#ifndef BTA_AV_NUM_STRS +#define BTA_AV_NUM_STRS 2 +#endif + +#ifndef BTA_AV_MAX_SEPS +#define BTA_AV_MAX_SEPS 2 +#endif + +#ifndef BTA_AV_MAX_A2DP_MTU + /*#define BTA_AV_MAX_A2DP_MTU 668 //224 (DM5) * 3 - 4(L2CAP header) */ +#define BTA_AV_MAX_A2DP_MTU 1008 +#endif + +#ifndef BTA_AV_MAX_VDP_MTU +#define BTA_AV_MAX_VDP_MTU 1008 +#endif + + +/* codec type */ +#define BTA_AV_CODEC_SBC A2D_MEDIA_CT_SBC /* SBC media codec type */ +#define BTA_AV_CODEC_M12 A2D_MEDIA_CT_M12 /* MPEG-1, 2 Audio media codec type */ +#define BTA_AV_CODEC_M24 A2D_MEDIA_CT_M24 /* MPEG-2, 4 AAC media codec type */ +#define BTA_AV_CODEC_ATRAC A2D_MEDIA_CT_ATRAC /* ATRAC family media codec type */ +#define BTA_AV_CODEC_H263_P0 VDP_MEDIA_CT_H263_P0 /* H.263 baseline (profile 0) */ +#define BTA_AV_CODEC_MPEG4 VDP_MEDIA_CT_MPEG4 /* MPEG-4 Visual Simple Profile */ +#define BTA_AV_CODEC_H263_P3 VDP_MEDIA_CT_H263_P3 /* H.263 profile 3 */ +#define BTA_AV_CODEC_H263_P8 VDP_MEDIA_CT_H263_P8 /* H.263 profile 8 */ +#define BTA_AV_CODEC_VEND VDP_MEDIA_CT_VEND /* Non-VDP */ + +typedef UINT8 tBTA_AV_CODEC; + +/* Company ID in BT assigned numbers */ +#define BTA_AV_BT_VENDOR_ID VDP_BT_VENDOR_ID /* Broadcom Corporation */ + +/* vendor specific codec ID */ +#define BTA_AV_CODEC_ID_H264 VDP_CODEC_ID_H264 /* Non-VDP codec ID - H.264 */ +#define BTA_AV_CODEC_ID_IMG VDP_CODEC_ID_IMG /* Non-VDP codec ID - images/slideshow */ + +/* operation id list for BTA_AvRemoteCmd */ +#define BTA_AV_RC_SELECT AVRC_ID_SELECT /* select */ +#define BTA_AV_RC_UP AVRC_ID_UP /* up */ +#define BTA_AV_RC_DOWN AVRC_ID_DOWN /* down */ +#define BTA_AV_RC_LEFT AVRC_ID_LEFT /* left */ +#define BTA_AV_RC_RIGHT AVRC_ID_RIGHT /* right */ +#define BTA_AV_RC_RIGHT_UP AVRC_ID_RIGHT_UP /* right-up */ +#define BTA_AV_RC_RIGHT_DOWN AVRC_ID_RIGHT_DOWN /* right-down */ +#define BTA_AV_RC_LEFT_UP AVRC_ID_LEFT_UP /* left-up */ +#define BTA_AV_RC_LEFT_DOWN AVRC_ID_LEFT_DOWN /* left-down */ +#define BTA_AV_RC_ROOT_MENU AVRC_ID_ROOT_MENU /* root menu */ +#define BTA_AV_RC_SETUP_MENU AVRC_ID_SETUP_MENU /* setup menu */ +#define BTA_AV_RC_CONT_MENU AVRC_ID_CONT_MENU /* contents menu */ +#define BTA_AV_RC_FAV_MENU AVRC_ID_FAV_MENU /* favorite menu */ +#define BTA_AV_RC_EXIT AVRC_ID_EXIT /* exit */ +#define BTA_AV_RC_0 AVRC_ID_0 /* 0 */ +#define BTA_AV_RC_1 AVRC_ID_1 /* 1 */ +#define BTA_AV_RC_2 AVRC_ID_2 /* 2 */ +#define BTA_AV_RC_3 AVRC_ID_3 /* 3 */ +#define BTA_AV_RC_4 AVRC_ID_4 /* 4 */ +#define BTA_AV_RC_5 AVRC_ID_5 /* 5 */ +#define BTA_AV_RC_6 AVRC_ID_6 /* 6 */ +#define BTA_AV_RC_7 AVRC_ID_7 /* 7 */ +#define BTA_AV_RC_8 AVRC_ID_8 /* 8 */ +#define BTA_AV_RC_9 AVRC_ID_9 /* 9 */ +#define BTA_AV_RC_DOT AVRC_ID_DOT /* dot */ +#define BTA_AV_RC_ENTER AVRC_ID_ENTER /* enter */ +#define BTA_AV_RC_CLEAR AVRC_ID_CLEAR /* clear */ +#define BTA_AV_RC_CHAN_UP AVRC_ID_CHAN_UP /* channel up */ +#define BTA_AV_RC_CHAN_DOWN AVRC_ID_CHAN_DOWN /* channel down */ +#define BTA_AV_RC_PREV_CHAN AVRC_ID_PREV_CHAN /* previous channel */ +#define BTA_AV_RC_SOUND_SEL AVRC_ID_SOUND_SEL /* sound select */ +#define BTA_AV_RC_INPUT_SEL AVRC_ID_INPUT_SEL /* input select */ +#define BTA_AV_RC_DISP_INFO AVRC_ID_DISP_INFO /* display information */ +#define BTA_AV_RC_HELP AVRC_ID_HELP /* help */ +#define BTA_AV_RC_PAGE_UP AVRC_ID_PAGE_UP /* page up */ +#define BTA_AV_RC_PAGE_DOWN AVRC_ID_PAGE_DOWN /* page down */ +#define BTA_AV_RC_POWER AVRC_ID_POWER /* power */ +#define BTA_AV_RC_VOL_UP AVRC_ID_VOL_UP /* volume up */ +#define BTA_AV_RC_VOL_DOWN AVRC_ID_VOL_DOWN /* volume down */ +#define BTA_AV_RC_MUTE AVRC_ID_MUTE /* mute */ +#define BTA_AV_RC_PLAY AVRC_ID_PLAY /* play */ +#define BTA_AV_RC_STOP AVRC_ID_STOP /* stop */ +#define BTA_AV_RC_PAUSE AVRC_ID_PAUSE /* pause */ +#define BTA_AV_RC_RECORD AVRC_ID_RECORD /* record */ +#define BTA_AV_RC_REWIND AVRC_ID_REWIND /* rewind */ +#define BTA_AV_RC_FAST_FOR AVRC_ID_FAST_FOR /* fast forward */ +#define BTA_AV_RC_EJECT AVRC_ID_EJECT /* eject */ +#define BTA_AV_RC_FORWARD AVRC_ID_FORWARD /* forward */ +#define BTA_AV_RC_BACKWARD AVRC_ID_BACKWARD /* backward */ +#define BTA_AV_RC_ANGLE AVRC_ID_ANGLE /* angle */ +#define BTA_AV_RC_SUBPICT AVRC_ID_SUBPICT /* subpicture */ +#define BTA_AV_RC_F1 AVRC_ID_F1 /* F1 */ +#define BTA_AV_RC_F2 AVRC_ID_F2 /* F2 */ +#define BTA_AV_RC_F3 AVRC_ID_F3 /* F3 */ +#define BTA_AV_RC_F4 AVRC_ID_F4 /* F4 */ +#define BTA_AV_RC_F5 AVRC_ID_F5 /* F5 */ +#define BTA_AV_VENDOR AVRC_ID_VENDOR /* vendor unique */ + +typedef UINT8 tBTA_AV_RC; + +/* state flag for pass through command */ +#define BTA_AV_STATE_PRESS AVRC_STATE_PRESS /* key pressed */ +#define BTA_AV_STATE_RELEASE AVRC_STATE_RELEASE /* key released */ + +typedef UINT8 tBTA_AV_STATE; + +/* command codes for BTA_AvVendorCmd */ +#define BTA_AV_CMD_CTRL AVRC_CMD_CTRL +#define BTA_AV_CMD_STATUS AVRC_CMD_STATUS +#define BTA_AV_CMD_SPEC_INQ AVRC_CMD_SPEC_INQ +#define BTA_AV_CMD_NOTIF AVRC_CMD_NOTIF +#define BTA_AV_CMD_GEN_INQ AVRC_CMD_GEN_INQ + +typedef UINT8 tBTA_AV_CMD; + +/* response codes for BTA_AvVendorRsp */ +#define BTA_AV_RSP_NOT_IMPL AVRC_RSP_NOT_IMPL +#define BTA_AV_RSP_ACCEPT AVRC_RSP_ACCEPT +#define BTA_AV_RSP_REJ AVRC_RSP_REJ +#define BTA_AV_RSP_IN_TRANS AVRC_RSP_IN_TRANS +#define BTA_AV_RSP_IMPL_STBL AVRC_RSP_IMPL_STBL +#define BTA_AV_RSP_CHANGED AVRC_RSP_CHANGED +#define BTA_AV_RSP_INTERIM AVRC_RSP_INTERIM + +typedef UINT8 tBTA_AV_CODE; + +/* error codes for BTA_AvProtectRsp */ +#define BTA_AV_ERR_NONE A2D_SUCCESS /* Success, no error */ +#define BTA_AV_ERR_BAD_STATE AVDT_ERR_BAD_STATE /* Message cannot be processed in this state */ +#define BTA_AV_ERR_RESOURCE AVDT_ERR_RESOURCE /* Insufficient resources */ +#define BTA_AV_ERR_BAD_CP_TYPE A2D_BAD_CP_TYPE /* The requested Content Protection Type is not supported */ +#define BTA_AV_ERR_BAD_CP_FORMAT A2D_BAD_CP_FORMAT /* The format of Content Protection Data is not correct */ + +typedef UINT8 tBTA_AV_ERR; + + +/* AV callback events */ +#define BTA_AV_ENABLE_EVT 0 /* AV enabled */ +#define BTA_AV_REGISTER_EVT 1 /* registered to AVDT */ +#define BTA_AV_OPEN_EVT 2 /* connection opened */ +#define BTA_AV_CLOSE_EVT 3 /* connection closed */ +#define BTA_AV_START_EVT 4 /* stream data transfer started */ +#define BTA_AV_STOP_EVT 5 /* stream data transfer stopped */ +#define BTA_AV_PROTECT_REQ_EVT 6 /* content protection request */ +#define BTA_AV_PROTECT_RSP_EVT 7 /* content protection response */ +#define BTA_AV_RC_OPEN_EVT 8 /* remote control channel open */ +#define BTA_AV_RC_CLOSE_EVT 9 /* remote control channel closed */ +#define BTA_AV_REMOTE_CMD_EVT 10 /* remote control command */ +#define BTA_AV_REMOTE_RSP_EVT 11 /* remote control response */ +#define BTA_AV_VENDOR_CMD_EVT 12 /* vendor dependent remote control command */ +#define BTA_AV_VENDOR_RSP_EVT 13 /* vendor dependent remote control response */ +#define BTA_AV_RECONFIG_EVT 14 /* reconfigure response */ +#define BTA_AV_SUSPEND_EVT 15 /* suspend response */ +#define BTA_AV_PENDING_EVT 16 /* incoming connection pending: + * signal channel is open and stream is not open + * after BTA_AV_SIG_TIME_VAL ms */ +#define BTA_AV_META_MSG_EVT 17 /* metadata messages */ +#define BTA_AV_REJECT_EVT 18 /* incoming connection rejected */ +#define BTA_AV_RC_FEAT_EVT 19 /* remote control channel peer supported features update */ +/* Max BTA event */ +#define BTA_AV_MAX_EVT 20 + +typedef UINT8 tBTA_AV_EVT; + +/* Event associated with BTA_AV_ENABLE_EVT */ +typedef struct +{ + tBTA_AV_FEAT features; +} tBTA_AV_ENABLE; + +/* Event associated with BTA_AV_REGISTER_EVT */ +typedef struct +{ + tBTA_AV_CHNL chnl; /* audio/video */ + tBTA_AV_HNDL hndl; /* Handle associated with the stream. */ + UINT8 app_id; /* ID associated with call to BTA_AvRegister() */ + tBTA_AV_STATUS status; +} tBTA_AV_REGISTER; + +/* data associated with BTA_AV_OPEN_EVT */ +#define BTA_AV_EDR_2MBPS 0x01 +#define BTA_AV_EDR_3MBPS 0x02 +typedef UINT8 tBTA_AV_EDR; + +typedef struct +{ + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + BD_ADDR bd_addr; + tBTA_AV_STATUS status; + BOOLEAN starting; + tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */ +} tBTA_AV_OPEN; + +/* data associated with BTA_AV_CLOSE_EVT */ +typedef struct +{ + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; +} tBTA_AV_CLOSE; + +/* data associated with BTA_AV_START_EVT */ +typedef struct +{ + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + tBTA_AV_STATUS status; + BOOLEAN initiator; /* TRUE, if local device initiates the START */ + BOOLEAN suspending; +} tBTA_AV_START; + +/* data associated with BTA_AV_SUSPEND_EVT */ +typedef struct +{ + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + BOOLEAN initiator; /* TRUE, if local device initiates the SUSPEND */ + tBTA_AV_STATUS status; +} tBTA_AV_SUSPEND; + +/* data associated with BTA_AV_RECONFIG_EVT */ +typedef struct +{ + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + tBTA_AV_STATUS status; +} tBTA_AV_RECONFIG; + +/* data associated with BTA_AV_PROTECT_REQ_EVT */ +typedef struct +{ + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + UINT8 *p_data; + UINT16 len; +} tBTA_AV_PROTECT_REQ; + +/* data associated with BTA_AV_PROTECT_RSP_EVT */ +typedef struct +{ + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + UINT8 *p_data; + UINT16 len; + tBTA_AV_ERR err_code; +} tBTA_AV_PROTECT_RSP; + +/* data associated with BTA_AV_RC_OPEN_EVT */ +typedef struct +{ + UINT8 rc_handle; + tBTA_AV_FEAT peer_features; + BD_ADDR peer_addr; + tBTA_AV_STATUS status; +} tBTA_AV_RC_OPEN; + +/* data associated with BTA_AV_RC_CLOSE_EVT */ +typedef struct +{ + UINT8 rc_handle; + BD_ADDR peer_addr; +} tBTA_AV_RC_CLOSE; + +/* data associated with BTA_AV_RC_FEAT_EVT */ +typedef struct +{ + UINT8 rc_handle; + tBTA_AV_FEAT peer_features; +} tBTA_AV_RC_FEAT; + +/* data associated with BTA_AV_REMOTE_CMD_EVT */ +typedef struct +{ + UINT8 rc_handle; + tBTA_AV_RC rc_id; + tBTA_AV_STATE key_state; + UINT8 len; + UINT8 *p_data; + tAVRC_HDR hdr; /* Message header. */ + UINT8 label; +} tBTA_AV_REMOTE_CMD; + +/* data associated with BTA_AV_REMOTE_RSP_EVT */ +typedef struct +{ + UINT8 rc_handle; + tBTA_AV_RC rc_id; + tBTA_AV_STATE key_state; + UINT8 len; + UINT8 *p_data; + tBTA_AV_CODE rsp_code; + UINT8 label; +} tBTA_AV_REMOTE_RSP; + +/* data associated with BTA_AV_VENDOR_CMD_EVT, BTA_AV_VENDOR_RSP_EVT */ +typedef struct +{ + UINT8 rc_handle; + UINT16 len; /* Max vendor dependent message is 512 */ + UINT8 label; + tBTA_AV_CODE code; + UINT32 company_id; + UINT8 *p_data; +} tBTA_AV_VENDOR; + +/* data associated with BTA_AV_META_MSG_EVT */ +typedef struct +{ + UINT8 rc_handle; + UINT16 len; + UINT8 label; + tBTA_AV_CODE code; + UINT32 company_id; + UINT8 *p_data; + tAVRC_MSG *p_msg; +} tBTA_AV_META_MSG; + +/* data associated with BTA_AV_PENDING_EVT */ +typedef struct +{ + BD_ADDR bd_addr; +} tBTA_AV_PEND; + +/* data associated with BTA_AV_REJECT_EVT */ +typedef struct +{ + BD_ADDR bd_addr; + tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the connection. */ +} tBTA_AV_REJECT; + + +/* union of data associated with AV callback */ +typedef union +{ + tBTA_AV_CHNL chnl; + tBTA_AV_ENABLE enable; + tBTA_AV_REGISTER registr; + tBTA_AV_OPEN open; + tBTA_AV_CLOSE close; + tBTA_AV_START start; + tBTA_AV_PROTECT_REQ protect_req; + tBTA_AV_PROTECT_RSP protect_rsp; + tBTA_AV_RC_OPEN rc_open; + tBTA_AV_RC_CLOSE rc_close; + tBTA_AV_REMOTE_CMD remote_cmd; + tBTA_AV_REMOTE_RSP remote_rsp; + tBTA_AV_VENDOR vendor_cmd; + tBTA_AV_VENDOR vendor_rsp; + tBTA_AV_RECONFIG reconfig; + tBTA_AV_SUSPEND suspend; + tBTA_AV_PEND pend; + tBTA_AV_META_MSG meta_msg; + tBTA_AV_REJECT reject; + tBTA_AV_RC_FEAT rc_feat; +} tBTA_AV; + + +#define BTA_AVC_PACKET_LEN AVRC_PACKET_LEN +#define BTA_VENDOR_DATA_OFFSET 6 +#define BTA_VENDOR_HEADER_LEN 4 +#define BTA_MAX_VENDOR_DEPENDENT_DATA_LEN (BTA_AVC_PACKET_LEN-BTA_VENDOR_DATA_OFFSET-BTA_VENDOR_HEADER_LEN) +#define BTA_GROUP_NAVI_MSG_OP_DATA_LEN 5 + +#define BTA_ERROR_INVALID_CMD AVRC_STS_BAD_CMD +#define BTA_ERROR_INVALID_PARAM AVRC_STS_BAD_PARAM +#define BTA_ERROR_BAD_CONTENTS AVRC_STS_NOT_FOUND +#define BTA_ERROR_INTERNAL AVRC_STS_INTERNAL_ERR + +#define BTA_AV_META_SINGLE_PACKET AVRC_PKT_SINGLE + +#define BTA_AV_CO_METADATA AVRC_CO_METADATA + +/* AV callback */ +typedef void (tBTA_AV_CBACK)(tBTA_AV_EVT event, tBTA_AV *p_data); + +/* type for stream state machine action functions */ +typedef void (*tBTA_AV_ACT)(void *p_cb, void *p_data); + +/* type for registering VDP */ +typedef void (tBTA_AV_REG) (tAVDT_CS *p_cs, char *p_service_name, void *p_data); + +/* AV configuration structure */ +typedef struct +{ + UINT32 company_id; /* AVRCP Company ID */ + UINT16 avrc_mtu; /* AVRCP MTU at L2CAP for control channel */ + UINT16 avrc_br_mtu; /* AVRCP MTU at L2CAP for browsing channel */ + UINT16 avrc_ct_cat; /* AVRCP controller categories */ + UINT16 avrc_tg_cat; /* AVRCP target categories */ + UINT16 sig_mtu; /* AVDTP signaling channel MTU at L2CAP */ + UINT16 audio_mtu; /* AVDTP audio transport channel MTU at L2CAP */ + const UINT16 *p_audio_flush_to;/* AVDTP audio transport channel flush timeout */ + UINT16 audio_mqs; /* AVDTP audio channel max data queue size */ + UINT16 video_mtu; /* AVDTP video transport channel MTU at L2CAP */ + UINT16 video_flush_to; /* AVDTP video transport channel flush timeout */ + BOOLEAN avrc_group; /* TRUE, to accept AVRC 1.3 group nevigation command */ + UINT8 num_co_ids; /* company id count in p_meta_co_ids */ + UINT8 num_evt_ids; /* event id count in p_meta_evt_ids */ + tBTA_AV_CODE rc_pass_rsp; /* the default response code for pass through commands */ + const UINT32 *p_meta_co_ids;/* the metadata Get Capabilities response for company id */ + const UINT8 *p_meta_evt_ids;/* the the metadata Get Capabilities response for event id */ + const tBTA_AV_ACT *p_act_tbl;/* the action function table for VDP stream */ + tBTA_AV_REG *p_reg; /* action function to register VDP */ +} tBTA_AV_CFG; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function BTA_AvEnable +** +** Description Enable the advanced audio/video service. When the enable +** operation is complete the callback function will be +** called with a BTA_AV_ENABLE_EVT. This function must +** be called before other function in the AV API are +** called. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, + tBTA_AV_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_AvDisable +** +** Description Disable the advanced audio/video service. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvDisable(void); + +/******************************************************************************* +** +** Function BTA_AvRegister +** +** Description Register the audio or video service to stack. When the +** operation is complete the callback function will be +** called with a BTA_AV_REGISTER_EVT. This function must +** be called before AVDT stream is open. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, + UINT8 app_id); + +/******************************************************************************* +** +** Function BTA_AvDeregister +** +** Description Deregister the audio or video service +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvDeregister(tBTA_AV_HNDL hndl); + +/******************************************************************************* +** +** Function BTA_AvOpen +** +** Description Opens an advanced audio/video connection to a peer device. +** When connection is open callback function is called +** with a BTA_AV_OPEN_EVT. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, + BOOLEAN use_rc, tBTA_SEC sec_mask); + +/******************************************************************************* +** +** Function BTA_AvClose +** +** Description Close the current streams. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvClose(tBTA_AV_HNDL handle); + +/******************************************************************************* +** +** Function BTA_AvDisconnect +** +** Description Close the connection to the address. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvDisconnect(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_AvStart +** +** Description Start audio/video stream data transfer. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvStart(void); + +/******************************************************************************* +** +** Function BTA_AvStop +** +** Description Stop audio/video stream data transfer. +** If suspend is TRUE, this function sends AVDT suspend signal +** to the connected peer(s). +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvStop(BOOLEAN suspend); + +/******************************************************************************* +** +** Function BTA_AvReconfig +** +** Description Reconfigure the audio/video stream. +** If suspend is TRUE, this function tries the suspend/reconfigure +** procedure first. +** If suspend is FALSE or when suspend/reconfigure fails, +** this function closes and re-opens the AVDT connection. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvReconfig(tBTA_AV_HNDL hndl, BOOLEAN suspend, UINT8 sep_info_idx, + UINT8 *p_codec_info, UINT8 num_protect, UINT8 *p_protect_info); + +/******************************************************************************* +** +** Function BTA_AvProtectReq +** +** Description Send a content protection request. This function can only +** be used if AV is enabled with feature BTA_AV_FEAT_PROTECT. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvProtectReq(tBTA_AV_HNDL hndl, UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function BTA_AvProtectRsp +** +** Description Send a content protection response. This function must +** be called if a BTA_AV_PROTECT_REQ_EVT is received. +** This function can only be used if AV is enabled with +** feature BTA_AV_FEAT_PROTECT. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, UINT8 error_code, UINT8 *p_data, + UINT16 len); + +/******************************************************************************* +** +** Function BTA_AvRemoteCmd +** +** Description Send a remote control command. This function can only +** be used if AV is enabled with feature BTA_AV_FEAT_RCCT. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id, + tBTA_AV_STATE key_state); + +/******************************************************************************* +** +** Function BTA_AvVendorCmd +** +** Description Send a vendor dependent remote control command. This +** function can only be used if AV is enabled with feature +** BTA_AV_FEAT_VENDOR. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvVendorCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE cmd_code, + UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function BTA_AvVendorRsp +** +** Description Send a vendor dependent remote control response. +** This function must be called if a BTA_AV_VENDOR_CMD_EVT +** is received. This function can only be used if AV is +** enabled with feature BTA_AV_FEAT_VENDOR. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvVendorRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, + UINT8 *p_data, UINT16 len, UINT32 company_id); + + +/******************************************************************************* +** +** Function BTA_AvOpenRc +** +** Description Open an AVRCP connection toward the device with the +** specified handle +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvOpenRc(tBTA_AV_HNDL handle); + +/******************************************************************************* +** +** Function BTA_AvCloseRc +** +** Description Close an AVRCP connection +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvCloseRc(UINT8 rc_handle); + +/******************************************************************************* +** +** Function BTA_AvMetaRsp +** +** Description Send a Metadata command/response. The message contained +** in p_pkt can be composed with AVRC utility functions. +** This function can only be used if AV is enabled with feature +** BTA_AV_FEAT_METADATA. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvMetaRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, + BT_HDR *p_pkt); + +/******************************************************************************* +** +** Function BTA_AvMetaCmd +** +** Description Send a Metadata/Advanced Control command. The message contained +** in p_pkt can be composed with AVRC utility functions. +** This function can only be used if AV is enabled with feature +** BTA_AV_FEAT_METADATA. +** This message is sent only when the peer supports the TG role. +*8 The only command makes sense right now is the absolute volume command. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_AvMetaCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CMD cmd_code, BT_HDR *p_pkt); + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_AV_API_H */ diff --git a/bta/include/bta_av_ci.h b/bta/include/bta_av_ci.h new file mode 100644 index 0000000..63668a9 --- /dev/null +++ b/bta/include/bta_av_ci.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * + * Copyright (C) 2005-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 interface file for advanced audio/video call-in functions. + * + ******************************************************************************/ +#ifndef BTA_AV_CI_H +#define BTA_AV_CI_H + +#include "bta_av_api.h" + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_av_ci_src_data_ready +** +** Description This function sends an event to the AV indicating that +** the phone has audio stream data ready to send and AV +** should call bta_av_co_audio_src_data_path() or +** bta_av_co_video_src_data_path(). +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl); + +/******************************************************************************* +** +** Function bta_av_ci_setconfig +** +** Description This function must be called in response to function +** bta_av_co_audio_setconfig() or bta_av_co_video_setconfig. +** Parameter err_code is set to an AVDTP status value; +** AVDT_SUCCESS if the codec configuration is ok, +** otherwise error. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, + UINT8 category, UINT8 num_seid, UINT8 *p_seid, + BOOLEAN recfg_needed); + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_AV_CI_H */ + diff --git a/bta/include/bta_av_co.h b/bta/include/bta_av_co.h new file mode 100644 index 0000000..862ac5e --- /dev/null +++ b/bta/include/bta_av_co.h @@ -0,0 +1,392 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 interface file for advanced audio/video call-out functions. + * + ******************************************************************************/ +#ifndef BTA_AV_CO_H +#define BTA_AV_CO_H + +#include "l2c_api.h" +#include "bta_av_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* TRUE to use SCMS-T content protection */ +#ifndef BTA_AV_CO_CP_SCMS_T +#define BTA_AV_CO_CP_SCMS_T FALSE +#endif + +/* the content protection IDs assigned by BT SIG */ +#define BTA_AV_CP_SCMS_T_ID 0x0002 +#define BTA_AV_CP_DTCP_ID 0x0001 + +#define BTA_AV_CP_LOSC 2 +#define BTA_AV_CP_INFO_LEN 3 + +#define BTA_AV_CP_SCMS_COPY_MASK 3 +#define BTA_AV_CP_SCMS_COPY_FREE 2 +#define BTA_AV_CP_SCMS_COPY_ONCE 1 +#define BTA_AV_CP_SCMS_COPY_NEVER 0 + +#define BTA_AV_CO_DEFAULT_AUDIO_OFFSET AVDT_MEDIA_OFFSET + +enum +{ + BTA_AV_CO_ST_INIT, + BTA_AV_CO_ST_IN, + BTA_AV_CO_ST_OUT, + BTA_AV_CO_ST_OPEN, + BTA_AV_CO_ST_STREAM +}; + + +/* data type for the Audio Codec Information*/ +typedef struct +{ + UINT16 bit_rate; /* SBC encoder bit rate in kbps */ + UINT16 bit_rate_busy; /* SBC encoder bit rate in kbps */ + UINT16 bit_rate_swampd;/* SBC encoder bit rate in kbps */ + UINT8 busy_level; /* Busy level indicating the bit-rate to be used */ + UINT8 codec_info[AVDT_CODEC_SIZE]; + UINT8 codec_type; /* Codec type */ +} tBTA_AV_AUDIO_CODEC_INFO; + +/******************************************************************************* +** +** Function bta_av_co_audio_init +** +** Description This callout function is executed by AV when it is +** started by calling BTA_AvEnable(). 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. +** +*******************************************************************************/ +BTA_API extern BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, + UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index); + +/******************************************************************************* +** +** 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 extern void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, + UINT8 num_snk, BD_ADDR addr); + +/******************************************************************************* +** +** Function bta_av_co_video_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 extern void bta_av_co_video_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, + UINT8 num_snk, BD_ADDR addr); + +/******************************************************************************* +** +** 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 extern 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); + +/******************************************************************************* +** +** Function bta_av_co_video_getconfig +** +** Description This callout function is executed by AV to retrieve the +** desired codec and content protection configuration for the +** video stream. +** +** +** Returns Stream codec and content protection configuration info. +** +*******************************************************************************/ +BTA_API extern UINT8 bta_av_co_video_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); + +/******************************************************************************* +** +** 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 extern 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); + +/******************************************************************************* +** +** Function bta_av_co_video_setconfig +** +** Description This callout function is executed by AV to set the +** codec and content protection configuration of the video stream. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_video_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); + +/******************************************************************************* +** +** Function bta_av_co_audio_open +** +** Description This function is called by AV when the audio stream connection +** is opened. +** BTA-AV maintains the MTU of A2DP streams. +** If this is the 2nd audio stream, mtu is the smaller of the 2 +** streams. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_audio_open(tBTA_AV_HNDL hndl, + tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu); + +/******************************************************************************* +** +** Function bta_av_co_video_open +** +** Description This function is called by AV when the video stream connection +** is opened. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_video_open(tBTA_AV_HNDL hndl, + tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu); + +/******************************************************************************* +** +** Function bta_av_co_audio_close +** +** Description This function is called by AV when the audio stream connection +** is closed. +** BTA-AV maintains the MTU of A2DP streams. +** When one stream is closed and no other audio stream is open, +** mtu is reported as 0. +** Otherwise, the MTU remains open is reported. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_audio_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT16 mtu); + +/******************************************************************************* +** +** Function bta_av_co_video_close +** +** Description This function is called by AV when the video stream connection +** is closed. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_video_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT16 mtu); + +/******************************************************************************* +** +** 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 extern void bta_av_co_audio_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr); + +/******************************************************************************* +** +** Function bta_av_co_video_start +** +** Description This function is called by AV when the video streaming data +** transfer is started. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_video_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr); + +/******************************************************************************* +** +** 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); + +/******************************************************************************* +** +** Function bta_av_co_video_stop +** +** Description This function is called by AV when the video streaming data +** transfer is stopped. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_video_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); + +/******************************************************************************* +** +** Function bta_av_co_audio_src_data_path +** +** Description This function is called to get the next data buffer from +** the audio codec +** +** Returns NULL if data is not ready. +** Otherwise, a GKI buffer (BT_HDR*) containing the audio data. +** +*******************************************************************************/ +BTA_API extern void * bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type, + UINT32 *p_len, UINT32 *p_timestamp); + +/******************************************************************************* +** +** Function bta_av_co_video_src_data_path +** +** Description This function is called to get the next data buffer from +** the video codec. +** +** Returns NULL if data is not ready. +** Otherwise, a video data buffer (UINT8*). +** +*******************************************************************************/ +BTA_API extern void * bta_av_co_video_src_data_path(tBTA_AV_CODEC codec_type, + UINT32 *p_len, UINT32 *p_timestamp); + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_av_co_audio_drop(tBTA_AV_HNDL hndl); + +/******************************************************************************* +** +** Function bta_av_co_video_report_conn +** +** Description This function is called by AV when the reporting channel is +** opened (open=TRUE) or closed (open=FALSE). +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_video_report_conn (BOOLEAN open, UINT8 avdt_handle); + +/******************************************************************************* +** +** Function bta_av_co_video_report_rr +** +** Description This function is called by AV when a Receiver Report is +** received +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_video_report_rr (UINT32 packet_lost); + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, UINT16 delay); + +/******************************************************************************* +** +** Function bta_av_co_video_delay +** +** Description This function is called by AV when the video stream connection +** needs to send the initial delay report to the connected SRC. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_av_co_video_delay(tBTA_AV_HNDL hndl, UINT16 delay); + +#endif /* BTA_AV_CO_H */ + diff --git a/bta/include/bta_av_sbc.h b/bta/include/bta_av_sbc.h new file mode 100644 index 0000000..98eb6ae --- /dev/null +++ b/bta/include/bta_av_sbc.h @@ -0,0 +1,207 @@ +/****************************************************************************** + * + * 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 interface to utility functions for dealing with SBC data + * frames and codec capabilities. + * + ******************************************************************************/ +#ifndef BTA_AV_SBC_H +#define BTA_AV_SBC_H + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* SBC packet header size */ +#define BTA_AV_SBC_HDR_SIZE A2D_SBC_MPL_HDR_LEN + +/******************************************************************************* +** +** Function bta_av_sbc_init_up_sample +** +** Description initialize the up sample +** +** src_sps: samples per second (source audio data) +** dst_sps: samples per second (converted audio data) +** bits: number of bits per pcm sample +** n_channels: number of channels (i.e. mono(1), stereo(2)...) +** +** Returns none +** +*******************************************************************************/ +extern void bta_av_sbc_init_up_sample (UINT32 src_sps, UINT32 dst_sps, + UINT16 bits, UINT16 n_channels); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (number of bytes) +** dst_samples: The size of p_dst (number of bytes) +** +** Note: An AE reported an issue with this function. +** When called with bta_av_sbc_up_sample(src, uint8_array_dst..) +** the byte before uint8_array_dst may get overwritten. +** Using uint16_array_dst avoids the problem. +** This issue is related to endian-ness and is hard to resolve +** in a generic manner. +** **************** Please use uint16 array as dst. +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_16s (16bits-stereo) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 4 bytes) +** dst_samples: The size of p_dst (in uint of 4 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_16m (16bits-mono) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 2 bytes) +** dst_samples: The size of p_dst (in uint of 2 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_8s (8bits-stereo) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 2 bytes) +** dst_samples: The size of p_dst (in uint of 2 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_8m (8bits-mono) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (number of bytes) +** dst_samples: The size of p_dst (number of bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample_8m (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_for_cap +** +** Description Determine the preferred SBC codec configuration for the +** given codec capabilities. The function is passed the +** preferred codec configuration and the peer codec +** capabilities for the stream. The function attempts to +** match the preferred capabilities with the configuration +** as best it can. The resulting codec configuration is +** returned in the same memory used for the capabilities. +** +** Returns 0 if ok, nonzero if error. +** Codec configuration in p_cap. +** +*******************************************************************************/ +extern UINT8 bta_av_sbc_cfg_for_cap(UINT8 *p_peer, tA2D_SBC_CIE *p_cap, tA2D_SBC_CIE *p_pref); + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_in_cap +** +** Description This function checks whether an SBC codec configuration +** is allowable for the given codec capabilities. +** +** Returns 0 if ok, nonzero if error. +** +*******************************************************************************/ +extern UINT8 bta_av_sbc_cfg_in_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap); + +/******************************************************************************* +** +** Function bta_av_sbc_bld_hdr +** +** Description This function builds the packet header for MPF1. +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_sbc_bld_hdr(BT_HDR *p_buf, UINT16 fr_per_pkt); + +#endif /* BTA_AV_SBC_H */ + diff --git a/bta/include/bta_dm_ci.h b/bta/include/bta_dm_ci.h new file mode 100644 index 0000000..bf0983e --- /dev/null +++ b/bta/include/bta_dm_ci.h @@ -0,0 +1,81 @@ +/****************************************************************************** + * + * Copyright (C) 2006-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 interface file for device mananger call-in functions. + * + ******************************************************************************/ +#ifndef BTA_DM_CI_H +#define BTA_DM_CI_H + +#include "bta_api.h" + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_dm_ci_io_req +** +** Description This function must be called in response to function +** bta_dm_co_io_req(), if *p_oob_data is set to BTA_OOB_UNKNOWN +** by bta_dm_co_io_req(). +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap, + tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function bta_dm_ci_rmt_oob +** +** Description This function must be called in response to function +** bta_dm_co_rmt_oob() to provide the OOB data associated +** with the remote device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_dm_ci_rmt_oob(BOOLEAN accept, BD_ADDR bd_addr, + BT_OCTET16 c, BT_OCTET16 r); +/******************************************************************************* +** +** Function bta_dm_sco_ci_data_ready +** +** Description This function sends an event to indicating that the phone +** has SCO data ready.. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_dm_sco_ci_data_ready(UINT16 event, UINT16 sco_handle); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/bta/include/bta_dm_co.h b/bta/include/bta_dm_co.h new file mode 100644 index 0000000..864104e --- /dev/null +++ b/bta/include/bta_dm_co.h @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * Copyright (C) 2006-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 interface file for device mananger callout functions. + * + ******************************************************************************/ +#ifndef BTA_DM_CO_H +#define BTA_DM_CO_H + +#include "bta_sys.h" + + +#ifndef BTA_SCO_OUT_PKT_SIZE + #define BTA_SCO_OUT_PKT_SIZE BTM_SCO_DATA_SIZE_MAX +#endif + +#define BTA_SCO_CODEC_PCM 0 /* used for regular SCO */ +#define BTA_SCO_CODEC_SBC 1 /* used for WBS */ +typedef UINT8 tBTA_SCO_CODEC_TYPE; + +#define BTA_DM_SCO_SAMP_RATE_8K 8000 +#define BTA_DM_SCO_SAMP_RATE_16K 16000 + +/* SCO codec information */ +typedef struct +{ + tBTA_SCO_CODEC_TYPE codec_type; +}tBTA_CODEC_INFO; + +#define BTA_DM_SCO_ROUTE_PCM BTM_SCO_ROUTE_PCM +#define BTA_DM_SCO_ROUTE_HCI BTM_SCO_ROUTE_HCI + +typedef tBTM_SCO_ROUTE_TYPE tBTA_DM_SCO_ROUTE_TYPE; + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** 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. +** +*******************************************************************************/ +BTA_API extern 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); + +/******************************************************************************* +** +** 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. +** +*******************************************************************************/ +BTA_API extern 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. +** +*******************************************************************************/ +BTA_API extern void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, BOOLEAN *p_upgrade ); + +/******************************************************************************* +** +** 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. +** +*******************************************************************************/ +BTA_API extern void bta_dm_co_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r); + +/******************************************************************************* +** +** 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 +** +** Parameters bd_addr - The peer device +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void bta_dm_co_rmt_oob(BD_ADDR bd_addr); + +/***************************************************************************** +** SCO over HCI Function Declarations +*****************************************************************************/ +/******************************************************************************* +** +** 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 Void. +** +*******************************************************************************/ +BTA_API extern tBTA_DM_SCO_ROUTE_TYPE bta_dm_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, + tBTA_CODEC_INFO *p_codec_info, UINT8 app_id); + + +/******************************************************************************* +** +** Function bta_dm_sco_co_open +** +** Description This function is executed when a SCO connection is open. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_dm_sco_co_open(UINT16 handle, UINT8 pkt_size, UINT16 event); + +/******************************************************************************* +** +** Function bta_dm_sco_co_close +** +** Description This function is called when a SCO connection is closed +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_dm_sco_co_close(void); + +/******************************************************************************* +** +** Function bta_dm_sco_co_out_data +** +** Description This function is called to send SCO data over HCI. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_dm_sco_co_out_data(BT_HDR **p_buf); + +/******************************************************************************* +** +** Function bta_dm_sco_co_in_data +** +** Description This function is called to send incoming SCO data to application. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_dm_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status); + + + +/******************************************************************************* +** +** 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. +** +*******************************************************************************/ +BTA_API extern 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 ); + + +/******************************************************************************* +** +** 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. +** +*******************************************************************************/ +BTA_API extern 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); + +// btla-specific ++ +/******************************************************************************* +** +** 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. +** +*******************************************************************************/ +BTA_API extern 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 ); +// btla-specific -- + +#endif diff --git a/bta/include/bta_fs_api.h b/bta/include/bta_fs_api.h new file mode 100644 index 0000000..a3c34e0 --- /dev/null +++ b/bta/include/bta_fs_api.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 public interface file for the file system of BTA, Broadcom's + * Bluetooth application layer for mobile phones. + * + ******************************************************************************/ +#ifndef BTA_FS_API_H +#define BTA_FS_API_H + +#include "bta_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* Configuration structure */ +typedef struct +{ + UINT16 max_file_len; /* Maximum size file name */ + UINT16 max_path_len; /* Maximum path length (includes appended file name) */ + char path_separator; /* 0x2f ('/'), or 0x5c ('\') */ +} tBTA_FS_CFG; + +extern tBTA_FS_CFG * p_bta_fs_cfg; + +#endif /* BTA_FS_API_H */ diff --git a/bta/include/bta_fs_ci.h b/bta/include/bta_fs_ci.h new file mode 100644 index 0000000..e2b5093 --- /dev/null +++ b/bta/include/bta_fs_ci.h @@ -0,0 +1,256 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 interface file for file system call-in functions. + * + ******************************************************************************/ +#ifndef BTA_FS_CI_H +#define BTA_FS_CI_H + +#include "bta_fs_co.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* Open Complete Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_FS_CO_STATUS status; + UINT32 file_size; + int fd; + const char *p_file; +} tBTA_FS_CI_OPEN_EVT; + +/* Read Ready Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_FS_CO_STATUS status; + int fd; + UINT16 num_read; +} tBTA_FS_CI_READ_EVT; + +/* Write Ready Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_FS_CO_STATUS status; + int fd; +} tBTA_FS_CI_WRITE_EVT; + +/* Get Directory Entry Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_FS_CO_STATUS status; +} tBTA_FS_CI_GETDIR_EVT; + +/* Resume Information Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_FS_CO_STATUS status; + BD_ADDR_PTR p_addr; + UINT8 *p_sess_info; + UINT32 timeout; + UINT32 offset; + UINT8 ssn; + UINT8 info; +} tBTA_FS_CI_RESUME_EVT; + +/* Action Complete Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_FS_CO_STATUS status; +} tBTA_FS_CI_ACTION_EVT; + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_fs_ci_write +** +** Description This function sends an event to BTA indicating the phone +** has written the number of bytes specified in the call-out +** function, bta_fs_co_write(), and is ready for more data. +** This function is used to control the TX data flow. +** Note: The data buffer is released by the stack aioer +** calling this function. +** +** Parameters fd - file descriptor passed to the stack in the +** bta_fs_ci_open call-in function. +** status - BTA_FS_CO_OK, BTA_FS_CO_NOSPACE, or BTA_FS_CO_FAIL +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_ci_write(int fd, tBTA_FS_CO_STATUS status, UINT16 evt); + +/******************************************************************************* +** +** Function bta_fs_ci_read +** +** Description This function sends an event to BTA indicating the phone has +** read in the requested amount of data specified in the +** bta_fs_co_read() call-out function. It should only be called +** when the requested number of bytes has been read in, or aioer +** the end of the file has been detected. +** +** Parameters fd - file descriptor passed to the stack in the +** bta_fs_ci_open call-in function. +** num_bytes_read - number of bytes read into the buffer +** specified in the read callout-function. +** status - BTA_FS_CO_OK if full buffer of data, +** BTA_FS_CO_EOF if the end of file has been reached, +** BTA_FS_CO_FAIL if an error has occurred. +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_ci_read(int fd, UINT16 num_bytes_read, + tBTA_FS_CO_STATUS status, UINT16 evt); + +/******************************************************************************* +** +** Function bta_fs_ci_open +** +** Description This function sends an event to BTA indicating the phone has +** finished opening a file for reading or writing. +** +** Parameters fd - file descriptor passed to the stack in the +** bta_fs_ci_open call-in function. +** status - BTA_FS_CO_OK if file was opened in mode specified +** in the call-out function. +** BTA_FS_CO_EACCES if the file exists, but contains +** the wrong access permissions. +** BTA_FS_CO_FAIL if any other error has occurred. +** file_size - The total size of the file +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_ci_open(int fd, tBTA_FS_CO_STATUS status, + UINT32 file_size, UINT16 evt); + +/******************************************************************************* +** +** Function bta_fs_ci_direntry +** +** Description This function is called in response to the +** bta_fs_co_getdirentry call-out function. +** +** Parameters status - BTA_FS_CO_OK if p_entry points to a valid entry. +** BTA_FS_CO_EODIR if no more entries (p_entry is ignored). +** BTA_FS_CO_FAIL if any errors have occurred. +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_ci_direntry(tBTA_FS_CO_STATUS status, UINT16 evt); + +/******************************************************************************* +** +** Function bta_fs_ci_resume +** +** Description This function is called in response to the +** bta_fs_co_resume call-out function. +** +** Parameters p_sess_info - the stored session ID and related information. +** ssn - the stored session sequence number. +** info - the stored BTA specific information (like last active operation). +** status - BTA_FS_CO_OK if p_entry points to a valid entry. +** BTA_FS_CO_FAIL if any errors have occurred. +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_ci_resume (BD_ADDR_PTR p_addr, UINT8 *p_sess_info, + UINT32 timeout, UINT32 offset, UINT8 ssn, UINT8 info, + tBTA_FS_CO_STATUS status, UINT16 evt); + +/******************************************************************************* +** +** Function bta_fs_ci_action +** +** Description This function is called in response to one of the action +** call-out functions: bta_fs_co_copy, bta_fs_co_rename or +** bta_fs_co_set_perms. +** +** Parameters status - BTA_FS_CO_OK if the action is succession. +** BTA_FS_CO_FAIL if any errors have occurred. +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_ci_action(tBTA_FS_CO_STATUS status, UINT16 evt); + +/******************************************************************************* +** +** Function bta_fs_ci_resume_op +** +** Description This function sends an event to BTA indicating the phone has +** finished opening a file for reading or writing on resume. +** +** Parameters fd - file descriptor passed to the stack in the +** bta_fs_ci_open call-in function. +** status - BTA_FS_CO_OK if file was opened in mode specified +** in the call-out function. +** BTA_FS_CO_EACCES if the file exists, but contains +** the wrong access permissions. +** BTA_FS_CO_FAIL if any other error has occurred. +** p_file - The file name associated with fd +** file_size - The total size of the file +** evt - Used Internally by BTA -> MUST be same value passed +** in call-out function. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_ci_resume_op(int fd, tBTA_FS_CO_STATUS status, const char *p_file, + UINT32 file_size, UINT16 evt); + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_FS_CI_H */ + diff --git a/bta/include/bta_fs_co.h b/bta/include/bta_fs_co.h new file mode 100644 index 0000000..7ab16fa --- /dev/null +++ b/bta/include/bta_fs_co.h @@ -0,0 +1,703 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 interface file for the synchronization server call-out + * functions. + * + ******************************************************************************/ +#ifndef BTA_FS_CO_H +#define BTA_FS_CO_H + +#include <time.h> + +#include "bta_api.h" +#include "goep_fs.h" +#include "obx_api.h" + +/***************************************************************************** +** Constants and Data Types +*****************************************************************************/ + +#ifndef BTA_FS_CO_MAX_SSN_ENTRIES +#define BTA_FS_CO_MAX_SSN_ENTRIES 10 +#endif + +/* Maximum path length supported by FS_CO */ +#ifndef BTA_FS_CO_PATH_LEN +#define BTA_FS_CO_PATH_LEN 294 +#endif + +#ifndef BTA_FS_CO_TEST_ROOT +#define BTA_FS_CO_TEST_ROOT "test_files" +#endif + +#define BTA_FS_CO_TEST_TYPE_NONE 0 +#define BTA_FS_CO_TEST_TYPE_REJECT 1 +#define BTA_FS_CO_TEST_TYPE_SUSPEND 2 + +#ifndef BTA_FS_CO_TEST_AB_END +#define BTA_FS_CO_TEST_AB_END BTA_FS_CO_TEST_TYPE_NONE +#endif + +/************************** +** Common Definitions +***************************/ + +/* Status codes returned by call-out functions, or in call-in functions as status */ +#define BTA_FS_CO_OK GOEP_OK +#define BTA_FS_CO_FAIL GOEP_FAIL /* Used to pass all other errors */ +#define BTA_FS_CO_EACCES GOEP_EACCES +#define BTA_FS_CO_ENOTEMPTY GOEP_ENOTEMPTY +#define BTA_FS_CO_EOF GOEP_EOF +#define BTA_FS_CO_EODIR GOEP_EODIR +#define BTA_FS_CO_ENOSPACE GOEP_ENOSPACE/* Returned in bta_fs_ci_open if no room */ +#define BTA_FS_CO_EIS_DIR GOEP_EIS_DIR +#define BTA_FS_CO_RESUME GOEP_RESUME /* used in ci_open, on resume */ +#define BTA_FS_CO_NONE GOEP_NONE /* used in ci_open, on resume (no file to resume) */ + +typedef UINT16 tBTA_FS_CO_STATUS; + +/* the index to the permission flags */ +#define BTA_FS_PERM_USER 0 +#define BTA_FS_PERM_GROUP 1 +#define BTA_FS_PERM_OTHER 2 +/* max number of the permission flags */ +#define BTA_FS_PERM_SIZE 3 + +/* Flags passed to the open function (bta_fs_co_open) +** Values are OR'd together. (First 3 are +** mutually exclusive. +*/ +#define BTA_FS_O_RDONLY GOEP_O_RDONLY +#define BTA_FS_O_WRONLY GOEP_O_WRONLY +#define BTA_FS_O_RDWR GOEP_O_RDWR + +#define BTA_FS_O_CREAT GOEP_O_CREAT +#define BTA_FS_O_EXCL GOEP_O_EXCL +#define BTA_FS_O_TRUNC GOEP_O_TRUNC + +#define BTA_FS_O_MODE_MASK(x) (((UINT16)(x)) & 0x0003) + +/* Origin for the bta_fs_co_seek function */ +#define BTA_FS_SEEK_SET GOEP_SEEK_SET +#define BTA_FS_SEEK_CUR GOEP_SEEK_CUR +#define BTA_FS_SEEK_END GOEP_SEEK_END + +/* mode field in bta_fs_co_access callout */ +#define BTA_FS_ACC_EXIST GOEP_ACC_EXIST +#define BTA_FS_ACC_READ GOEP_ACC_READ +#define BTA_FS_ACC_RDWR GOEP_ACC_RDWR + +#define BTA_FS_LEN_UNKNOWN GOEP_LEN_UNKNOWN +#define BTA_FS_INVALID_FD GOEP_INVALID_FD +#define BTA_FS_INVALID_APP_ID (0xFF) /* this app_id is reserved */ + +/* mode field in tBTA_FS_DIRENTRY (OR'd together) */ +#define BTA_FS_A_RDONLY GOEP_A_RDONLY +#define BTA_FS_A_DIR GOEP_A_DIR /* Entry is a sub directory */ + +#define BTA_FS_CTIME_LEN GOEP_CTIME_LEN /* Creation time "yyyymmddTHHMMSSZ" */ + +/* Return structure type for a directory entry */ +typedef struct +{ + UINT32 refdata; /* holder for OS specific data used to get next entry */ + UINT32 filesize; + char crtime[BTA_FS_CTIME_LEN]; /* "yyyymmddTHHMMSSZ", or "" if none */ + char *p_name; /* Contains the addr of memory to copy name into */ + UINT8 mode; /* BTA_FS_A_RDONLY and/or BTA_FS_A_DIR */ +} tBTA_FS_DIRENTRY; + +/* session state */ +enum +{ + BTA_FS_CO_SESS_ST_NONE, + BTA_FS_CO_SESS_ST_ACTIVE, + BTA_FS_CO_SESS_ST_SUSPEND, + BTA_FS_CO_SESS_ST_RESUMING +}; +typedef UINT8 tBTA_FS_CO_SESS_ST; + + + +/* a data type to keep an array of ssn/file offset - the info can be saved to NV */ +typedef struct +{ + char path[BTA_FS_CO_PATH_LEN + 1]; /* the "current path". path[0]==0-> root */ + char file[BTA_FS_CO_PATH_LEN + 1]; /* file[0] !=0 on resume -> the previous suspended session had opened files */ + int oflags; /* the flag to open the file */ + BD_ADDR bd_addr; + UINT8 sess_info[OBX_SESSION_INFO_SIZE]; + UINT32 offset; /* last file offset */ + UINT32 timeout; /* the timeout value on suspend */ + time_t suspend_time; /* the time of suspend */ + UINT16 nbytes; /* number of bytes for last read/write */ + UINT8 ssn; + UINT8 info; /* info for BTA on the client side */ + UINT8 app_id; + tBTA_FS_CO_SESS_ST sess_st; +} tBTA_FS_CO_SESSION; + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +/************************** +** Common Functions +***************************/ +/******************************************************************************* +** +** Function bta_fs_co_init +** +** Description This function is executed as a part of the start up sequence +** to make sure the control block is initialized. +** +** Parameters void. +** +** Returns void +** +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_init(void); + +/******************************************************************************* +** +** 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(). +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_open(const char *p_path, int oflags, UINT32 size, + UINT16 evt, UINT8 app_id); + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern 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); + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_resume_op(UINT32 offset, UINT16 evt, UINT8 app_id); + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern 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); + +/******************************************************************************* +** +** 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(). +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_resume(UINT16 evt, UINT8 app_id); + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_sess_ssn(int fd, UINT8 ssn, UINT8 app_id); + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_setdir(const char *p_path, UINT8 app_id); + +/******************************************************************************* +** +** 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 ] +** +*******************************************************************************/ +BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_close(int fd, UINT8 app_id); + +/******************************************************************************* +** +** 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. +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_read(int fd, UINT8 *p_buf, UINT16 nbytes, UINT16 evt, + UINT8 ssn, UINT8 app_id); + +/******************************************************************************* +** +** 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, +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_write(int fd, const UINT8 *p_buf, UINT16 nbytes, UINT16 evt, + UINT8 ssn, UINT8 app_id); + +/******************************************************************************* +** +** 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: BTA_FS_SEEK_SET, BTA_FS_SEEK_CUR, +** or BTA_FS_SEEK_END. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_seek (int fd, INT32 offset, INT16 origin, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_access +** +** Description This function is called to check the existence of a file or +** directory. +** +** 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] +** +*******************************************************************************/ +BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_access(const char *p_path, int mode, + BOOLEAN *p_is_dir, UINT8 app_id); + +/******************************************************************************* +** +** 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] +** +*******************************************************************************/ +BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_mkdir(const char *p_path, UINT8 app_id); + +/******************************************************************************* +** +** 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] +** +*******************************************************************************/ +BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_rmdir(const char *p_path, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_unlink +** +** Description This function is called by 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] +** +*******************************************************************************/ +BTA_API extern tBTA_FS_CO_STATUS bta_fs_co_unlink(const char *p_path, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_getdirentry +** +** Description This function is called to retrieve a directory entry for the +** specified 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 +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_getdirentry(const char *p_path, BOOLEAN first_item, + tBTA_FS_DIRENTRY *p_entry, UINT16 evt, + UINT8 app_id); + +/******************************************************************************* +** +** 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] +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_copy(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id); + +/******************************************************************************* +** +** 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] +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_rename(const char *p_src_path, const char *p_dest_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id); + +/******************************************************************************* +** +** 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] +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_set_perms(const char *p_src_path, UINT8 *p_perms, UINT16 evt, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_sess_fopen +** +** Description This function is called by bta_fs_co_open to keep track of +** the opened file (for reliable session suspend/resume.) +** +** Parameters p_path - Fully qualified path and file name. +** oflags - permissions and mode (see constants above) +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_sess_fopen(const char *p_path, int oflags, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_sess_fclose +** +** Description This function is called by bta_fs_co_close +** +** Parameters 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 +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_sess_fclose(UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_sess_offset +** +** Description This function is called by bta_fs_co_write to keep track of +** the last file offset (Only the receiving side needs to keep +** track of the file offset) +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_sess_offset(UINT8 ssn, INT32 pos, UINT16 nbytes, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_suspended_addr +** +** Description find the peer address of the suspended session control block +** for the given an app_id. +** +** Returns the control block found. +** +*******************************************************************************/ +BTA_API extern UINT8 *bta_fs_co_suspended_addr(UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_num_suspended_session +** +** Description find the number of suspended session control blocks for the +** given an app_id. +** +** Returns the number of control blocks found. +** +*******************************************************************************/ +BTA_API extern UINT8 bta_fs_co_num_suspended_session(UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_get_active_session +** +** Description find the active session control block for the given an app_id. +** +** Returns the control block found. +** +*******************************************************************************/ +BTA_API extern tBTA_FS_CO_SESSION *bta_fs_co_get_active_session(UINT8 app_id); + +/******************************************************************************* +** +** Function bta_fs_co_init_db +** +** Description Initialize the session control blocks for platform. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_fs_co_init_db (tBTA_FS_CO_SESSION *p_first); + +/******************************************************************************* +** +** Function bta_fs_convert_oflags +** +** Description This function converts the open flags from BTA into MFS. +** +** Returns BTA FS status value. +** +*******************************************************************************/ +BTA_API extern int bta_fs_convert_bta_oflags(int bta_oflags); + +#endif /* BTA_FS_CO_H */ diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h new file mode 100644 index 0000000..0404847 --- /dev/null +++ b/bta/include/bta_gatt_api.h @@ -0,0 +1,1219 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 public interface file for BTA GATT. + * + ******************************************************************************/ +#ifndef BTA_GATT_API_H +#define BTA_GATT_API_H + +#include "bta_api.h" +#include "gatt_api.h" + +#ifndef BTA_GATT_INCLUDED +#define BTA_GATT_INCLUDED FALSE +#endif + + +#if ((BLE_INCLUDED == FALSE) && (BTA_GATT_INCLUDED == TRUE)) +#undef BTA_GATT_INCLUDED +#define BTA_GATT_INCLUDED FALSE +#endif + + +#ifndef BTA_GATT_DEBUG +#define BTA_GATT_DEBUG FALSE +#endif + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/************************** +** Common Definitions +***************************/ +/* GATT ID */ +typedef struct +{ + tBT_UUID uuid; /* uuid of the attribute */ + UINT8 inst_id; /* instance ID */ +} tBTA_GATT_ID; + +/* Success code and error codes */ +#define BTA_GATT_OK GATT_SUCCESS +#define BTA_GATT_INVALID_HANDLE GATT_INVALID_HANDLE /* 0x0001 */ +#define BTA_GATT_READ_NOT_PERMIT GATT_READ_NOT_PERMIT /* 0x0002 */ +#define BTA_GATT_WRITE_NOT_PERMIT GATT_WRITE_NOT_PERMIT /* 0x0003 */ +#define BTA_GATT_INVALID_PDU GATT_INVALID_PDU /* 0x0004 */ +#define BTA_GATT_INSUF_AUTHENTICATION GATT_INSUF_AUTHENTICATION /* 0x0005 */ +#define BTA_GATT_REQ_NOT_SUPPORTED GATT_REQ_NOT_SUPPORTED /* 0x0006 */ +#define BTA_GATT_INVALID_OFFSET GATT_INVALID_OFFSET /* 0x0007 */ +#define BTA_GATT_INSUF_AUTHORIZATION GATT_INSUF_AUTHORIZATION /* 0x0008 */ +#define BTA_GATT_PREPARE_Q_FULL GATT_PREPARE_Q_FULL /* 0x0009 */ +#define BTA_GATT_NOT_FOUND GATT_NOT_FOUND /* 0x000a */ +#define BTA_GATT_NOT_LONG GATT_NOT_LONG /* 0x000b */ +#define BTA_GATT_INSUF_KEY_SIZE GATT_INSUF_KEY_SIZE /* 0x000c */ +#define BTA_GATT_INVALID_ATTR_LEN GATT_INVALID_ATTR_LEN /* 0x000d */ +#define BTA_GATT_ERR_UNLIKELY GATT_ERR_UNLIKELY /* 0x000e */ +#define BTA_GATT_INSUF_ENCRYPTION GATT_INSUF_ENCRYPTION /* 0x000f */ +#define BTA_GATT_UNSUPPORT_GRP_TYPE GATT_UNSUPPORT_GRP_TYPE /* 0x0010 */ +#define BTA_GATT_INSUF_RESOURCE GATT_INSUF_RESOURCE /* 0x0011 */ + + +#define BTA_GATT_ILLEGAL_PARAMETER GATT_ILLEGAL_PARAMETER /* 0x0087 */ +#define BTA_GATT_NO_RESOURCES GATT_NO_RESOURCES /* 0x0080 */ +#define BTA_GATT_INTERNAL_ERROR GATT_INTERNAL_ERROR /* 0x0081 */ +#define BTA_GATT_WRONG_STATE GATT_WRONG_STATE /* 0x0082 */ +#define BTA_GATT_DB_FULL GATT_DB_FULL /* 0x0083 */ +#define BTA_GATT_BUSY GATT_BUSY /* 0x0084 */ +#define BTA_GATT_ERROR GATT_ERROR /* 0x0085 */ +#define BTA_GATT_CMD_STARTED GATT_CMD_STARTED /* 0x0086 */ +#define BTA_GATT_PENDING GATT_PENDING /* 0x0088 */ +#define BTA_GATT_AUTH_FAIL GATT_AUTH_FAIL /* 0x0089 */ +#define BTA_GATT_MORE GATT_MORE /* 0x008a */ +#define BTA_GATT_INVALID_CFG GATT_INVALID_CFG /* 0x008b */ +#define BTA_GATT_DUP_REG 0x008c +#define BTA_GATT_ALREADY_OPEN 0x008d /* 0x008d */ +typedef UINT8 tBTA_GATT_STATUS; + +#define BTA_GATT_INVALID_CONN_ID GATT_INVALID_CONN_ID + + +/* Client callback function events */ +#define BTA_GATTC_REG_EVT 0 /* GATT client is registered. */ +#define BTA_GATTC_DEREG_EVT 1 /* GATT client deregistered event */ +#define BTA_GATTC_OPEN_EVT 2 /* GATTC open request status event */ +#define BTA_GATTC_READ_CHAR_EVT 3 /* GATT read characteristic event */ +#define BTA_GATTC_WRITE_CHAR_EVT 4 /* GATT write characteristic or char descriptor event */ +#define BTA_GATTC_CLOSE_EVT 5 /* GATTC close request status event */ +#define BTA_GATTC_SEARCH_CMPL_EVT 6 /* GATT discovery complete event */ +#define BTA_GATTC_SEARCH_RES_EVT 7 /* GATT discovery result event */ +#define BTA_GATTC_READ_DESCR_EVT 8 /* GATT read characterisitc descriptor event */ +#define BTA_GATTC_WRITE_DESCR_EVT 9 /* GATT write characteristic descriptor event */ +#define BTA_GATTC_NOTIF_EVT 10 /* GATT attribute notification event */ +#define BTA_GATTC_PREP_WRITE_EVT 11 /* GATT prepare write event */ +#define BTA_GATTC_EXEC_EVT 12 /* execute write complete event */ +#define BTA_GATTC_ACL_EVT 13 /* ACL up event */ +#define BTA_GATTC_CANCEL_OPEN_EVT 14 /* cancel open event */ +#define BTA_GATTC_SRVC_CHG_EVT 15 /* service change event */ +typedef UINT8 tBTA_GATTC_EVT; + +typedef tGATT_IF tBTA_GATTC_IF; + +typedef struct +{ + UINT16 unit; /* as UUIUD defined by SIG */ + UINT16 descr; /* as UUID as defined by SIG */ + tGATT_FORMAT format; + INT8 exp; + UINT8 name_spc; /* The name space of the description */ +}tBTA_GATT_CHAR_PRES; + +#define BTA_GATT_CLT_CONFIG_NONE GATT_CLT_CONFIG_NONE /* 0x0000 */ +#define BTA_GATT_CLT_CONFIG_NOTIFICATION GATT_CLT_CONFIG_NOTIFICATION /* 0x0001 */ +#define BTA_GATT_CLT_CONFIG_INDICATION GATT_CLT_CONFIG_INDICATION /* 0x0002 */ +typedef UINT16 tBTA_GATT_CLT_CHAR_CONFIG; + +/* characteristic descriptor: server configuration value +*/ +#define BTA_GATT_SVR_CONFIG_NONE GATT_SVR_CONFIG_NONE /* 0x0000 */ +#define BTA_GATT_SVR_CONFIG_BROADCAST GATT_SVR_CONFIG_BROADCAST /* 0x0001 */ +typedef UINT16 tBTA_GATT_SVR_CHAR_CONFIG; + +/* Characteristic Aggregate Format attribute value +*/ +#define BTA_GATT_AGGR_HANDLE_NUM_MAX 10 +typedef struct +{ + UINT8 num_handle; + UINT16 handle_list[BTA_GATT_AGGR_HANDLE_NUM_MAX]; +} tBTA_GATT_CHAR_AGGRE; +typedef tGATT_VALID_RANGE tBTA_GATT_VALID_RANGE; + +typedef struct +{ + UINT16 len; + UINT8 *p_value; +}tBTA_GATT_UNFMT; + +#define BTA_GATT_MAX_ATTR_LEN GATT_MAX_ATTR_LEN + +#define BTA_GATTC_TYPE_WRITE GATT_WRITE +#define BTA_GATTC_TYPE_WRITE_NO_RSP GATT_WRITE_NO_RSP +typedef UINT8 tBTA_GATTC_WRITE_TYPE; + +#define BTA_GATT_CONN_UNKNOWN 0 +#define BTA_GATT_CONN_NO_RESOURCES GATT_CONN_NO_RESOURCES /* connection fail for l2cap resource failure */ +#define BTA_GATT_CONN_TIMEOUT GATT_CONN_TIMEOUT /* 0x08 connection timeout */ +#define BTA_GATT_CONN_TERMINATE_PEER_USER GATT_CONN_TERMINATE_PEER_USER /* 0x13 connection terminate by peer user */ +#define BTA_GATT_CONN_TERMINATE_LOCAL_HOST GATT_CONN_TERMINATE_LOCAL_HOST/* 0x16 connectionterminated by local host */ +#define BTA_GATT_CONN_FAIL_ESTABLISH GATT_CONN_FAIL_ESTABLISH /* 0x03E connection fail to establish */ +#define BTA_GATT_CONN_LMP_TIMEOUT GATT_CONN_LMP_TIMEOUT /* 0x22 connection fail for LMP response tout */ +#define BTA_GATT_CONN_CANCEL GATT_CONN_CANCEL /* 0x0100 L2CAP connection cancelled */ +#define BTA_GATT_CONN_NONE 0x0101 /* 0x0101 no connection to cancel */ +typedef UINT16 tBTA_GATT_REASON; + +typedef struct +{ + tBTA_GATT_ID id; + BOOLEAN is_primary; +}tBTA_GATT_SRVC_ID; + +typedef struct +{ + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; +}tBTA_GATTC_CHAR_ID; + +typedef struct +{ + tBTA_GATTC_CHAR_ID char_id; + tBT_UUID descr_type; +}tBTA_GATTC_CHAR_DESCR_ID; + +typedef struct +{ + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_SRVC_ID incl_svc_id; +}tBTA_GATTC_INCL_SVC_ID; + +#define BTA_GATT_TYPE_CHAR 0 +#define BTA_GATT_TYPE_CHAR_DESCR 1 +typedef UINT8 tBTA_GATT_ID_TYPE; + +typedef struct +{ + tBTA_GATT_ID_TYPE id_type; + union + { + tBTA_GATTC_CHAR_ID char_id; + tBTA_GATTC_CHAR_DESCR_ID char_descr_id; + + } id_value; +}tBTA_GATTC_ATTR_ID; + +#define BTA_GATTC_MULTI_MAX GATT_MAX_READ_MULTI_HANDLES + +typedef struct +{ + UINT8 num_attr; + tBTA_GATTC_ATTR_ID id_list[BTA_GATTC_MULTI_MAX]; + +}tBTA_GATTC_MULTI; + +#define BTA_GATT_AUTH_REQ_NONE GATT_AUTH_REQ_NONE +#define BTA_GATT_AUTH_REQ_NO_MITM GATT_AUTH_REQ_NO_MITM /* unauthenticated encryption */ +#define BTA_GATT_AUTH_REQ_MITM GATT_AUTH_REQ_MITM /* authenticated encryption */ +#define BTA_GATT_AUTH_REQ_SIGNED_NO_MITM GATT_AUTH_REQ_SIGNED_NO_MITM +#define BTA_GATT_AUTH_REQ_SIGNED_MITM GATT_AUTH_REQ_SIGNED_MITM + +typedef tGATT_AUTH_REQ tBTA_GATT_AUTH_REQ; + +enum +{ + BTA_GATTC_ATTR_TYPE_INCL_SRVC, + BTA_GATTC_ATTR_TYPE_CHAR, + BTA_GATTC_ATTR_TYPE_CHAR_DESCR, + BTA_GATTC_ATTR_TYPE_SRVC +}; +typedef UINT8 tBTA_GATTC_ATTR_TYPE; + + +typedef struct +{ + tBT_UUID uuid; + UINT16 s_handle; + UINT16 e_handle; /* used for service only */ + UINT8 attr_type; + UINT8 id; + UINT8 prop; /* used when attribute type is characteristic */ + BOOLEAN is_primary; /* used when attribute type is service */ +}tBTA_GATTC_NV_ATTR; + +/* callback data structure */ +typedef struct +{ + tBTA_GATT_STATUS status; + tBTA_GATTC_IF client_if; +// btla-specific ++ + tBT_UUID app_uuid; +// btla-specific -- +}tBTA_GATTC_REG; + +typedef struct +{ + UINT8 num_pres_fmt; /* number of presentation format aggregated*/ + tBTA_GATTC_CHAR_DESCR_ID pre_format[BTA_GATTC_MULTI_MAX]; +}tBTA_GATT_CHAR_AGGRE_VALUE; + +typedef union +{ + tBTA_GATT_CHAR_AGGRE_VALUE aggre_value; + tBTA_GATT_UNFMT unformat; + +}tBTA_GATT_READ_VAL; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBT_UUID descr_type; + tBTA_GATT_READ_VAL *p_value; +}tBTA_GATTC_READ; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; + tBTA_GATT_SRVC_ID srvc_id; + tBTA_GATT_ID char_id; + tBT_UUID descr_type; +}tBTA_GATTC_WRITE; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; +}tBTA_GATTC_EXEC_CMPL; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_STATUS status; +}tBTA_GATTC_SEARCH_CMPL; + +typedef struct +{ + UINT16 conn_id; + tBTA_GATT_SRVC_ID service_uuid; +}tBTA_GATTC_SRVC_RES; + + +typedef struct +{ + tBTA_GATT_STATUS status; + UINT16 conn_id; + tBTA_GATTC_IF client_if; + BD_ADDR remote_bda; +}tBTA_GATTC_OPEN; + +typedef struct +{ + tBTA_GATT_STATUS status; + UINT16 conn_id; + tBTA_GATTC_IF client_if; + BD_ADDR remote_bda; + tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect event is reported */ +}tBTA_GATTC_CLOSE; + +typedef struct +{ + UINT16 conn_id; + BD_ADDR bda; + tBTA_GATTC_CHAR_ID char_id; + tBT_UUID descr_type; + UINT16 len; + UINT8 value[BTA_GATT_MAX_ATTR_LEN]; + BOOLEAN is_notify; +}tBTA_GATTC_NOTIFY; + +// btla-specific ++ +typedef struct +{ + tBTA_GATT_STATUS status; + tBTA_GATTC_IF client_if; + UINT16 conn_id; + BD_ADDR remote_bda; +}tBTA_GATTC_OPEN_CLOSE; +// btla-specific -- + +typedef union +{ + tBTA_GATT_STATUS status; + + tBTA_GATTC_SEARCH_CMPL search_cmpl; /* discovery complete */ + tBTA_GATTC_SRVC_RES srvc_res; /* discovery result */ + tBTA_GATTC_REG reg_oper; /* registration data */ + tBTA_GATTC_OPEN open; + tBTA_GATTC_CLOSE close; + tBTA_GATTC_READ read; /* read attribute/descriptor data */ + tBTA_GATTC_WRITE write; /* write complete data */ + tBTA_GATTC_EXEC_CMPL exec_cmpl; /* execute complete */ + tBTA_GATTC_NOTIFY notify; /* notification/indication event data */ + BD_ADDR remote_bda; /* service change event */ +} tBTA_GATTC; + +/* Client callback function */ +typedef void (tBTA_GATTC_CBACK)(tBTA_GATTC_EVT event, tBTA_GATTC *p_data); + + +/* GATT Server Data Structure */ +/* Server callback function events */ +#define BTA_GATTS_REG_EVT 0 +#define BTA_GATTS_READ_EVT GATTS_REQ_TYPE_READ /* 1 */ +#define BTA_GATTS_WRITE_EVT GATTS_REQ_TYPE_WRITE /* 2 */ +#define BTA_GATTS_EXEC_WRITE_EVT GATTS_REQ_TYPE_WRITE_EXEC /* 3 */ +#define BTA_GATTS_MTU_EVT GATTS_REQ_TYPE_MTU /* 4 */ +#define BTA_GATTS_CONF_EVT GATTS_REQ_TYPE_CONF /* 5 */ +#define BTA_GATTS_DEREG_EVT 6 +#define BTA_GATTS_CREATE_EVT 7 +#define BTA_GATTS_ADD_INCL_SRVC_EVT 8 +#define BTA_GATTS_ADD_CHAR_EVT 9 +#define BTA_GATTS_ADD_CHAR_DESCR_EVT 10 +#define BTA_GATTS_DELELTE_EVT 11 +#define BTA_GATTS_START_EVT 12 +#define BTA_GATTS_STOP_EVT 13 +#define BTA_GATTS_CONNECT_EVT 14 +#define BTA_GATTS_DISCONNECT_EVT 15 +#define BTA_GATTS_OPEN_EVT 16 +#define BTA_GATTS_CANCEL_OPEN_EVT 17 +#define BTA_GATTS_CLOSE_EVT 18 + +typedef UINT8 tBTA_GATTS_EVT; +typedef tGATT_IF tBTA_GATTS_IF; + +/* Attribute permissions +*/ +#define BTA_GATT_PERM_READ GATT_PERM_READ /* bit 0 - 0x0001 */ +#define BTA_GATT_PERM_READ_ENCRYPTED GATT_PERM_READ_ENCRYPTED /* bit 1 - 0x0002 */ +#define BTA_GATT_PERM_READ_ENC_MITM GATT_PERM_READ_ENC_MITM /* bit 2 - 0x0004 */ +#define BTA_GATT_PERM_WRITE GATT_PERM_WRITE /* bit 4 - 0x0010 */ +#define BTA_GATT_PERM_WRITE_ENCRYPTED GATT_PERM_WRITE_ENCRYPTED /* bit 5 - 0x0020 */ +#define BTA_GATT_PERM_WRITE_ENC_MITM GATT_PERM_WRITE_ENC_MITM /* bit 6 - 0x0040 */ +#define BTA_GATT_PERM_WRITE_SIGNED GATT_PERM_WRITE_SIGNED /* bit 7 - 0x0080 */ +#define BTA_GATT_PERM_WRITE_SIGNED_MITM GATT_PERM_WRITE_SIGNED_MITM /* bit 8 - 0x0100 */ +typedef UINT16 tBTA_GATT_PERM; + +#define BTA_GATTS_INVALID_APP 0xff + +#define BTA_GATTS_INVALID_IF 0 + +/* definition of characteristic properties */ +#define BTA_GATT_CHAR_PROP_BIT_BROADCAST GATT_CHAR_PROP_BIT_BROADCAST /* 0x01 */ +#define BTA_GATT_CHAR_PROP_BIT_READ GATT_CHAR_PROP_BIT_READ /* 0x02 */ +#define BTA_GATT_CHAR_PROP_BIT_WRITE_NR GATT_CHAR_PROP_BIT_WRITE_NR /* 0x04 */ +#define BTA_GATT_CHAR_PROP_BIT_WRITE GATT_CHAR_PROP_BIT_WRITE /* 0x08 */ +#define BTA_GATT_CHAR_PROP_BIT_NOTIFY GATT_CHAR_PROP_BIT_NOTIFY /* 0x10 */ +#define BTA_GATT_CHAR_PROP_BIT_INDICATE GATT_CHAR_PROP_BIT_INDICATE /* 0x20 */ +#define BTA_GATT_CHAR_PROP_BIT_AUTH GATT_CHAR_PROP_BIT_AUTH /* 0x40 */ +#define BTA_GATT_CHAR_PROP_BIT_EXT_PROP GATT_CHAR_PROP_BIT_EXT_PROP /* 0x80 */ +typedef UINT8 tBTA_GATT_CHAR_PROP; + +#ifndef BTA_GATTC_CHAR_DESCR_MAX +#define BTA_GATTC_CHAR_DESCR_MAX 7 +#endif + +/*********************** NV callback Data Definitions ********************** +*/ +typedef struct +{ + tBT_UUID app_uuid128; + tBT_UUID svc_uuid; + UINT16 svc_inst; + UINT16 s_handle; + UINT16 e_handle; + BOOLEAN is_primary; /* primary service or secondary */ +} tBTA_GATTS_HNDL_RANGE; + +#define BTA_GATTS_SRV_CHG_CMD_ADD_CLIENT GATTS_SRV_CHG_CMD_ADD_CLIENT +#define BTA_GATTS_SRV_CHG_CMD_UPDATE_CLIENT GATTS_SRV_CHG_CMD_UPDATE_CLIENT +#define BTA_GATTS_SRV_CHG_CMD_REMOVE_CLIENT GATTS_SRV_CHG_CMD_REMOVE_CLIENT +#define BTA_GATTS_SRV_CHG_CMD_READ_NUM_CLENTS GATTS_SRV_CHG_CMD_READ_NUM_CLENTS +#define BTA_GATTS_SRV_CHG_CMD_READ_CLENT GATTS_SRV_CHG_CMD_READ_CLENT +typedef tGATTS_SRV_CHG_CMD tBTA_GATTS_SRV_CHG_CMD; + +typedef tGATTS_SRV_CHG tBTA_GATTS_SRV_CHG; +typedef tGATTS_SRV_CHG_REQ tBTA_GATTS_SRV_CHG_REQ; +typedef tGATTS_SRV_CHG_RSP tBTA_GATTS_SRV_CHG_RSP; + +enum +{ + BTA_GATT_TRANSPORT_LE, + BTA_GATT_TRANSPORT_BR_EDR, + BTA_GATT_TRANSPORT_LE_BR_EDR +}; +typedef UINT8 tBTA_GATT_TRANSPORT; + +/* attribute value */ +typedef tGATT_VALUE tBTA_GATT_VALUE; + +/* attribute response data */ +typedef tGATTS_RSP tBTA_GATTS_RSP; + +/* attribute request data from the client */ +#define BTA_GATT_PREP_WRITE_CANCEL 0x00 +#define BTA_GATT_PREP_WRITE_EXEC 0x01 +typedef tGATT_EXEC_FLAG tBTA_GATT_EXEC_FLAG; + +/* read request always based on UUID */ +typedef tGATT_READ_REQ tTA_GBATT_READ_REQ; + +/* write request data */ +typedef tGATT_WRITE_REQ tBTA_GATT_WRITE_REQ; + +/* callback data for server access request from client */ +typedef tGATTS_DATA tBTA_GATTS_REQ_DATA; + +typedef struct +{ + BD_ADDR remote_bda; + UINT32 trans_id; + UINT16 conn_id; + tBTA_GATTS_REQ_DATA *p_data; +}tBTA_GATTS_REQ; + +typedef struct +{ + tBTA_GATTS_IF server_if; + tBTA_GATT_STATUS status; +// btla-specific ++ + tBT_UUID uuid; +// btla-specific -- +}tBTA_GATTS_REG_OPER; + + +typedef struct +{ + tBTA_GATTS_IF server_if; + UINT16 service_id; +// btla-specific ++ + UINT16 svc_instance; + BOOLEAN is_primary; + tBTA_GATT_STATUS status; + tBT_UUID uuid; +// btla-specific -- +}tBTA_GATTS_CREATE; + +typedef struct +{ + tBTA_GATTS_IF server_if; + UINT16 service_id; + UINT16 attr_id; + tBTA_GATT_STATUS status; +// btla-specific ++ + tBT_UUID char_uuid; +// btla-specific -- +}tBTA_GATTS_ADD_RESULT; + +typedef struct +{ + tBTA_GATTS_IF server_if; + UINT16 service_id; + tBTA_GATT_STATUS status; +}tBTA_GATTS_SRVC_OPER; + + +typedef struct +{ + tBTA_GATTS_IF server_if; + BD_ADDR remote_bda; + UINT16 conn_id; + tBTA_GATT_REASON reason; /* report disconnect reason */ +}tBTA_GATTS_CONN; + +/* GATTS callback data */ +typedef union +{ + tBTA_GATTS_REG_OPER reg_oper; + tBTA_GATTS_CREATE create; + tBTA_GATTS_SRVC_OPER srvc_oper; + tBTA_GATT_STATUS status; /* BTA_GATTS_CONF_EVT */ + tBTA_GATTS_ADD_RESULT add_result; /* add included service: BTA_GATTS_ADD_INCL_SRVC_EVT + add char : BTA_GATTS_ADD_CHAR_EVT + add char descriptor: BTA_GATTS_ADD_CHAR_DESCR_EVT */ + tBTA_GATTS_REQ req_data; + tBTA_GATTS_CONN conn; /* BTA_GATTS_CONN_EVT */ + +}tBTA_GATTS; + + +/* Server callback function */ +typedef void (tBTA_GATTS_CBACK)(tBTA_GATTS_EVT event, tBTA_GATTS *p_data); +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************** +** Client Functions +***************************/ + +/******************************************************************************* +** +** Function BTA_GATTC_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTC module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_client_cb - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb); + +/******************************************************************************* +** +** Function BTA_GATTC_AppDeregister +** +** Description This function is called to deregister an application +** from BTA GATTC module. +** +** Parameters client_if - client interface identifier. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_AppDeregister (tBTA_GATTC_IF client_if); + +/******************************************************************************* +** +** Function BTA_GATTC_Open +** +** Description Open a direct connection or add a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct); + +/******************************************************************************* +** +** Function BTA_GATTC_CancelOpen +** +** Description Open a direct connection or add a background auto connection +** bd address +** +** Parameters client_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct); + +/******************************************************************************* +** +** Function BTA_GATTC_Close +** +** Description Close a connection to a GATT server. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_Close(UINT16 conn_id); + +/******************************************************************************* +** +** Function BTA_GATTC_ServiceSearchRequest +** +** Description This function is called to request a GATT service discovery +** on a GATT server. This function report service search result +** by a callback event, and followed by a service search complete +** event. +** +** Parameters conn_id: connection ID. +** p_srvc_uuid: a UUID of the service application is interested in. +** If Null, discover for all services. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_ServiceSearchRequest(UINT16 conn_id, tBT_UUID *p_srvc_uuid); + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstChar +** +** Description This function is called to find the first charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the characteristic is belonged to. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter to carry the characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetFirstChar (UINT16 conn_id, + tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property); + +/******************************************************************************* +** +** Function BTA_GATTC_GetNextChar +** +** Description This function is called to find the next charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_char_id: start the characteristic search from the next record +** after the one identified by char_id. +** p_char_uuid_cond: Characteristic UUID, if NULL find the first available +** characteristic. +** p_char_result: output parameter which will store the GATT +** characteristic ID. +** p_property: output parameter, characteristic property. +** +** Returns returns status. +** +*******************************************************************************/ +BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetNextChar (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_start_char_id, + tBT_UUID *p_char_uuid_cond, + tBTA_GATTC_CHAR_ID *p_char_result, + tBTA_GATT_CHAR_PROP *p_property); + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstCharDescr +** +** Description This function is called to find the first charatceristic descriptor of the +** charatceristic on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_char_id: the characteristic ID of which the descriptor is belonged to. +** p_descr_uuid_cond: Characteristic Descr UUID, if NULL find the first available +** characteristic. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetFirstCharDescr (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result); + +/******************************************************************************* +** +** Function BTA_GATTC_GetNextCharDescr +** +** Description This function is called to find the next charatceristic of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_descr_id: start the characteristic search from the next record +** after the one identified by p_start_descr_id. +** p_descr_uuid_cond: Characteristic descriptor UUID, if NULL find +** the first available characteristic descriptor. +** p_descr_result: output parameter which will store the GATT +** characteristic descriptor ID. +** +** Returns returns status. +** +*******************************************************************************/ +BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetNextCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_start_descr_id, + tBT_UUID *p_descr_uuid_cond, + tBTA_GATTC_CHAR_DESCR_ID *p_descr_result); + + +/******************************************************************************* +** +** Function BTA_GATTC_GetFirstIncludedService +** +** Description This function is called to find the first included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_srvc_id: the service ID of which the included service is belonged to. +** p_uuid_cond: include service UUID, if NULL find the first available +** included service. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetFirstIncludedService(UINT16 conn_id, + tBTA_GATT_SRVC_ID *p_srvc_id, + tBT_UUID *p_uuid_cond, + tBTA_GATTC_INCL_SVC_ID *p_result); + +/******************************************************************************* +** +** Function BTA_GATTC_GetNextIncludedService +** +** Description This function is called to find the next included service of the +** service on the given server. +** +** Parameters conn_id: connection ID which identify the server. +** p_start_id: start the search from the next record +** after the one identified by p_start_id. +** p_uuid_cond: Included service UUID, if NULL find the first available +** included service. +** p_result: output parameter which will store the GATT ID +** of the included service found. +** +** Returns returns status. +** +*******************************************************************************/ +BTA_API extern tBTA_GATT_STATUS BTA_GATTC_GetNextIncludedService(UINT16 conn_id, + tBTA_GATTC_INCL_SVC_ID *p_start_id, + tBT_UUID *p_uuid_cond, + tBTA_GATTC_INCL_SVC_ID *p_result); + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharacteristic +** +** Description This function is called to read a service's characteristics of +** the given characteritisc ID. +** +** Parameters conn_id - connectino ID. +** p_char_id - characteritic ID to read. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_ReadCharacteristic (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_ReadCharDescr +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters conn_id - connection ID. +** p_char_descr_id - characteritic descriptor ID to read. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_ReadCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharValue +** +** Description This function is called to write characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to write. +** write_type - type of write. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_WriteCharValue (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + tBTA_GATTC_WRITE_TYPE write_type, + UINT16 len, + UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_WriteCharDescr +** +** Description This function is called to write characteristic descriptor value. +** +** Parameters conn_id - connection ID +** p_char_descr_id - characteristic descriptor ID to write. +** write_type - type of write. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_WriteCharDescr (UINT16 conn_id, + tBTA_GATTC_CHAR_DESCR_ID *p_char_descr_id, + tBTA_GATTC_WRITE_TYPE write_type, + tBTA_GATT_UNFMT *p_data, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_SendIndConfirm +** +** Description This function is called to send handle value confirmation. +** +** Parameters conn_id - connection ID. +** p_char_id - characteristic ID to confrim. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_SendIndConfirm (UINT16 conn_id, tBTA_GATTC_CHAR_ID *p_char_id); + +/******************************************************************************* +** +** Function BTA_GATTC_RegisterForNotifications +** +** Description This function is called to register for notification of a service. +** +** Parameters client_if - client interface. +** remote_bda - target GATT server. +** p_char_id - pointer to GATT characteristic ID. +** +** Returns OK if registration succeed, otherwise failed. +** +*******************************************************************************/ +BTA_API extern tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR remote_bda, + tBTA_GATTC_CHAR_ID *p_char_id); + + +/******************************************************************************* +** +** Function BTA_GATTC_DeregisterForNotifications +** +** Description This function is called to de-register for notification of a servbice. +** +** Parameters client_if - client interface. +** remote_bda - target GATT server. +** p_char_id - pointer to a GATT characteristic ID. +** +** Returns OK if deregistration succeed, otherwise failed. +** +*******************************************************************************/ +BTA_API extern tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications (tBTA_GATTC_IF client_if, + BD_ADDR remote_bda, + tBTA_GATTC_CHAR_ID *p_char_id); + +/******************************************************************************* +** +** Function BTA_GATTC_PrepareWrite +** +** Description This function is called to prepare write a characteristic value. +** +** Parameters conn_id - connection ID. +** p_char_id - GATT characteritic ID of the service. +** offset - offset of the write value. +** len: length of the data to be written. +** p_value - the value to be written. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_PrepareWrite (UINT16 conn_id, + tBTA_GATTC_CHAR_ID *p_char_id, + UINT16 offset, + UINT16 len, + UINT8 *p_value, + tBTA_GATT_AUTH_REQ auth_req); + +/******************************************************************************* +** +** Function BTA_GATTC_ExecuteWrite +** +** Description This function is called to execute write a prepare write sequence. +** +** Parameters conn_id - connection ID. +** is_execute - execute or cancel. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute); + +/******************************************************************************* +** +** Function BTA_GATTC_ReadMultiple +** +** Description This function is called to read multiple characteristic or +** characteristic descriptors. +** +** Parameters conn_id - connectino ID. +** p_read_multi - read multiple parameters. +** +** Returns None +** +*******************************************************************************/ +BTA_API extern void BTA_GATTC_ReadMultiple(UINT16 conn_id, tBTA_GATTC_MULTI *p_read_multi, + tBTA_GATT_AUTH_REQ auth_req); + + + + +/******************************************************************************* +** BTA GATT Server API +********************************************************************************/ +/******************************************************************************* +** +** Function BTA_GATTS_AppRegister +** +** Description This function is called to register application callbacks +** with BTA GATTS module. +** +** Parameters p_app_uuid - applicaiton UUID +** p_cback - pointer to the application callback function. +** +** Returns None +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTS_CBACK *p_cback); + + +/******************************************************************************* +** +** Function BTA_GATTS_AppDeregister +** +** Description De-register with BTA GATT Server. +** +** Parameters server_if: server interface +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if); + +/******************************************************************************* +** +** Function BTA_GATTS_CreateService +** +** Description Create a service. When service creation is done, a callback +** event BTA_GATTS_CREATE_SRVC_EVT is called to report status +** and service ID to the profile. The service ID obtained in +** the callback function needs to be used when adding included +** service and characteristics/descriptors into the service. +** +** Parameters server_if: server interface. +** p_service_uuid: service UUID. +** inst: instance ID number of this service. +** num_handle: numble of handle requessted for this service. +** is_primary: is this service a primary one or not. +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_CreateService(tBTA_GATTS_IF server_if, tBT_UUID *p_service_uuid, + UINT8 inst, UINT16 num_handle, BOOLEAN is_primary); + +/******************************************************************************* +** +** Function BTA_GATTS_AddIncludeService +** +** Description This function is called to add an included service. After included +** service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT +** is reported the included service ID. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** included_service_id: the service ID to be included. +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_AddIncludeService(UINT16 service_id, UINT16 included_service_id); + +/******************************************************************************* +** +** Function BTA_GATTS_AddCharacteristic +** +** Description This function is called to add a characteristic into a service. +** +** Parameters service_id: service ID to which this included service is to +** be added. +** p_char_uuid : Characteristic UUID. +** perm : Characteristic value declaration attribute permission. +** property : Characteristic Properties +** +** Returns None +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_AddCharacteristic (UINT16 service_id, tBT_UUID *p_char_uuid, + tBTA_GATT_PERM perm, tBTA_GATT_CHAR_PROP property); + +/******************************************************************************* +** +** Function BTA_GATTS_AddCharDescriptor +** +** Description This function is called to add characteristic descriptor. When +** it's done, a callback event BTA_GATTS_ADD_DESCR_EVT is called +** to report the status and an ID number for this descriptor. +** +** Parameters service_id: service ID to which this charatceristic descriptor is to +** be added. +** perm: descriptor access permission. +** p_descr_uuid: descriptor UUID. +** p_descr_params: descriptor value if it's read only descriptor. +** +** Returns returns status. +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_AddCharDescriptor (UINT16 service_id, + tBTA_GATT_PERM perm, + tBT_UUID * p_descr_uuid); + +/******************************************************************************* +** +** Function BTA_GATTS_DeleteService +** +** Description This function is called to delete a service. When this is done, +** a callback event BTA_GATTS_DELETE_EVT is report with the status. +** +** Parameters service_id: service_id to be deleted. +** +** Returns returns none. +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_DeleteService(UINT16 service_id); + +/******************************************************************************* +** +** Function BTA_GATTS_StartService +** +** Description This function is called to start a service. +** +** Parameters service_id: the service ID to be started. +** sup_transport: supported trasnport. +** +** Returns None. +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_StartService(UINT16 service_id, tBTA_GATT_TRANSPORT sup_transport); + +/******************************************************************************* +** +** Function BTA_GATTS_StopService +** +** Description This function is called to stop a service. +** +** Parameters service_id - service to be topped. +** +** Returns None +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_StopService(UINT16 service_id); + +/******************************************************************************* +** +** Function BTA_GATTS_HandleValueIndication +** +** Description This function is called to read a characteristics descriptor. +** +** Parameters conn_id - connection identifier. +** attr_id - attribute ID to indicate. +** data_len - indicate data length. +** p_data: data to indicate. +** need_confirm - if this indication expects a confirmation or not. +** +** Returns None +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_id, + UINT16 data_len, + UINT8 *p_data, + BOOLEAN need_confirm); + +/******************************************************************************* +** +** Function BTA_GATTS_SendRsp +** +** Description This function is called to send a response to a request. +** +** Parameters conn_id - connection identifier. +** trans_id - transaction ID. +** status - response status +** p_msg - response data. +** +** Returns None +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, + tBTA_GATT_STATUS status, tBTA_GATTS_RSP *p_msg); + + + + +/******************************************************************************* +** +** Function BTA_GATTS_Open +** +** Description Open a direct open connection or add a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct); + + +/******************************************************************************* +** +** Function BTA_GATTS_CancelOpen +** +** Description Cancel a direct open connection or remove a background auto connection +** bd address +** +** Parameters server_if: server interface. +** remote_bda: remote device BD address. +** is_direct: direct connection or background auto connection +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, BOOLEAN is_direct); + + +/******************************************************************************* +** +** Function BTA_GATTS_Close +** +** Description Close a connection a remote device. +** +** Parameters conn_id: connectino ID to be closed. +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_GATTS_Close(UINT16 conn_id); + + +#ifdef __cplusplus + +} +#endif + + +#endif /* BTA_GATT_API_H */ + diff --git a/bta/include/bta_gattc_ci.h b/bta/include/bta_gattc_ci.h new file mode 100644 index 0000000..1525e3e --- /dev/null +++ b/bta/include/bta_gattc_ci.h @@ -0,0 +1,120 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 interface file for GATT call-in functions. + * + ******************************************************************************/ +#ifndef BTA_GATTC_CI_H +#define BTA_GATTC_CI_H + +#include "bta_gatt_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* Open Complete Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_STATUS status; +} tBTA_GATTC_CI_EVT; + +#define BTA_GATTC_NV_LOAD_MAX 10 + +/* Read Ready Event */ +typedef struct +{ + BT_HDR hdr; + tBTA_GATT_STATUS status; + UINT16 num_attr; + tBTA_GATTC_NV_ATTR attr[BTA_GATTC_NV_LOAD_MAX]; +} tBTA_GATTC_CI_LOAD; + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_open +** +** Description This function sends an event to indicate server cache open +** completed. +** +** Parameters server_bda - server BDA of this cache. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_gattc_ci_cache_open(BD_ADDR server_bda, UINT16 evt, + tBTA_GATT_STATUS status, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_ci_cache_load +** +** Description This function sends an event to BTA indicating the phone has +** load the servere cache and ready to send it to the stack. +** +** Parameters server_bda - server BDA of this cache. +** num_bytes_read - number of bytes read into the buffer +** specified in the read callout-function. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_gattc_ci_cache_load(BD_ADDR server_bda, UINT16 evt, + UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_atrr, + tBTA_GATT_STATUS status, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_ci_save +** +** Description This function sends an event to BTA indicating the phone has +** save the server cache. +** +** Parameters server_bda - server BDA of this cache. +** status - BTA_GATT_OK if full buffer of data, +** BTA_GATT_FAIL if an error has occurred. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_gattc_ci_cache_save(BD_ADDR server_bda, UINT16 evt, + tBTA_GATT_STATUS status, UINT16 conn_id); + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_GATTC_CI_H */ + diff --git a/bta/include/bta_gattc_co.h b/bta/include/bta_gattc_co.h new file mode 100644 index 0000000..d2392b8 --- /dev/null +++ b/bta/include/bta_gattc_co.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Copyright (C) 2010-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 interface file for BTA GATT client call-out functions. + * + ******************************************************************************/ +#ifndef BTA_GATTC_CO_H +#define BTA_GATTC_CO_H + +#include "bta_gatt_api.h" + +/******************************************************************************* +** +** Function bta_gattc_co_cache_open +** +** Description This callout function is executed by GATTC when a GATT server +** cache is ready to be sent. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache open is done. +** conn_id: connection ID of this cache operation attach to. +** to_save: open cache to save or to load. +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void bta_gattc_co_cache_open(BD_ADDR server_bda, UINT16 evt, + UINT16 conn_id, BOOLEAN to_save); + +/******************************************************************************* +** +** Function bta_gattc_co_cache_close +** +** Description This callout function is executed by GATTC when a GATT server +** cache is written completely. +** +** Parameter server_bda: server bd address of this cache belongs to +** conn_id: connection ID of this cache operation attach to. +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void bta_gattc_co_cache_close(BD_ADDR server_bda, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_co_cache_save +** +** Description This callout function is executed by GATT when a server cache +** is available to save. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache save is done. +** num_attr: number of attribute to be save. +** p_attr: pointer to the list of attributes to save. +** attr_index: starting attribute index of the save operation. +** conn_id: connection ID of this cache operation attach to. +** Returns +** +*******************************************************************************/ +BTA_API extern void bta_gattc_co_cache_save(BD_ADDR server_bda, UINT16 evt, + UINT16 num_attr, tBTA_GATTC_NV_ATTR *p_attr, + UINT16 attr_index, UINT16 conn_id); + +/******************************************************************************* +** +** Function bta_gattc_co_cache_load +** +** Description This callout function is executed by GATT when server cache +** is required to load. +** +** Parameter server_bda: server bd address of this cache belongs to +** evt: call in event to be passed in when cache save is done. +** num_attr: number of attribute to be save. +** attr_index: starting attribute index of the save operation. +** conn_id: connection ID of this cache operation attach to. +** Returns +** +*******************************************************************************/ +BTA_API extern void bta_gattc_co_cache_load(BD_ADDR server_bda, UINT16 evt, + UINT16 start_index, UINT16 conn_id); + +#endif /* BTA_GATT_CO_H */ + diff --git a/bta/include/bta_gatts_co.h b/bta/include/bta_gatts_co.h new file mode 100644 index 0000000..86f65dc --- /dev/null +++ b/bta/include/bta_gatts_co.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Copyright (C) 2010-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 interface file for BTA GATT server call-out functions. + * + ******************************************************************************/ +#ifndef BTA_GATTS_CO_H +#define BTA_GATTS_CO_H + +#include "bta_gatt_api.h" + +/******************************************************************************* +** +** Function bta_gatts_co_update_handle_range +** +** Description This callout function is executed by GATTS when a GATT server +** handle range ios to be added or removed. +** +** Parameter is_add: true is to add a handle range; otherwise is to delete. +** p_hndl_range: handle range. +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void bta_gatts_co_update_handle_range(BOOLEAN is_add, tBTA_GATTS_HNDL_RANGE *p_hndl_range); + +/******************************************************************************* +** +** Function bta_gatts_co_srv_chg +** +** Description This call-out is to read/write/remove service change related +** informaiton. The request consists of the cmd and p_req and the +** response is returned in p_rsp +** +** Parameter cmd - request command +** p_req - request paramters +** p_rsp - response data for the request +** +** Returns TRUE - if the request is processed successfully and +** the response is returned in p_rsp. +** FASLE - if the request can not be processed +** +*******************************************************************************/ +BTA_API extern BOOLEAN bta_gatts_co_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd, + tBTA_GATTS_SRV_CHG_REQ *p_req, + tBTA_GATTS_SRV_CHG_RSP *p_rsp); + +/******************************************************************************* +** +** Function bta_gatts_co_load_handle_range +** +** Description This callout function is executed by GATTS when a GATT server +** handle range is requested to be loaded from NV. +** +** Parameter +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern BOOLEAN bta_gatts_co_load_handle_range(UINT8 index, + tBTA_GATTS_HNDL_RANGE *p_handle); + + +#endif /* BTA_GATTS_CO_H */ + diff --git a/bta/include/bta_hh_api.h b/bta/include/bta_hh_api.h new file mode 100644 index 0000000..f613d30 --- /dev/null +++ b/bta/include/bta_hh_api.h @@ -0,0 +1,479 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#ifndef BTA_HH_API_H +#define BTA_HH_API_H + +#include "bta_api.h" +#include "hidh_api.h" + +/***************************************************************************** +** Constants and Type Definitions +*****************************************************************************/ +#ifndef BTA_HH_DEBUG +#define BTA_HH_DEBUG FALSE +#endif + +#ifndef BTA_HH_SSR_MAX_LATENCY_DEF +#define BTA_HH_SSR_MAX_LATENCY_DEF 1600 +#endif + +#ifndef BTA_HH_SSR_MIN_TOUT_DEF +#define BTA_HH_SSR_MIN_TOUT_DEF 2 +#endif + +/* BTA HID Host callback events */ +#define BTA_HH_ENABLE_EVT 0 /* HH enabled */ +#define BTA_HH_DISABLE_EVT 1 /* HH disabled */ +#define BTA_HH_OPEN_EVT 2 /* connection opened */ +#define BTA_HH_CLOSE_EVT 3 /* connection closed */ +#define BTA_HH_GET_RPT_EVT 4 /* BTA_HhGetReport callback */ +#define BTA_HH_SET_RPT_EVT 5 /* BTA_HhSetReport callback */ +#define BTA_HH_GET_PROTO_EVT 6 /* BTA_GetProtoMode callback */ +#define BTA_HH_SET_PROTO_EVT 7 /* BTA_HhSetProtoMode callback */ +#define BTA_HH_GET_IDLE_EVT 8 /* BTA_HhGetIdle comes callback */ +#define BTA_HH_SET_IDLE_EVT 9 /* BTA_HhSetIdle finish callback */ +#define BTA_HH_GET_DSCP_EVT 10 /* Get report descripotor */ +#define BTA_HH_ADD_DEV_EVT 11 /* Add Device callback */ +#define BTA_HH_RMV_DEV_EVT 12 /* remove device finished */ +#define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */ +#define BTA_HH_UPDATE_UCD_EVT 14 +#define BTA_HH_API_ERR_EVT 15 /* API error is caught */ + +typedef UINT16 tBTA_HH_EVT; + +/* defined the minimum offset */ +#define BTA_HH_MIN_OFFSET L2CAP_MIN_OFFSET+1 + +#define BTA_HH_MAX_KNOWN HID_HOST_MAX_DEVICES +/* invalid device handle */ +#define BTA_HH_INVALID_HANDLE 0xff + +/* type of protocol mode */ +#define BTA_HH_PROTO_RPT_MODE (0x00) +#define BTA_HH_PROTO_BOOT_MODE (0x01) +#define BTA_HH_PROTO_UNKNOWN (0xff) +typedef UINT8 tBTA_HH_PROTO_MODE; + +enum +{ + BTA_HH_KEYBD_RPT_ID = 1, + BTA_HH_MOUSE_RPT_ID +}; +typedef UINT8 tBTA_HH_BOOT_RPT_ID; + +/* type of devices, bit mask */ +#define BTA_HH_DEVT_UNKNOWN 0x00 +#define BTA_HH_DEVT_JOS 0x01 /* joy stick */ +#define BTA_HH_DEVT_GPD 0x02 /* game pad */ +#define BTA_HH_DEVT_RMC 0x03 /* remote control */ +#define BTA_HH_DEVT_SED 0x04 /* sensing device */ +#define BTA_HH_DEVT_DGT 0x05 /* Digitizer tablet */ +#define BTA_HH_DEVT_CDR 0x06 /* card reader */ +#define BTA_HH_DEVT_KBD 0x10 /* keyboard */ +#define BTA_HH_DEVT_MIC 0x20 /* pointing device */ +#define BTA_HH_DEVT_COM 0x30 /* Combo keyboard/pointing */ +#define BTA_HH_DEVT_OTHER 0x80 +typedef UINT8 tBTA_HH_DEVT; + +enum +{ + BTA_HH_OK, + BTA_HH_HS_HID_NOT_READY, /* handshake error : device not ready */ + BTA_HH_HS_INVALID_RPT_ID, /* handshake error : invalid report ID */ + BTA_HH_HS_TRANS_NOT_SPT, /* handshake error : transaction not spt */ + BTA_HH_HS_INVALID_PARAM, /* handshake error : invalid paremter */ + BTA_HH_HS_ERROR, /* handshake error : unspecified HS error */ + BTA_HH_ERR, /* general BTA HH error */ + BTA_HH_ERR_SDP, /* SDP error */ + BTA_HH_ERR_PROTO, /* SET_Protocol error, + only used in BTA_HH_OPEN_EVT callback */ + BTA_HH_ERR_DB_FULL, /* device database full error, used in + BTA_HH_OPEN_EVT/BTA_HH_ADD_DEV_EVT */ + BTA_HH_ERR_TOD_UNSPT, /* type of device not supported */ + BTA_HH_ERR_NO_RES, /* out of system resources */ + BTA_HH_ERR_AUTH_FAILED, /* authentication fail */ + BTA_HH_ERR_HDL +}; +typedef UINT8 tBTA_HH_STATUS; + + +#define BTA_HH_VIRTUAL_CABLE HID_VIRTUAL_CABLE +#define BTA_HH_NORMALLY_CONNECTABLE HID_NORMALLY_CONNECTABLE +#define BTA_HH_RECONN_INIT HID_RECONN_INIT +#define BTA_HH_SDP_DISABLE HID_SDP_DISABLE +#define BTA_HH_BATTERY_POWER HID_BATTERY_POWER +#define BTA_HH_REMOTE_WAKE HID_REMOTE_WAKE +#define BTA_HH_SUP_TOUT_AVLBL HID_SUP_TOUT_AVLBL +#define BTA_HH_SEC_REQUIRED HID_SEC_REQUIRED +typedef UINT16 tBTA_HH_ATTR_MASK; + + +/* supported type of device and corresponding application ID */ +typedef struct +{ + tBTA_HH_DEVT tod; /* type of device */ + UINT8 app_id; /* corresponding application ID */ +}tBTA_HH_SPT_TOD; + +/* configuration struct */ +typedef struct +{ + UINT8 max_devt_spt; /* max number of types of devices spt */ + tBTA_HH_SPT_TOD *p_devt_list; /* supported types of device list */ + UINT16 sdp_db_size; +}tBTA_HH_CFG; + +enum +{ + BTA_HH_RPTT_RESRV, /* reserved */ + BTA_HH_RPTT_INPUT, /* input report */ + BTA_HH_RPTT_OUTPUT, /* output report */ + BTA_HH_RPTT_FEATURE /* feature report */ +}; +typedef UINT8 tBTA_HH_RPT_TYPE; + +/* HID_CONTROL operation code used in BTA_HhSendCtrl() +*/ +enum +{ + BTA_HH_CTRL_NOP = 0 + HID_PAR_CONTROL_NOP ,/* mapping from BTE */ + BTA_HH_CTRL_HARD_RESET, /* hard reset */ + BTA_HH_CTRL_SOFT_RESET, /* soft reset */ + BTA_HH_CTRL_SUSPEND, /* enter suspend */ + BTA_HH_CTRL_EXIT_SUSPEND, /* exit suspend */ + BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG /* virtual unplug */ +}; +typedef UINT8 tBTA_HH_TRANS_CTRL_TYPE; + +typedef tHID_DEV_DSCP_INFO tBTA_HH_DEV_DESCR; + +/* id DI is not existing in remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO will be set to 0xffff */ +#define BTA_HH_VENDOR_ID_INVALID 0xffff + + +/* report descriptor information */ +typedef struct +{ + UINT16 vendor_id; /* vendor ID */ + UINT16 product_id; /* product ID */ + UINT16 version; /* version */ + UINT16 ssr_max_latency; /* SSR max latency */ + UINT16 ssr_min_tout; /* SSR min timeout */ + UINT8 ctry_code; /*Country Code.*/ + tBTA_HH_DEV_DESCR descriptor; +}tBTA_HH_DEV_DSCP_INFO; + +/* callback event data for BTA_HH_OPEN_EVT */ +typedef struct +{ + BD_ADDR bda; /* HID device bd address */ + tBTA_HH_STATUS status; /* operation status */ + UINT8 handle; /* device handle */ +} tBTA_HH_CONN; + +typedef tBTA_HH_CONN tBTA_HH_DEV_INFO; + +/* callback event data */ +typedef struct +{ + tBTA_HH_STATUS status; /* operation status */ + UINT8 handle; /* device handle */ +} tBTA_HH_CBDATA; + +enum +{ + BTA_HH_MOD_CTRL_KEY, + BTA_HH_MOD_SHFT_KEY, + BTA_HH_MOD_ALT_KEY, + BTA_HH_MOD_GUI_KEY, + BTA_HH_MOD_MAX_KEY +}; + +/* parsed boot mode keyboard report */ +typedef struct +{ + UINT8 this_char[6]; /* virtual key code */ + BOOLEAN mod_key[BTA_HH_MOD_MAX_KEY]; + /* ctrl, shift, Alt, GUI */ + /* modifier key: is Shift key pressed */ + /* modifier key: is Ctrl key pressed */ + /* modifier key: is Alt key pressed */ + /* modifier key: GUI up/down */ + BOOLEAN caps_lock; /* is caps locked */ + BOOLEAN num_lock; /* is Num key pressed */ +} tBTA_HH_KEYBD_RPT; + +/* parsed boot mode mouse report */ +typedef struct +{ + UINT8 mouse_button; /* mouse button is clicked */ + INT8 delta_x; /* displacement x */ + INT8 delta_y; /* displacement y */ +}tBTA_HH_MICE_RPT; + +/* parsed Boot report */ +typedef struct +{ + tBTA_HH_BOOT_RPT_ID dev_type; /* type of device report */ + union + { + tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */ + tBTA_HH_MICE_RPT mice_rpt; /* mouse report */ + } data_rpt; +} tBTA_HH_BOOT_RPT; + +/* handshake data */ +typedef struct +{ + tBTA_HH_STATUS status; /* handshake status */ + UINT8 handle; /* device handle */ + union + { + tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */ + BT_HDR *p_rpt_data; /* GET_RPT_EVT : report data */ + UINT8 idle_rate; /* GET_IDLE_EVT : idle rate */ + } rsp_data; + +}tBTA_HH_HSDATA; + +/* union of data associated with HD callback */ +typedef union +{ + tBTA_HH_DEV_INFO dev_info; /* BTA_HH_ADD_DEV_EVT, BTA_HH_RMV_DEV_EVT */ + tBTA_HH_CONN conn; /* BTA_HH_OPEN_EVT */ + tBTA_HH_CBDATA dev_status; /* BTA_HH_CLOSE_EVT, + BTA_HH_SET_PROTO_EVT + BTA_HH_SET_RPT_EVT + BTA_HH_SET_IDLE_EVT */ + + tBTA_HH_STATUS status; /* BTA_HH_ENABLE_EVT */ + tBTA_HH_DEV_DSCP_INFO dscp_info; /* BTA_HH_GET_DSCP_EVT */ + tBTA_HH_HSDATA hs_data; /* GET_ transaction callback + BTA_HH_GET_RPT_EVT + BTA_HH_GET_PROTO_EVT + BTA_HH_GET_IDLE_EVT */ +} tBTA_HH; + +/* BTA HH callback function */ +typedef void (tBTA_HH_CBACK) (tBTA_HH_EVT event, tBTA_HH *p_data); + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function BTA_HhRegister +** +** Description This function enable HID host and registers HID-Host with +** lower layers. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhEnable(tBTA_SEC sec_mask, BOOLEAN ucd_enabled, tBTA_HH_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_HhDeregister +** +** Description This function is called when the host is about power down. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhDisable(void); + +/******************************************************************************* +** +** Function BTA_HhOpen +** +** Description This function is called to start an inquiry and read SDP +** record of responding devices; connect to a device if only +** one active HID device is found. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhOpen (BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode, + tBTA_SEC sec_mask); + +/******************************************************************************* +** +** Function BTA_HhClose +** +** Description This function disconnects the device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhClose(UINT8 dev_handle); + +/******************************************************************************* +** +** Function BTA_HhSetProtoMode +** +** Description This function set the protocol mode at specified HID handle +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhSetProtoMode(UINT8 handle, tBTA_HH_PROTO_MODE t_type); + +/******************************************************************************* +** +** Function BTA_HhGetProtoMode +** +** Description This function get the protocol mode of a specified HID device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhGetProtoMode(UINT8 dev_handle); +/******************************************************************************* +** +** Function BTA_HhSetReport +** +** Description send SET_REPORT to device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhSetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, + BT_HDR *p_data); + +/******************************************************************************* +** +** Function BTA_HhGetReport +** +** Description Send a GET_REPORT to HID device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhGetReport(UINT8 dev_handle, tBTA_HH_RPT_TYPE r_type, + UINT8 rpt_id, UINT16 buf_size); +/******************************************************************************* +** +** Function BTA_HhSendCtrl +** +** Description Send HID_CONTROL request to a HID device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhSendCtrl(UINT8 dev_handle, + tBTA_HH_TRANS_CTRL_TYPE c_type); + +/******************************************************************************* +** +** Function BTA_HhSetIdle +** +** Description send SET_IDLE to device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhSetIdle(UINT8 dev_handle, UINT16 idle_rate); + + +/******************************************************************************* +** +** Function BTA_HhGetIdle +** +** Description Send a GET_IDLE from HID device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhGetIdle(UINT8 dev_handle); + +/******************************************************************************* +** +** Function BTA_HhSendData +** +** Description Send DATA transaction to a HID device. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR *p_buf); + +/******************************************************************************* +** +** Function BTA_HhGetDscpInfo +** +** Description Get report descriptor of the device +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhGetDscpInfo(UINT8 dev_handle); + +/******************************************************************************* +** +** Function BTA_HhAddDev +** +** Description Add a virtually cabled device into HID-Host device list +** to manage and assign a device handle for future API call, +** host applciation call this API at start-up to initialize its +** virtually cabled devices. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, + UINT8 sub_class, UINT8 app_id, + tBTA_HH_DEV_DSCP_INFO dscp_info); +/******************************************************************************* +** +** Function BTA_HhRemoveDev +** +** Description Remove a device from the HID host devices list. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhRemoveDev(UINT8 dev_handle ); +/******************************************************************************* +** +** Parsing Utility Functions +** +*******************************************************************************/ +/******************************************************************************* +** +** Function BTA_HhParseBootRpt +** +** Description This utility function parse a boot mode report. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT *p_data, UINT8 *p_report, + UINT16 report_len); + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_HH_API_H */ diff --git a/bta/include/bta_hh_co.h b/bta/include/bta_hh_co.h new file mode 100644 index 0000000..8f648df --- /dev/null +++ b/bta/include/bta_hh_co.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * + * Copyright (C) 2005-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 interface file for hid host call-out functions. + * + ******************************************************************************/ +#ifndef BTA_HH_CO_H +#define BTA_HH_CO_H + +#include "bta_hh_api.h" + + +/******************************************************************************* +** +** Function bta_hh_co_data +** +** Description This callout function is executed by HH when data is received +** in interupt channel. +** +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern 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); + +/******************************************************************************* +** +** Function bta_hh_co_open +** +** Description This callout function is executed by HH when connection is +** opened, and application may do some device specific +** initialization. +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, + UINT16 attr_mask, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_hh_co_close +** +** Description This callout function is executed by HH when connection is +** closed, and device specific finalizatio nmay be needed. +** +** Returns void. +** +*******************************************************************************/ +BTA_API extern void bta_hh_co_close(UINT8 dev_handle, UINT8 app_id); + +#endif /* BTA_HH_CO_H */ + diff --git a/bta/include/bta_hl_api.h b/bta/include/bta_hl_api.h new file mode 100644 index 0000000..e7febf8 --- /dev/null +++ b/bta/include/bta_hl_api.h @@ -0,0 +1,908 @@ +/****************************************************************************** + * + * 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 public interface file for the HeaLth device profile (HL) + * subsystem of BTA, Broadcom's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ +#ifndef BTA_HL_API_H +#define BTA_HL_API_H + +#include "bta_api.h" +#include "btm_api.h" +#include "mca_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/* Extra Debug Code */ +#ifndef BTA_HL_DEBUG +#define BTA_HL_DEBUG TRUE +#endif + +#ifndef BTA_HL_NUM_APPS +#define BTA_HL_NUM_APPS 3 +#endif + +#ifndef BTA_HL_NUM_MDEPS +#define BTA_HL_NUM_MDEPS 5 +#endif + +#ifndef BTA_HL_NUM_MCLS +#define BTA_HL_NUM_MCLS 7 +#endif + +#ifndef BTA_HL_NUM_MDLS_PER_MDEP +#define BTA_HL_NUM_MDLS_PER_MDEP 4 +#endif + +#ifndef BTA_HL_NUM_MDLS_PER_MCL +#define BTA_HL_NUM_MDLS_PER_MCL 10 +#endif + +#ifndef BTA_HL_NUM_DATA_TYPES +#define BTA_HL_NUM_DATA_TYPES 5 /* maximum number of data types can be supported + per MDEP ID */ +#endif + +#define BTA_HL_MCAP_RSP_TOUT 2 /* 2 seconds */ + +#ifndef BTA_HL_CCH_NUM_FILTER_ELEMS +#define BTA_HL_CCH_NUM_FILTER_ELEMS 3 +#endif + +#ifndef BTA_HL_NUM_SDP_CBACKS +#define BTA_HL_NUM_SDP_CBACKS 7 +#endif + +#ifndef BTA_HL_NUM_SDP_RECS +#define BTA_HL_NUM_SDP_RECS 3 +#endif + +#ifndef BTA_HL_NUM_SDP_MDEPS +#define BTA_HL_NUM_SDP_MDEPS 10 +#endif + +#ifndef BTA_HL_NUM_SVC_ELEMS +#define BTA_HL_NUM_SVC_ELEMS 2 +#endif + +#ifndef BTA_HL_NUM_PROTO_ELEMS +#define BTA_HL_NUM_PROTO_ELEMS 2 +#endif + +#define BTA_HL_VERSION_01_00 0x0100 +#define BTA_HL_NUM_ADD_PROTO_LISTS 1 +#define BTA_HL_NUM_ADD_PROTO_ELEMS 2 +#define BTA_HL_MDEP_SEQ_SIZE 20 +#define BTA_HL_VAL_ARRY_SIZE 320 + +#ifndef BTA_HL_NUM_MDL_CFGS +#define BTA_HL_NUM_MDL_CFGS 16 /* numer of MDL cfg saved in the persistent memory*/ +#endif + +#define BTA_HL_NUM_TIMERS 7 + +#define BTA_HL_CCH_RSP_TOUT 2000 +#define BTA_HL_LRG_POOL_ID GKI_POOL_ID_7 +#define BTA_HL_MAX_TIME 255 +#define BTA_HL_MIN_TIME 1 +#define BTA_HL_INVALID_APP_HANDLE 0xFF +#define BTA_HL_INVALID_MCL_HANDLE 0xFF +#define BTA_HL_INVALID_MDL_HANDLE 0xFFFF + +#define BTA_HL_STATUS_OK 0 +#define BTA_HL_STATUS_FAIL 1 /* Used to pass all other errors */ +#define BTA_HL_STATUS_ABORTED 2 +#define BTA_HL_STATUS_NO_RESOURCE 3 +#define BTA_HL_STATUS_LAST_ITEM 4 +#define BTA_HL_STATUS_DUPLICATE_APP_ID 5 +#define BTA_HL_STATUS_INVALID_APP_HANDLE 6 +#define BTA_HL_STATUS_INVALID_MCL_HANDLE 7 +#define BTA_HL_STATUS_MCAP_REG_FAIL 8 +#define BTA_HL_STATUS_MDEP_CO_FAIL 9 +#define BTA_HL_STATUS_ECHO_CO_FAIL 10 +#define BTA_HL_STATUS_MDL_CFG_CO_FAIL 11 +#define BTA_HL_STATUS_SDP_NO_RESOURCE 12 +#define BTA_HL_STATUS_SDP_FAIL 13 +#define BTA_HL_STATUS_NO_CCH 14 +#define BTA_HL_STATUS_NO_MCL 15 + +#define BTA_HL_STATUS_NO_FIRST_RELIABLE 17 +#define BTA_HL_STATUS_INVALID_DCH_CFG 18 +#define BTA_HL_STATUS_INVALID_MDL_HANDLE 19 +#define BTA_HL_STATUS_INVALID_BD_ADDR 20 +#define BTA_HL_STATUS_INVALID_RECONNECT_CFG 21 +#define BTA_HL_STATUS_ECHO_TEST_BUSY 22 +#define BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID 23 +#define BTA_HL_STATUS_INVALID_MDL_ID 24 +#define BTA_HL_STATUS_NO_MDL_ID_FOUND 25 +#define BTA_HL_STATUS_DCH_BUSY 26 /* DCH is congested*/ +#define BTA_HL_STATUS_INVALID_CTRL_PSM 27 + +typedef UINT8 tBTA_HL_STATUS; +typedef tMCA_HANDLE tBTA_HL_APP_HANDLE; +typedef tMCA_CL tBTA_HL_MCL_HANDLE; +typedef tMCA_DL tBTA_HL_MDL_HANDLE; +enum +{ + BTA_HL_DEVICE_TYPE_SINK, + BTA_HL_DEVICE_TYPE_SOURCE, + BTA_HL_DEVICE_TYPE_DUAL +}; + +typedef UINT8 tBTA_HL_DEVICE_TYPE; + + + +#define BTA_HL_SDP_IEEE_11073_20601 0x01 + +#define BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT 2 /* 0x02 */ +#define BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT 4 /* 0x04 */ +#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE 0 /* 0x08 */ +#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER 0 /* 0x10 */ + +#define BTA_HL_MCAP_SUP_PROC_MASK (BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT | \ + BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT | \ + BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE | \ + BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER) +#define BTA_HL_MDEP_ROLE_SOURCE 0x00 +#define BTA_HL_MDEP_ROLE_SINK 0x01 + +typedef UINT8 tBTA_HL_MDEP_ROLE; + +#define BTA_HL_MDEP_ROLE_MASK_SOURCE 0x01 /* bit mask */ +#define BTA_HL_MDEP_ROLE_MASK_SINK 0x02 +typedef UINT8 tBTA_HL_MDEP_ROLE_MASK; + + +#define BTA_HL_ECHO_TEST_MDEP_ID 0 +#define BTA_HL_ECHO_TEST_MDEP_CFG_IDX 0 + +#define BTA_HL_INVALID_MDEP_ID 0xFF +typedef tMCA_DEP tBTA_HL_MDEP_ID; /* 0 is for echo test, + 0x01-0x7F availave for use, + 0x80-0xFF reserved*/ + + +#define BTA_HL_DELETE_ALL_MDL_IDS 0xFFFF +#define BTA_HL_MAX_MDL_VAL 0xFEFF +typedef UINT16 tBTA_HL_MDL_ID; /* 0x0000 reserved, + 0x0001-0xFEFF dynamic range, + 0xFF00-0xFFFE reserved, + 0xFFFF indicates all MDLs*/ + +#define BTA_HL_MDEP_DESP_LEN 35 + +#define BTA_HL_DCH_MODE_RELIABLE 0 +#define BTA_HL_DCH_MODE_STREAMING 1 + +typedef UINT8 tBTA_HL_DCH_MODE; + +#define BTA_HL_DCH_CFG_NO_PREF 0 +#define BTA_HL_DCH_CFG_RELIABLE 1 +#define BTA_HL_DCH_CFG_STREAMING 2 +#define BTA_HL_DCH_CFG_UNKNOWN 0xFF + +typedef UINT8 tBTA_HL_DCH_CFG; + +/* The Default DCH CFG for the echo test when the device is a Source */ +#define BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG BTA_HL_DCH_CFG_RELIABLE + +#define BTA_HL_DCH_CREATE_RSP_SUCCESS 0 +#define BTA_HL_DCH_CREATE_RSP_CFG_REJ 1 + +typedef UINT8 tBTA_HL_DCH_CREATE_RSP; + +#define BTA_HL_MCAP_SUP_PROC_RECONNECT_INIT 0x02 +#define BTA_HL_MCAP_SUP_PROC_RECONNECT_APT 0x04 +#define BTA_HL_MCAP_SUP_PROC_CSP_SLAVE 0x08 +#define BTA_HL_MCAP_SUP_PROC_CSP_MASTER 0x10 + +typedef UINT8 tBTA_HL_SUP_PROC_MASK; + +typedef struct +{ + UINT16 max_rx_apdu_size; /* local rcv MTU */ + UINT16 max_tx_apdu_size; /* maximum TX APDU size*/ +} tBTA_HL_ECHO_CFG; + + +typedef struct +{ + UINT16 data_type; + UINT16 max_rx_apdu_size; /* local rcv MTU */ + UINT16 max_tx_apdu_size; /* maximum TX APDU size*/ + char desp[BTA_HL_MDEP_DESP_LEN+1]; +} tBTA_HL_MDEP_DATA_TYPE_CFG; + + +typedef struct +{ + tBTA_HL_MDEP_ROLE mdep_role; + UINT8 num_of_mdep_data_types; + tBTA_HL_MDEP_DATA_TYPE_CFG data_cfg[BTA_HL_NUM_DATA_TYPES]; +} tBTA_HL_MDEP_CFG; + +typedef struct +{ + tBTA_HL_MDEP_ID mdep_id; /* MDEP ID 0x01-0x7F */ + tBTA_HL_MDEP_CFG mdep_cfg; +} tBTA_HL_MDEP; + +typedef struct +{ + tBTA_HL_MDEP mdep[BTA_HL_NUM_MDEPS]; + tBTA_HL_ECHO_CFG echo_cfg; + tBTA_HL_MDEP_ROLE_MASK app_role_mask; + BOOLEAN advertize_source_sdp; + UINT8 num_of_mdeps; +} tBTA_HL_SUP_FEATURE; + +typedef struct +{ + BOOLEAN delete_req_pending; + tBTA_HL_MDL_ID mdl_id; + tBTA_HL_MCL_HANDLE mcl_handle; +} tBTA_HL_DELETE_MDL; + +typedef struct +{ + UINT8 time; + UINT16 mtu; + tBTA_HL_MDL_ID mdl_id; + tBTA_HL_MDEP_ID local_mdep_id; + tBTA_HL_MDEP_ROLE local_mdep_role; + BOOLEAN active; /* true if this item is in use */ + tBTA_HL_DCH_MODE dch_mode; + UINT8 fcs; + BD_ADDR peer_bd_addr; +} tBTA_HL_MDL_CFG; + + +/* Maximum number of supported feature list items (list_elem in tSDP_SUP_FEATURE_ELEM) */ +#define BTA_HL_NUM_SUP_FEATURE_ELEMS 10 +#define BTA_HL_SUP_FEATURE_SDP_BUF_SIZE 512 +/* This structure is used to add supported feature lists and find supported feature elements */ +typedef struct +{ + UINT8 mdep_id; + UINT16 data_type; + tBTA_HL_MDEP_ROLE mdep_role; + char *p_mdep_desp; +} tBTA_HL_SUP_FEATURE_ELEM; + +typedef struct +{ + UINT16 num_elems; + tBTA_HL_SUP_FEATURE_ELEM list_elem[BTA_HL_NUM_SUP_FEATURE_ELEMS]; +} tBTA_HL_SUP_FEATURE_LIST_ELEM; + + +typedef struct +{ + tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */ + tBTA_SEC sec_mask; /* security mask for accepting conenction*/ + const char *p_srv_name; /* service name to be used in the SDP; null terminated*/ + const char *p_srv_desp; /* service description to be used in the SDP; null terminated */ + const char *p_provider_name; /* provide name to be used in the SDP; null terminated */ +} tBTA_HL_REG_PARAM; + +typedef struct +{ + UINT16 ctrl_psm; + BD_ADDR bd_addr; /* Address of peer device */ + tBTA_SEC sec_mask; /* security mask for initiating connection*/ +} tBTA_HL_CCH_OPEN_PARAM; + + +typedef struct +{ + UINT16 ctrl_psm; + tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */ + tBTA_HL_MDEP_ID peer_mdep_id; /* peer mdep id */ + tBTA_HL_DCH_CFG local_cfg; + tBTA_SEC sec_mask; /* security mask for initiating connection*/ +} tBTA_HL_DCH_OPEN_PARAM; + + +typedef struct +{ + UINT16 ctrl_psm; + tBTA_HL_MDL_ID mdl_id; +} tBTA_HL_DCH_RECONNECT_PARAM; + + +typedef struct +{ + UINT16 ctrl_psm; + UINT16 pkt_size; + tBTA_HL_DCH_CFG local_cfg; +} tBTA_HL_DCH_ECHO_TEST_PARAM; + +typedef struct +{ + UINT16 buf_size; + UINT8 p_buf; /* buffer pointer */ +} tBTA_HL_DCH_BUF_INFO; + +typedef struct +{ + tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */ + tBTA_HL_MDL_ID mdl_id; + tBTA_HL_DCH_CREATE_RSP rsp_code; + tBTA_HL_DCH_CFG cfg_rsp; +} tBTA_HL_DCH_CREATE_RSP_PARAM; + +typedef struct +{ + UINT16 data_type; + UINT8 mdep_id; + tBTA_HL_MDEP_ROLE mdep_role; + char mdep_desp[BTA_HL_MDEP_DESP_LEN+1]; +}tBTA_HL_SDP_MDEP_CFG; + +typedef struct +{ + UINT16 ctrl_psm; + UINT16 data_psm; + UINT8 mcap_sup_proc; + UINT8 num_mdeps; /* number of mdep elements from SDP*/ + char srv_name[BTA_SERVICE_NAME_LEN+1]; + char srv_desp[BTA_SERVICE_DESP_LEN+1]; + char provider_name[BTA_PROVIDER_NAME_LEN+1]; + tBTA_HL_SDP_MDEP_CFG mdep_cfg[BTA_HL_NUM_SDP_MDEPS]; +} tBTA_HL_SDP_REC; + +typedef struct +{ + UINT8 num_recs; + tBTA_HL_SDP_REC sdp_rec[BTA_HL_NUM_SDP_RECS]; +} tBTA_HL_SDP; + +/* HL control callback function events */ +enum +{ + BTA_HL_CTRL_ENABLE_CFM_EVT = 0, + BTA_HL_CTRL_DISABLE_CFM_EVT +}; +typedef UINT8 tBTA_HL_CTRL_EVT; +/* Structure associated with BTA_HL_ENABLE_EVT + BTA_HL_DISABLE_EVT */ + +typedef struct +{ + tBTA_HL_STATUS status; +} tBTA_HL_CTRL_ENABLE_DISABLE; + +typedef union +{ + tBTA_HL_CTRL_ENABLE_DISABLE enable_cfm; + tBTA_HL_CTRL_ENABLE_DISABLE disable_cfm; +} tBTA_HL_CTRL; + +/* HL instance callback function events */ +enum +{ + BTA_HL_REGISTER_CFM_EVT =0, + BTA_HL_DEREGISTER_CFM_EVT, + BTA_HL_CCH_OPEN_IND_EVT, + BTA_HL_CCH_OPEN_CFM_EVT, + BTA_HL_CCH_CLOSE_IND_EVT, + BTA_HL_CCH_CLOSE_CFM_EVT, + BTA_HL_DCH_CREATE_IND_EVT, + BTA_HL_DCH_OPEN_IND_EVT, + BTA_HL_DCH_OPEN_CFM_EVT, + BTA_HL_DCH_CLOSE_IND_EVT, + BTA_HL_DCH_CLOSE_CFM_EVT, + BTA_HL_DCH_RECONNECT_IND_EVT, + BTA_HL_DCH_RECONNECT_CFM_EVT, + + BTA_HL_DCH_ABORT_IND_EVT, + BTA_HL_DCH_ABORT_CFM_EVT, + BTA_HL_DELETE_MDL_IND_EVT, + BTA_HL_DELETE_MDL_CFM_EVT, + BTA_HL_DCH_SEND_DATA_CFM_EVT, + BTA_HL_DCH_RCV_DATA_IND_EVT, + BTA_HL_CONG_CHG_IND_EVT, + BTA_HL_DCH_ECHO_TEST_CFM_EVT, + BTA_HL_SDP_QUERY_CFM_EVT, + BTA_HL_SDP_INFO_IND_EVT +}; +typedef UINT8 tBTA_HL_EVT; + + +typedef struct +{ + tBTA_HL_STATUS status; /* start status */ + UINT8 app_id; + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_REGISTER_CFM; + + +typedef struct +{ + tBTA_HL_STATUS status; /* start status */ + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_DEREGISTER_CFM; + + +typedef struct +{ + BOOLEAN intentional; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_CCH_CLOSE_IND; + + +typedef struct +{ + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_MCL_IND; + +typedef struct +{ + tBTA_HL_STATUS status; /* connection status */ + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_MCL_CFM; + +typedef struct +{ + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; + BD_ADDR bd_addr; /* address of peer device */ +} tBTA_HL_CCH_OPEN_IND; + +typedef struct +{ + tBTA_HL_STATUS status; /* connection status */ + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; + BD_ADDR bd_addr; /* address of peer device */ +} tBTA_HL_CCH_OPEN_CFM; + +typedef struct +{ + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; + tBTA_HL_MDEP_ID local_mdep_id; + tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this + data channel conenction */ + tBTA_HL_DCH_CFG cfg; /* dch cfg requested by the peer device */ +} tBTA_HL_DCH_CREATE_IND; + +typedef struct +{ + tBTA_HL_MDL_HANDLE mdl_handle; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; + tBTA_HL_MDEP_ID local_mdep_id; + tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this + data channel conenction */ + tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/ + + BOOLEAN first_reliable; /* whether this is the first reliable data channel */ + UINT16 mtu; +} tBTA_HL_DCH_OPEN_IND; + +typedef struct +{ + tBTA_HL_STATUS status; /* connection status */ + tBTA_HL_MDL_HANDLE mdl_handle; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; + tBTA_HL_MDEP_ID local_mdep_id; + tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this + data channel conenction */ + tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/ + BOOLEAN first_reliable; /* whether this is the first reliable data channel */ + UINT16 mtu; +} tBTA_HL_DCH_OPEN_CFM; + + +typedef struct +{ + BOOLEAN intentional; + tBTA_HL_MDL_HANDLE mdl_handle; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_DCH_CLOSE_IND; + + +typedef struct +{ + tBTA_HL_MDL_HANDLE mdl_handle; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_MDL_IND; + +typedef struct +{ + tBTA_HL_STATUS status; + tBTA_HL_MDL_HANDLE mdl_handle; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; +} tBTA_HL_MDL_CFM; + +typedef struct +{ + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; + tBTA_HL_MDL_ID mdl_id; +} tBTA_HL_DELETE_MDL_IND; + +typedef struct +{ + tBTA_HL_STATUS status; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; + tBTA_HL_MDL_ID mdl_id; +} tBTA_HL_DELETE_MDL_CFM; + +typedef struct +{ + tBTA_HL_MDL_HANDLE mdl_handle; + tBTA_HL_MCL_HANDLE mcl_handle; + tBTA_HL_APP_HANDLE app_handle; + BOOLEAN cong; +} tBTA_HL_DCH_CONG_IND; + +typedef struct +{ + tBTA_HL_APP_HANDLE app_handle; + UINT16 ctrl_psm; + UINT16 data_psm; + UINT8 data_x_spec; + UINT8 mcap_sup_procs; +} tBTA_HL_SDP_INFO_IND; + +typedef struct +{ + tBTA_HL_STATUS status; + tBTA_HL_APP_HANDLE app_handle; + BD_ADDR bd_addr; + tBTA_HL_SDP *p_sdp; +} tBTA_HL_SDP_QUERY_CFM; + +typedef union +{ + tBTA_HL_REGISTER_CFM reg_cfm; + tBTA_HL_DEREGISTER_CFM dereg_cfm; + tBTA_HL_CCH_OPEN_IND cch_open_ind; + tBTA_HL_CCH_OPEN_CFM cch_open_cfm; + tBTA_HL_CCH_CLOSE_IND cch_close_ind; + tBTA_HL_MCL_CFM cch_close_cfm; + tBTA_HL_DCH_CREATE_IND dch_create_ind; + tBTA_HL_DCH_OPEN_IND dch_open_ind; + tBTA_HL_DCH_OPEN_CFM dch_open_cfm; + tBTA_HL_DCH_CLOSE_IND dch_close_ind; + tBTA_HL_MDL_CFM dch_close_cfm; + tBTA_HL_DCH_OPEN_IND dch_reconnect_ind; + tBTA_HL_DCH_OPEN_CFM dch_reconnect_cfm; + tBTA_HL_MCL_IND dch_abort_ind; + tBTA_HL_MCL_CFM dch_abort_cfm; + tBTA_HL_DELETE_MDL_IND delete_mdl_ind; + tBTA_HL_DELETE_MDL_CFM delete_mdl_cfm; + tBTA_HL_MDL_CFM dch_send_data_cfm; + tBTA_HL_MDL_IND dch_rcv_data_ind; + tBTA_HL_DCH_CONG_IND dch_cong_ind; + tBTA_HL_MCL_CFM echo_test_cfm; + tBTA_HL_SDP_QUERY_CFM sdp_query_cfm; + tBTA_HL_SDP_INFO_IND sdp_info_ind; + +} tBTA_HL; + +/* HL callback functions */ +typedef void tBTA_HL_CTRL_CBACK(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL *p_data); +typedef void tBTA_HL_CBACK(tBTA_HL_EVT event, tBTA_HL *p_data); + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************** +** API Functions +***************************/ + +/******************************************************************************* +** +** Function BTA_HlEnable +** +** Description Enable the HL subsystems. This function must be +** called before any other functions in the HL API are called. +** When the enable operation is completed the callback function +** will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event. +** +** Parameters p_cback - HL event call back function +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlEnable(tBTA_HL_CTRL_CBACK *p_ctrl_cback); +/******************************************************************************* +** +** Function BTA_HlDisable +** +** Description Disable the HL subsystem. +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlDisable(void); +/******************************************************************************* +** +** Function BTA_HlRegister +** +** Description Register a HDP application +** +** +** Parameters app_id - hdp application ID +** p_reg_param - non-platform related parameters for the +** HDP application +** p_cback - HL event callback fucntion +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlRegister(UINT8 app_id, + tBTA_HL_REG_PARAM *p_reg_param, + tBTA_HL_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_HlDeregister +** +** Description Deregister an HDP application +** +** Parameters app_handle - Application handle +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlDeregister(tBTA_HL_APP_HANDLE app_handle); + +/******************************************************************************* +** +** Function BTA_HlCchOpen +** +** Description Open a Control channel connection with the specified BD address +** and the control PSM value is used to select which +** HDP insatnce should be used in case the peer device support +** multiple HDP instances. +** +** +** Parameters app_handle - Application Handle +** p_open_param - parameters for opening a control channel +** +** Returns void +** +** Note: If the control PSM value is zero then the first HDP +** instance is used for the control channel setup +*******************************************************************************/ + BTA_API extern void BTA_HlCchOpen(tBTA_HL_APP_HANDLE app_handle, + tBTA_HL_CCH_OPEN_PARAM *p_open_param); + +/******************************************************************************* +** +** Function BTA_HlCchClose +** +** Description Close a Control channel connection with the specified MCL +** handle +** +** Parameters mcl_handle - MCL handle +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle); + +/******************************************************************************* +** +** Function BTA_HlDchOpen +** +** Description Open a data channel connection with the specified DCH parameters +** +** Parameters mcl_handle - MCL handle +** p_open_param - parameters for opening a data channel +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_DCH_OPEN_PARAM *p_open_param); +/******************************************************************************* +** +** Function BTA_HlDchReconnect +** +** Description Reconnect a data channel with the specified MDL_ID +** +** Parameters mcl_handle - MCL handle +*8 p_recon_param - parameters for reconnecting a data channel +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_DCH_RECONNECT_PARAM *p_recon_param); +/******************************************************************************* +** +** Function BTA_HlDchClose +** +** Description Close a data channel with the specified MDL handle +** +** Parameters mdl_handle - MDL handle +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle); + +/******************************************************************************* +** +** Function BTA_HlDchAbort +** +** Description Abort the current data channel setup with the specified MCL +** handle +** +** Parameters mcl_handle - MCL handle +** +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle); + +/******************************************************************************* +** +** Function BTA_HlSendData +** +** Description Send an APDU to the peer device +** +** Parameters mdl_handle - MDL handle +** pkt_size - size of the data packet to be sent +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle, + UINT16 pkt_size); + +/******************************************************************************* +** +** Function BTA_HlDeleteMdl +** +** Description Delete the specified MDL_ID within the specified MCL handle +** +** Parameters mcl_handle - MCL handle +** mdl_id - MDL ID +** +** Returns void +** +** note: If mdl_id = 0xFFFF then this means to delete all MDLs +** and this value can only be used with DeleteMdl request only +** not other requests +** +*******************************************************************************/ + BTA_API extern void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_MDL_ID mdl_id ); + +/******************************************************************************* +** +** Function BTA_HlDchEchoTest +** +** Description Initiate an echo test with the specified MCL handle +** +** Parameters mcl_handle - MCL handle +*8 p_echo_test_param - parameters for echo testing +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlDchEchoTest( tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_DCH_ECHO_TEST_PARAM *p_echo_test_param); + +/******************************************************************************* +** +** Function BTA_HlSdpQuery +** +** Description SDP query request for the specified BD address +** +** Parameters app_handle - application handle +** bd_addr - BD address +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlSdpQuery(tBTA_HL_APP_HANDLE app_handle, + BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_HlDchCreateMdlRsp +** +** Description Set the Response and configuration values for the Create MDL +** request +** +** Parameters mcl_handle - MCL handle +** p_rsp_param - parameters specified whether the request should +** be accepted or not and if it should be accepted +** then it also specified the configuration response +** value +** +** Returns void +** +*******************************************************************************/ + BTA_API extern void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_DCH_CREATE_RSP_PARAM *p_rsp_param); + + + +#ifdef __cplusplus + +} +#endif + +#endif /* BTA_HL_API_H */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bta/include/bta_hl_ci.h b/bta/include/bta_hl_ci.h new file mode 100644 index 0000000..4d3951c --- /dev/null +++ b/bta/include/bta_hl_ci.h @@ -0,0 +1,125 @@ +/****************************************************************************** + * + * 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 interface file for the HL (HeaLth device profile) subsystem + * call-in functions. + * + ******************************************************************************/ +#ifndef BTA_HL_CI_H +#define BTA_HL_CI_H + +#include "bta_api.h" +#include "bta_hl_api.h" + + +/***************************************************************************** +** Constants and Data Types +*****************************************************************************/ +/************************** +** Common Definitions +***************************/ +/* Read Ready Event */ +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +/************************** +** Common Functions +***************************/ +/******************************************************************************* +** +** Function bta_hl_ci_get_tx_data +** +** Description This function is called in response to the +** bta_hl_co_get_tx_data call-out function. +** +** Parameters mdl_handle -MDL handle +** status - BTA_MA_STATUS_OK if operation is successful +** BTA_MA_STATUS_FAIL if any errors have occurred. +** evt - evt from the call-out function +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_hl_ci_get_tx_data( tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_STATUS status, + UINT16 evt ); + +/******************************************************************************* +** +** Function bta_hl_ci_put_rx_data +** +** Description This function is called in response to the +** bta_hl_co_put_rx_data call-out function. +** +** Parameters mdl_handle -MDL handle +** status - BTA_MA_STATUS_OK if operation is successful +** BTA_MA_STATUS_FAIL if any errors have occurred. +** evt - evt from the call-out function +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_hl_ci_put_rx_data( tBTA_HL_MDL_HANDLE mdl_handle, + tBTA_HL_STATUS status, + UINT16 evt ); + + + +/******************************************************************************* +** +** Function bta_hl_ci_get_echo_data +** +** Description This function is called in response to the +** bta_hl_co_get_echo_data call-out function. +** +** Parameters mcl_handle -MCL handle +** status - BTA_MA_STATUS_OK if operation is successful +** BTA_MA_STATUS_FAIL if any errors have occurred. +** evt - evt from the call-out function +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_hl_ci_get_echo_data( tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status, + UINT16 evt ); + + +/******************************************************************************* +** +** Function bta_hl_ci_put_echo_data +** +** Description This function is called in response to the +** bta_hl_co_put_echo_data call-out function. +** +** Parameters mcl_handle -MCL handle +** status - BTA_MA_STATUS_OK if operation is successful +** BTA_MA_STATUS_FAIL if any errors have occurred. +** evt - evt from the call-out function +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_hl_ci_put_echo_data( tBTA_HL_MCL_HANDLE mcl_handle, + tBTA_HL_STATUS status, + UINT16 evt ); +#endif /* BTA_HL_CI_H */ + + diff --git a/bta/include/bta_hl_co.h b/bta/include/bta_hl_co.h new file mode 100644 index 0000000..46f8290 --- /dev/null +++ b/bta/include/bta_hl_co.h @@ -0,0 +1,232 @@ +/****************************************************************************** + * + * 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 interface file for the HL (HeaLth device profile) subsystem + * call-out functions. + * + ******************************************************************************/ +#ifndef BTA_HL_CO_H +#define BTA_HL_CO_H + +#include "bta_api.h" +#include "bta_hl_api.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 +** +*******************************************************************************/ +BTA_API extern BOOLEAN bta_hl_co_get_num_of_mdep(UINT8 app_id, UINT8 *p_num_of_mdep); +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern BOOLEAN bta_hl_co_advrtise_source_sdp(UINT8 app_id); +/******************************************************************************* +** +** 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 +*******************************************************************************/ +BTA_API extern 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); + + +/******************************************************************************* +** +** Function bta_hl_co_get_echo_config +** +** Description This function is called to get the echo test +** maximum APDU size configuration +** +** Parameters app_id - HDP application ID +** p_echo_cfg (output) - pointer to the Echo test maximum APDU size +** configuration +** +** Returns Bloolean - TRUE success +*******************************************************************************/ +BTA_API extern BOOLEAN bta_hl_co_get_echo_config(UINT8 app_id, + tBTA_HL_ECHO_CFG *p_echo_cfg); + + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_hl_co_save_mdl(UINT8 app_id, UINT8 item_idx, tBTA_HL_MDL_CFG *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 +** +*******************************************************************************/ +BTA_API extern void bta_hl_co_delete_mdl(UINT8 app_id, UINT8 item_idx); +/******************************************************************************* +** +** Function bta_hl_co_get_mdl_config +** +** Description This function is called to get the MDL configuration +** from teh 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 +** +** +*******************************************************************************/ +BTA_API extern BOOLEAN bta_hl_co_load_mdl_config (UINT8 app_id, UINT8 buffer_size, + tBTA_HL_MDL_CFG *p_mdl_buf ); + + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_hl_co_get_tx_data (UINT8 app_id, tBTA_HL_MDL_HANDLE mdl_handle, + UINT16 buf_size, UINT8 *p_buf, UINT16 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 +** +*******************************************************************************/ +BTA_API extern void bta_hl_co_put_rx_data (UINT8 app_id, tBTA_HL_MDL_HANDLE mdl_handle, + UINT16 data_size, UINT8 *p_data, UINT16 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 +** +*******************************************************************************/ +BTA_API extern void bta_hl_co_get_echo_data (UINT8 app_id, tBTA_HL_MCL_HANDLE mcl_handle, + UINT16 buf_size, UINT8 *p_buf, UINT16 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 +** +*******************************************************************************/ +BTA_API extern void bta_hl_co_put_echo_data (UINT8 app_id, tBTA_HL_MCL_HANDLE mcl_handle, + UINT16 data_size, UINT8 *p_data, UINT16 evt); + +#endif /* BTA_HL_CO_H */ diff --git a/bta/include/bta_jv_api.h b/bta/include/bta_jv_api.h new file mode 100644 index 0000000..73a9164 --- /dev/null +++ b/bta/include/bta_jv_api.h @@ -0,0 +1,1122 @@ +/****************************************************************************** + * + * Copyright (C) 2006-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 public interface file the BTA Java I/F + * + ******************************************************************************/ +#ifndef BTA_JV_API_H +#define BTA_JV_API_H + +#include "data_types.h" +#include "bt_target.h" +#include "bt_types.h" +#include "bta_api.h" +#include "btm_api.h" +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/* status values */ +#define BTA_JV_SUCCESS 0 /* Successful operation. */ +#define BTA_JV_FAILURE 1 /* Generic failure. */ +#define BTA_JV_BUSY 2 /* Temporarily can not handle this request. */ +#define BTA_JV_NO_DATA 3 /* no data. */ + +typedef UINT8 tBTA_JV_STATUS; +#define BTA_JV_INTERNAL_ERR (-1) /* internal error. */ + +#define BTA_JV_MAX_UUIDS SDP_MAX_UUID_FILTERS +#define BTA_JV_MAX_ATTRS SDP_MAX_ATTR_FILTERS +#define BTA_JV_MAX_SDP_REC SDP_MAX_RECORDS +#if SDP_FOR_JV_INCLUDED == TRUE +#define BTA_JV_MAX_L2C_CONN (GAP_MAX_CONNECTIONS + 1) +#else +#define BTA_JV_MAX_L2C_CONN GAP_MAX_CONNECTIONS +#endif +#define BTA_JV_MAX_SCN PORT_MAX_RFC_PORTS /* same as BTM_MAX_SCN (in btm_int.h) */ +#define BTA_JV_MAX_RFC_CONN MAX_RFC_PORTS + +#ifndef BTA_JV_DEF_RFC_MTU +#define BTA_JV_DEF_RFC_MTU (3*330) +#endif + +/* */ +#ifndef BTA_JV_MAX_RFC_SR_SESSION +#define BTA_JV_MAX_RFC_SR_SESSION 3 +#endif + +/* BTA_JV_MAX_RFC_SR_SESSION can not be bigger than MAX_BD_CONNECTIONS */ +#if (BTA_JV_MAX_RFC_SR_SESSION > MAX_BD_CONNECTIONS) +#undef BTA_JV_MAX_RFC_SR_SESSION +#define BTA_JV_MAX_RFC_SR_SESSION MAX_BD_CONNECTIONS +#endif + +#define BTA_JV_FIRST_SERVICE_ID BTA_FIRST_JV_SERVICE_ID +#define BTA_JV_LAST_SERVICE_ID BTA_LAST_JV_SERVICE_ID +#define BTA_JV_NUM_SERVICE_ID (BTA_LAST_JV_SERVICE_ID - BTA_FIRST_JV_SERVICE_ID + 1) + +/* Discoverable modes */ +enum +{ + BTA_JV_DISC_NONE, + BTA_JV_DISC_LIMITED, + BTA_JV_DISC_GENERAL +}; +typedef UINT16 tBTA_JV_DISC; + +/* Security Mode (BTA_JvGetSecurityMode) */ +#define BTA_JV_SEC_MODE_UNDEFINED BTM_SEC_MODE_UNDEFINED /* 0 */ +#define BTA_JV_SEC_MODE_NONE BTM_SEC_MODE_NONE /* 1 */ +#define BTA_JV_SEC_MODE_SERVICE BTM_SEC_MODE_SERVICE /* 2 */ +#define BTA_JV_SEC_MODE_LINK BTM_SEC_MODE_LINK /* 3 */ +#define BTA_JV_SEC_MODE_SP BTM_SEC_MODE_SP /* 4 */ +#define BTA_JV_SEC_MODE_SP_DEBUG BTM_SEC_MODE_SP_DEBUG /* 5 */ +typedef UINT8 tBTA_JV_SEC_MODE; + +#define BTA_JV_ROLE_SLAVE BTM_ROLE_SLAVE +#define BTA_JV_ROLE_MASTER BTM_ROLE_MASTER +typedef UINT32 tBTA_JV_ROLE; + +#define BTA_JV_SERVICE_LMTD_DISCOVER BTM_COD_SERVICE_LMTD_DISCOVER /* 0x0020 */ +#define BTA_JV_SERVICE_POSITIONING BTM_COD_SERVICE_POSITIONING /* 0x0100 */ +#define BTA_JV_SERVICE_NETWORKING BTM_COD_SERVICE_NETWORKING /* 0x0200 */ +#define BTA_JV_SERVICE_RENDERING BTM_COD_SERVICE_RENDERING /* 0x0400 */ +#define BTA_JV_SERVICE_CAPTURING BTM_COD_SERVICE_CAPTURING /* 0x0800 */ +#define BTA_JV_SERVICE_OBJ_TRANSFER BTM_COD_SERVICE_OBJ_TRANSFER /* 0x1000 */ +#define BTA_JV_SERVICE_AUDIO BTM_COD_SERVICE_AUDIO /* 0x2000 */ +#define BTA_JV_SERVICE_TELEPHONY BTM_COD_SERVICE_TELEPHONY /* 0x4000 */ +#define BTA_JV_SERVICE_INFORMATION BTM_COD_SERVICE_INFORMATION /* 0x8000 */ + + + +/* Java I/F callback events */ +/* events received by tBTA_JV_DM_CBACK */ +#define BTA_JV_ENABLE_EVT 0 /* JV enabled */ +#define BTA_JV_SET_DISCOVER_EVT 1 /* the result for BTA_JvSetDiscoverability */ +#define BTA_JV_LOCAL_ADDR_EVT 2 /* Local device address */ +#define BTA_JV_LOCAL_NAME_EVT 3 /* Local device name */ +#define BTA_JV_REMOTE_NAME_EVT 4 /* Remote device name */ +#define BTA_JV_SET_ENCRYPTION_EVT 5 /* Set Encryption */ +#define BTA_JV_GET_SCN_EVT 6 /* Reserved an SCN */ +#define BTA_JV_GET_PSM_EVT 7 /* Reserved a PSM */ +#define BTA_JV_DISCOVERY_COMP_EVT 8 /* SDP discovery complete */ +#define BTA_JV_SERVICES_LEN_EVT 9 /* the result for BTA_JvGetServicesLength */ +#define BTA_JV_SERVICE_SEL_EVT 10 /* the result for BTA_JvServiceSelect */ +#define BTA_JV_CREATE_RECORD_EVT 11 /* the result for BTA_JvCreateRecord */ +#define BTA_JV_UPDATE_RECORD_EVT 12 /* the result for BTA_JvUpdateRecord */ +#define BTA_JV_ADD_ATTR_EVT 13 /* the result for BTA_JvAddAttribute */ +#define BTA_JV_DELETE_ATTR_EVT 14 /* the result for BTA_JvDeleteAttribute */ +#define BTA_JV_CANCEL_DISCVRY_EVT 15 /* the result for BTA_JvCancelDiscovery */ + +/* events received by tBTA_JV_L2CAP_CBACK */ +#define BTA_JV_L2CAP_OPEN_EVT 16 /* open status of L2CAP connection */ +#define BTA_JV_L2CAP_CLOSE_EVT 17 /* L2CAP connection closed */ +#define BTA_JV_L2CAP_START_EVT 18 /* L2CAP server started */ +#define BTA_JV_L2CAP_CL_INIT_EVT 19 /* L2CAP client initiated a connection */ +#define BTA_JV_L2CAP_DATA_IND_EVT 20 /* L2CAP connection received data */ +#define BTA_JV_L2CAP_CONG_EVT 21 /* L2CAP connection congestion status changed */ +#define BTA_JV_L2CAP_READ_EVT 22 /* the result for BTA_JvL2capRead */ +#define BTA_JV_L2CAP_RECEIVE_EVT 23 /* the result for BTA_JvL2capReceive*/ +#define BTA_JV_L2CAP_WRITE_EVT 24 /* the result for BTA_JvL2capWrite*/ + +/* events received by tBTA_JV_RFCOMM_CBACK */ +#define BTA_JV_RFCOMM_OPEN_EVT 25 /* open status of RFCOMM Client connection */ +#define BTA_JV_RFCOMM_CLOSE_EVT 26 /* RFCOMM connection closed */ +#define BTA_JV_RFCOMM_START_EVT 27 /* RFCOMM server started */ +#define BTA_JV_RFCOMM_CL_INIT_EVT 28 /* RFCOMM client initiated a connection */ +#define BTA_JV_RFCOMM_DATA_IND_EVT 29 /* RFCOMM connection received data */ +#define BTA_JV_RFCOMM_CONG_EVT 30 /* RFCOMM connection congestion status changed */ +#define BTA_JV_RFCOMM_READ_EVT 31 /* the result for BTA_JvRfcommRead */ +#define BTA_JV_RFCOMM_WRITE_EVT 32 /* the result for BTA_JvRfcommWrite*/ +#define BTA_JV_RFCOMM_SRV_OPEN_EVT 33 /* open status of Server RFCOMM connection */ +#define BTA_JV_MAX_EVT 34 /* max number of JV events */ + +typedef UINT16 tBTA_JV_EVT; + +/* data associated with BTA_JV_SET_DISCOVER_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + tBTA_JV_DISC disc_mode; /* The current discoverable mode */ +} tBTA_JV_SET_DISCOVER; + +/* data associated with BTA_JV_DISCOVERY_COMP_EVT_ */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + int scn; /* channel # */ +} tBTA_JV_DISCOVERY_COMP; + +/* data associated with BTA_JV_SET_ENCRYPTION_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + BD_ADDR bd_addr; /* The peer address */ +} tBTA_JV_SET_ENCRYPTION; + +/* data associated with BTA_JV_SERVICES_LEN_EVT */ +typedef struct +{ + INT32 num_services; /* -1, if error. Otherwise, the number of + * services collected from peer */ + UINT16 *p_services_len; /* this points the same location as the + * parameter in BTA_JvGetServicesLength() */ +} tBTA_JV_SERVICES_LEN; + +/* data associated with BTA_JV_SERVICE_SEL_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* The peer address */ + UINT16 service_len; /* the length of this record */ +} tBTA_JV_SERVICE_SEL; + +/* data associated with BTA_JV_CREATE_RECORD_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ +} tBTA_JV_CREATE_RECORD; + +/* data associated with BTA_JV_UPDATE_RECORD_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The SDP record handle was updated */ +} tBTA_JV_UPDATE_RECORD; + +/* data associated with BTA_JV_ADD_ATTR_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The SDP record handle was updated */ +} tBTA_JV_ADD_ATTR; + +/* data associated with BTA_JV_DELETE_ATTR_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The SDP record handle was updated */ +} tBTA_JV_DELETE_ATTR; + +/* data associated with BTA_JV_L2CAP_OPEN_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + BD_ADDR rem_bda; /* The peer address */ + INT32 tx_mtu; /* The transmit MTU */ +} tBTA_JV_L2CAP_OPEN; + +/* data associated with BTA_JV_L2CAP_CLOSE_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + BOOLEAN async; /* FALSE, if local initiates disconnect */ +} tBTA_JV_L2CAP_CLOSE; + +/* data associated with BTA_JV_L2CAP_START_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT8 sec_id; /* security ID used by this server */ +} tBTA_JV_L2CAP_START; + +/* data associated with BTA_JV_L2CAP_CL_INIT_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT8 sec_id; /* security ID used by this client */ +} tBTA_JV_L2CAP_CL_INIT; + +/* data associated with BTA_JV_L2CAP_CONG_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + BOOLEAN cong; /* TRUE, congested. FALSE, uncongested */ +} tBTA_JV_L2CAP_CONG; + +/* data associated with BTA_JV_L2CAP_READ_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT32 req_id; /* The req_id in the associated BTA_JvL2capRead() */ + UINT8 *p_data; /* This points the same location as the p_data + * parameter in BTA_JvL2capRead () */ + UINT16 len; /* The length of the data read. */ +} tBTA_JV_L2CAP_READ; + +/* data associated with BTA_JV_L2CAP_RECEIVE_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT32 req_id; /* The req_id in the associated BTA_JvL2capReceive() */ + UINT8 *p_data; /* This points the same location as the p_data + * parameter in BTA_JvL2capReceive () */ + UINT16 len; /* The length of the data read. */ +} tBTA_JV_L2CAP_RECEIVE; + +/* data associated with BTA_JV_L2CAP_WRITE_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT32 req_id; /* The req_id in the associated BTA_JvL2capWrite() */ + UINT16 len; /* The length of the data written. */ + BOOLEAN cong; /* congestion status */ +} tBTA_JV_L2CAP_WRITE; + +/* data associated with BTA_JV_RFCOMM_OPEN_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + BD_ADDR rem_bda; /* The peer address */ +} tBTA_JV_RFCOMM_OPEN; +/* data associated with BTA_JV_RFCOMM_SRV_OPEN_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT32 new_listen_handle; /* The new listen handle */ + BD_ADDR rem_bda; /* The peer address */ +} tBTA_JV_RFCOMM_SRV_OPEN; + + +/* data associated with BTA_JV_RFCOMM_CLOSE_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 port_status; /* PORT status */ + UINT32 handle; /* The connection handle */ + BOOLEAN async; /* FALSE, if local initiates disconnect */ +} tBTA_JV_RFCOMM_CLOSE; + +/* data associated with BTA_JV_RFCOMM_START_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT8 sec_id; /* security ID used by this server */ + BOOLEAN use_co; /* TRUE to use co_rfc_data */ +} tBTA_JV_RFCOMM_START; + +/* data associated with BTA_JV_RFCOMM_CL_INIT_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT8 sec_id; /* security ID used by this client */ + BOOLEAN use_co; /* TRUE to use co_rfc_data */ +} tBTA_JV_RFCOMM_CL_INIT; +/*data associated with BTA_JV_L2CAP_DATA_IND_EVT & BTA_JV_RFCOMM_DATA_IND_EVT */ +typedef struct +{ + UINT32 handle; /* The connection handle */ +} tBTA_JV_DATA_IND; + +/* data associated with BTA_JV_RFCOMM_CONG_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + BOOLEAN cong; /* TRUE, congested. FALSE, uncongested */ +} tBTA_JV_RFCOMM_CONG; + +/* data associated with BTA_JV_RFCOMM_READ_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT32 req_id; /* The req_id in the associated BTA_JvRfcommRead() */ + UINT8 *p_data; /* This points the same location as the p_data + * parameter in BTA_JvRfcommRead () */ + UINT16 len; /* The length of the data read. */ +} tBTA_JV_RFCOMM_READ; + +/* data associated with BTA_JV_RFCOMM_WRITE_EVT */ +typedef struct +{ + tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */ + UINT32 handle; /* The connection handle */ + UINT32 req_id; /* The req_id in the associated BTA_JvRfcommWrite() */ + int len; /* The length of the data written. */ + BOOLEAN cong; /* congestion status */ +} tBTA_JV_RFCOMM_WRITE; + + +/* union of data associated with JV callback */ +typedef union +{ + tBTA_JV_STATUS status; /* BTA_JV_ENABLE_EVT */ + tBTA_JV_DISCOVERY_COMP disc_comp; /* BTA_JV_DISCOVERY_COMP_EVT */ + tBTA_JV_SET_DISCOVER set_discover; /* BTA_JV_SET_DISCOVER_EVT */ + tBTA_JV_SET_ENCRYPTION set_encrypt; /* BTA_JV_SET_ENCRYPTION_EVT */ + BD_ADDR bd_addr; /* BTA_JV_LOCAL_ADDR_EVT */ + UINT8 *p_name; /* BTA_JV_LOCAL_NAME_EVT, + BTA_JV_REMOTE_NAME_EVT */ + UINT8 scn; /* BTA_JV_GET_SCN_EVT */ + UINT16 psm; /* BTA_JV_GET_PSM_EVT */ + tBTA_JV_SERVICES_LEN servs_len; /* BTA_JV_SERVICES_LEN_EVT */ + tBTA_JV_SERVICE_SEL serv_sel; /* BTA_JV_SERVICE_SEL_EVT */ + tBTA_JV_CREATE_RECORD create_rec; /* BTA_JV_CREATE_RECORD_EVT */ + tBTA_JV_UPDATE_RECORD update_rec; /* BTA_JV_UPDATE_RECORD_EVT */ + tBTA_JV_ADD_ATTR add_attr; /* BTA_JV_ADD_ATTR_EVT */ + tBTA_JV_DELETE_ATTR del_attr; /* BTA_JV_DELETE_ATTR_EVT */ + tBTA_JV_L2CAP_OPEN l2c_open; /* BTA_JV_L2CAP_OPEN_EVT */ + tBTA_JV_L2CAP_CLOSE l2c_close; /* BTA_JV_L2CAP_CLOSE_EVT */ + tBTA_JV_L2CAP_START l2c_start; /* BTA_JV_L2CAP_START_EVT */ + tBTA_JV_L2CAP_CL_INIT l2c_cl_init; /* BTA_JV_L2CAP_CL_INIT_EVT */ + tBTA_JV_L2CAP_CONG l2c_cong; /* BTA_JV_L2CAP_CONG_EVT */ + tBTA_JV_L2CAP_READ l2c_read; /* BTA_JV_L2CAP_READ_EVT */ + tBTA_JV_L2CAP_WRITE l2c_write; /* BTA_JV_L2CAP_WRITE_EVT */ + tBTA_JV_RFCOMM_OPEN rfc_open; /* BTA_JV_RFCOMM_OPEN_EVT */ + tBTA_JV_RFCOMM_SRV_OPEN rfc_srv_open; /* BTA_JV_RFCOMM_SRV_OPEN_EVT */ + tBTA_JV_RFCOMM_CLOSE rfc_close; /* BTA_JV_RFCOMM_CLOSE_EVT */ + tBTA_JV_RFCOMM_START rfc_start; /* BTA_JV_RFCOMM_START_EVT */ + tBTA_JV_RFCOMM_CL_INIT rfc_cl_init; /* BTA_JV_RFCOMM_CL_INIT_EVT */ + tBTA_JV_RFCOMM_CONG rfc_cong; /* BTA_JV_RFCOMM_CONG_EVT */ + tBTA_JV_RFCOMM_READ rfc_read; /* BTA_JV_RFCOMM_READ_EVT */ + tBTA_JV_RFCOMM_WRITE rfc_write; /* BTA_JV_RFCOMM_WRITE_EVT */ + tBTA_JV_DATA_IND data_ind; /* BTA_JV_L2CAP_DATA_IND_EVT + BTA_JV_RFCOMM_DATA_IND_EVT */ +} tBTA_JV; + +/* JAVA DM Interface callback */ +typedef void (tBTA_JV_DM_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void * user_data); + +/* JAVA RFCOMM interface callback */ +typedef void* (tBTA_JV_RFCOMM_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data); + +/* JAVA L2CAP interface callback */ +typedef void (tBTA_JV_L2CAP_CBACK)(tBTA_JV_EVT event, tBTA_JV *p_data); + +/* JV configuration structure */ +typedef struct +{ + UINT16 sdp_raw_size; /* The size of p_sdp_raw_data */ + UINT16 sdp_db_size; /* The size of p_sdp_db */ + UINT8 *p_sdp_raw_data; /* The data buffer to keep raw data */ + tSDP_DISCOVERY_DB *p_sdp_db; /* The data buffer to keep SDP database */ +} tBTA_JV_CFG; + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function BTA_JvEnable +** +** Description Enable the Java I/F service. When the enable +** operation is complete the callback function will be +** called with a BTA_JV_ENABLE_EVT. This function must +** be called before other functions in the JV API are +** called. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_JvDisable +** +** Description Disable the Java I/F +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_JvDisable(void); + +/******************************************************************************* +** +** Function BTA_JvIsEnable +** +** Description Get the JV registration status. +** +** Returns TRUE, if registered +** +*******************************************************************************/ +BTA_API extern BOOLEAN BTA_JvIsEnable(void); + +/******************************************************************************* +** +** Function BTA_JvSetDiscoverability +** +** Description This function sets the Bluetooth discoverable modes +** of the local device. This controls whether other +** Bluetooth devices can find the local device. +** +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_SET_DISCOVER_EVT. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvSetDiscoverability(tBTA_JV_DISC disc_mode); + +/******************************************************************************* +** +** Function BTA_JvGetDiscoverability +** +** Description This function gets the Bluetooth +** discoverable modes of local device +** +** Returns The current Bluetooth discoverable mode. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_DISC BTA_JvGetDiscoverability(void); + +/******************************************************************************* +** +** Function BTA_JvGetLocalDeviceAddr +** +** Description This function obtains the local Bluetooth device address. +** The local Bluetooth device address is reported by the +** tBTA_JV_DM_CBACK callback with a BTA_JV_LOCAL_ADDR_EVT. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvGetLocalDeviceAddr(void); + +/******************************************************************************* +** +** Function BTA_JvGetLocalDeviceName +** +** Description This function obtains the name of the local device +** The local Bluetooth device name is reported by the +** tBTA_JV_DM_CBACK callback with a BTA_JV_LOCAL_NAME_EVT. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvGetLocalDeviceName(void); + +/******************************************************************************* +** +** Function BTA_JvGetRemoteDeviceName +** +** Description This function obtains the name of the specified device. +** The Bluetooth device name is reported by the +** tBTA_JV_DM_CBACK callback with a BTA_JV_REMOTE_NAME_EVT. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvGetRemoteDeviceName(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_JvGetPreknownDevice +** +** Description This function obtains the Bluetooth address in the inquiry +** database collected via the previous call to BTA_DmSearch(). +** +** Returns The number of preknown devices if p_bd_addr is NULL +** BTA_JV_SUCCESS if successful. +** BTA_JV_INTERNAL_ERR(-1) if internal failure. +** +*******************************************************************************/ +BTA_API extern INT32 BTA_JvGetPreknownDevice(UINT8 * p_bd_addr, UINT32 index); + +/******************************************************************************* +** +** Function BTA_JvGetDeviceClass +** +** Description This function obtains the local Class of Device. +** +** Returns DEV_CLASS, A three-byte array of UINT8 that contains the +** Class of Device information. The definitions are in the +** "Bluetooth Assigned Numbers". +** +*******************************************************************************/ +BTA_API extern UINT8 * BTA_JvGetDeviceClass(void); + +/******************************************************************************* +** +** Function BTA_JvSetServiceClass +** +** Description This function sets the service class of local Class of Device +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvSetServiceClass(UINT32 service); + +/******************************************************************************* +** +** Function BTA_JvSetEncryption +** +** Description This function ensures that the connection to the given device +** is encrypted. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_SET_ENCRYPTION_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvSetEncryption(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_JvIsAuthenticated +** +** Description This function checks if the peer device is authenticated +** +** Returns TRUE if authenticated. +** FALSE if not. +** +*******************************************************************************/ +BTA_API extern BOOLEAN BTA_JvIsAuthenticated(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_JvIsTrusted +** +** Description This function checks if the peer device is trusted +** (previously paired) +** +** Returns TRUE if trusted. +** FALSE if not. +** +*******************************************************************************/ +BTA_API extern BOOLEAN BTA_JvIsTrusted(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_JvIsAuthorized +** +** Description This function checks if the peer device is authorized +** +** Returns TRUE if authorized. +** FALSE if not. +** +*******************************************************************************/ +BTA_API extern BOOLEAN BTA_JvIsAuthorized(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_JvIsEncrypted +** +** Description This function checks if the link to peer device is encrypted +** +** Returns TRUE if encrypted. +** FALSE if not. +** +*******************************************************************************/ +BTA_API extern BOOLEAN BTA_JvIsEncrypted(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_JvGetSecurityMode +** +** Description This function returns the current Bluetooth security mode +** of the local device +** +** Returns The current Bluetooth security mode. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_SEC_MODE BTA_JvGetSecurityMode(void); + +/* BTA_JvIsMaster is replaced by BTA_DmIsMaster */ + +/******************************************************************************* +** +** Function BTA_JvGetSCN +** +** Description This function reserves a SCN (server channel number) for +** applications running over RFCOMM. It is primarily called by +** server profiles/applications to register their SCN into the +** SDP database. The SCN is reported by the tBTA_JV_DM_CBACK +** callback with a BTA_JV_GET_SCN_EVT. +** If the SCN reported is 0, that means all SCN resources are +** exhausted. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvGetSCN(void); + +/******************************************************************************* +** +** Function BTA_JvFreeSCN +** +** Description This function frees a server channel number that was used +** by an application running over RFCOMM. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvFreeSCN(UINT8 scn); + +/******************************************************************************* +** +** Function BTA_JvGetPSM +** +** Description This function reserves a PSM (Protocol Service Multiplexer) +** applications running over L2CAP. It is primarily called by +** server profiles/applications to register their PSM into the +** SDP database. +** +** Returns The next free PSM +** +*******************************************************************************/ +BTA_API extern UINT16 BTA_JvGetPSM(void); + +/******************************************************************************* +** +** Function BTA_JvStartDiscovery +** +** Description This function performs service discovery for the services +** provided by the given peer device. When the operation is +** complete the tBTA_JV_DM_CBACK callback function will be +** called with a BTA_JV_DISCOVERY_COMP_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, UINT16 num_uuid, + tSDP_UUID *p_uuid_list, void* user_data); + +/******************************************************************************* +** +** Function BTA_JvCancelDiscovery +** +** Description This function cancels an active service discovery. +** When the operation is +** complete the tBTA_JV_DM_CBACK callback function will be +** called with a BTA_JV_CANCEL_DISCVRY_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvCancelDiscovery(void * user_data); + +/******************************************************************************* +** +** Function BTA_JvGetServicesLength +** +** Description This function obtains the number of services and the length +** of each service found in the SDP database (result of last +** BTA_JvStartDiscovery().When the operation is complete the +** tBTA_JV_DM_CBACK callback function will be called with a +** BTA_JV_SERVICES_LEN_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvGetServicesLength(BOOLEAN inc_hdr, UINT16 *p_services_len); + +/******************************************************************************* +** +** Function BTA_JvGetServicesResult +** +** Description This function returns a number of service records found +** during current service search, equals to the number returned +** by previous call to BTA_JvGetServicesLength. +** The contents of each SDP record will be returned under a +** TLV (type, len, value) representation in the data buffer +** provided by the caller. +** +** Returns -1, if error. Otherwise, the number of services +** +*******************************************************************************/ +BTA_API extern INT32 BTA_JvGetServicesResult(BOOLEAN inc_hdr, UINT8 **TLVs); + +/******************************************************************************* +** +** Function BTA_JvServiceSelect +** +** Description This function checks if the SDP database contains the given +** service UUID. When the operation is complete the +** tBTA_JV_DM_CBACK callback function will be called with a +** BTA_JV_SERVICE_SEL_EVT with the length of the service record. +** If the service is not found or error, -1 is reported. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvServiceSelect(UINT16 uuid); + +/******************************************************************************* +** +** Function BTA_JvServiceResult +** +** Description This function returns the contents of the SDP record from +** last BTA_JvServiceSelect. The contents will be returned under +** a TLV (type, len, value) representation in the data buffer +** provided by the caller. +** +** Returns -1, if error. Otherwise, the length of service record. +** +*******************************************************************************/ +BTA_API extern INT32 BTA_JvServiceResult(UINT8 *TLV); + +/******************************************************************************* +** +** Function BTA_JvCreateRecord +** +** Description Create a service record in the local SDP database by user in +** tBTA_JV_DM_CBACK callback with a BTA_JV_CREATE_RECORD_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvCreateRecordByUser(void* user_data); + +/******************************************************************************* +** +** Function BTA_JvUpdateRecord +** +** Description Update a service record in the local SDP database. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_UPDATE_RECORD_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvUpdateRecord(UINT32 handle, UINT16 *p_ids, + UINT8 **p_values, INT32 *p_value_sizes, INT32 array_len); + +/******************************************************************************* +** +** Function BTA_JvAddAttribute +** +** Description Add an attribute to a service record in the local SDP database. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_ADD_ATTR_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvAddAttribute(UINT32 handle, UINT16 attr_id, + UINT8 *p_value, INT32 value_size); + +/******************************************************************************* +** +** Function BTA_JvDeleteAttribute +** +** Description Delete an attribute from a service record in the local SDP database. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_DELETE_ATTR_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvDeleteAttribute(UINT32 handle, UINT16 attr_id); + +/******************************************************************************* +** +** Function BTA_JvDeleteRecord +** +** Description Delete a service record in the local SDP database. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvDeleteRecord(UINT32 handle); + +/******************************************************************************* +** +** Function BTA_JvReadRecord +** +** Description Read a service record in the local SDP database. +** +** Returns -1, if the record is not found. +** Otherwise, the offset (0 or 1) to start of data in p_data. +** +** The size of data copied into p_data is in *p_data_len. +** +*******************************************************************************/ +BTA_API extern INT32 BTA_JvReadRecord(UINT32 handle, UINT8 *p_data, INT32 *p_data_len); + +/******************************************************************************* +** +** Function BTA_JvL2capConnect +** +** Description Initiate a connection as a L2CAP client to the given BD +** Address. +** When the connection is initiated or failed to initiate, +** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT +** When the connection is established or failed, +** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, + tBTA_JV_ROLE role, UINT16 remote_psm, UINT16 rx_mtu, + BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_JvL2capClose +** +** Description This function closes an L2CAP client connection +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle); + +/******************************************************************************* +** +** Function BTA_JvL2capStartServer +** +** Description This function starts an L2CAP server and listens for an L2CAP +** connection from a remote Bluetooth device. When the server +** is started successfully, tBTA_JV_L2CAP_CBACK is called with +** BTA_JV_L2CAP_START_EVT. When the connection is established, +** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvL2capStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role, + UINT16 local_psm, UINT16 rx_mtu, + tBTA_JV_L2CAP_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_JvL2capStopServer +** +** Description This function stops the L2CAP server. If the server has an +** active connection, it would be closed. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvL2capStopServer(UINT16 local_psm); + +/******************************************************************************* +** +** Function BTA_JvL2capRead +** +** Description This function reads data from an L2CAP connection +** When the operation is complete, tBTA_JV_L2CAP_CBACK is +** called with BTA_JV_L2CAP_READ_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id, + UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function BTA_JvL2capReceive +** +** Description This function reads data from an L2CAP connection +** When the operation is complete, tBTA_JV_L2CAP_CBACK is +** called with BTA_JV_L2CAP_RECEIVE_EVT. +** If there are more data queued in L2CAP than len, the extra data will be discarded. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvL2capReceive(UINT32 handle, UINT32 req_id, + UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function BTA_JvL2capReady +** +** Description This function determined if there is data to read from +** an L2CAP connection +** +** Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size. +** BTA_JV_FAILURE, if error. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvL2capReady(UINT32 handle, UINT32 *p_data_size); + +/******************************************************************************* +** +** Function BTA_JvL2capWrite +** +** Description This function writes data to an L2CAP connection +** When the operation is complete, tBTA_JV_L2CAP_CBACK is +** called with BTA_JV_L2CAP_WRITE_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvL2capWrite(UINT32 handle, UINT32 req_id, + UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function BTA_JvRfcommConnect +** +** Description This function makes an RFCOMM conection to a remote BD +** Address. +** When the connection is initiated or failed to initiate, +** tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_CL_INIT_EVT +** When the connection is established or failed, +** tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_OPEN_EVT +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, + tBTA_JV_ROLE role, UINT8 remote_scn, BD_ADDR peer_bd_addr, + tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data); + +/******************************************************************************* +** +** Function BTA_JvRfcommClose +** +** Description This function closes an RFCOMM connection +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvRfcommClose(UINT32 handle); + +/******************************************************************************* +** +** Function BTA_JvRfcommStartServer +** +** Description This function starts listening for an RFCOMM connection +** request from a remote Bluetooth device. When the server is +** started successfully, tBTA_JV_RFCOMM_CBACK is called +** with BTA_JV_RFCOMM_START_EVT. +** When the connection is established, tBTA_JV_RFCOMM_CBACK +** is called with BTA_JV_RFCOMM_OPEN_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, + tBTA_JV_ROLE role, UINT8 local_scn, UINT8 max_session, + tBTA_JV_RFCOMM_CBACK *p_cback, void *user_data); + +/******************************************************************************* +** +** Function BTA_JvRfcommStopServer +** +** Description This function stops the RFCOMM server. If the server has an +** active connection, it would be closed. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvRfcommStopServer(UINT32 handle); + +/******************************************************************************* +** +** Function BTA_JvRfcommRead +** +** Description This function reads data from an RFCOMM connection +** When the operation is complete, tBTA_JV_RFCOMM_CBACK is +** called with BTA_JV_RFCOMM_READ_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvRfcommRead(UINT32 handle, UINT32 req_id, + UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function BTA_JvRfcommReady +** +** Description This function determined if there is data to read from +** an RFCOMM connection +** +** Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size. +** BTA_JV_FAILURE, if error. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvRfcommReady(UINT32 handle, UINT32 *p_data_size); + +/******************************************************************************* +** +** Function BTA_JvRfcommWrite +** +** Description This function writes data to an RFCOMM connection +** When the operation is complete, tBTA_JV_RFCOMM_CBACK is +** called with BTA_JV_RFCOMM_WRITE_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +BTA_API extern tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id); + + +/******************************************************************************* +** +** Function BTA_JvRfcommGetPortHdl +** +** Description This function fetches the rfcomm port handle +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +UINT16 BTA_JvRfcommGetPortHdl(UINT32 handle); + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_JV_API_H */ + diff --git a/bta/include/bta_jv_co.h b/bta/include/bta_jv_co.h new file mode 100644 index 0000000..098766c --- /dev/null +++ b/bta/include/bta_jv_co.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * Copyright (C) 2007-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 interface file for java interface call-out functions. + * + ******************************************************************************/ +#ifndef BTA_JV_CO_H +#define BTA_JV_CO_H + +#include "bta_jv_api.h" + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + + +/******************************************************************************* +** +** Function bta_jv_co_rfc_data +** +** Description This function is called by JV to send data to the java glue +** code when the RX data path is configured to use a call-out +** +** Returns void +** +*******************************************************************************/ + +BTA_API extern int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf); +BTA_API extern int bta_co_rfc_data_outgoing_size(void *user_data, int *size); +BTA_API extern int bta_co_rfc_data_outgoing(void *user_data, UINT8* buf, UINT16 size); + +#endif /* BTA_DG_CO_H */ + diff --git a/bta/include/bta_op_api.h b/bta/include/bta_op_api.h new file mode 100644 index 0000000..c26ea35 --- /dev/null +++ b/bta/include/bta_op_api.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 public interface file for the object push (OP) client and + * server subsystem of BTA, Broadcom's Bluetooth application layer for + * mobile phones. + * + ******************************************************************************/ +#ifndef BTA_OP_API_H +#define BTA_OP_API_H + +#include "bta_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/* Extra Debug Code */ +#ifndef BTA_OPS_DEBUG +#define BTA_OPS_DEBUG FALSE +#endif + +#ifndef BTA_OPC_DEBUG +#define BTA_OPC_DEBUG FALSE +#endif + + +/* Object format */ +#define BTA_OP_VCARD21_FMT 1 /* vCard 2.1 */ +#define BTA_OP_VCARD30_FMT 2 /* vCard 3.0 */ +#define BTA_OP_VCAL_FMT 3 /* vCal 1.0 */ +#define BTA_OP_ICAL_FMT 4 /* iCal 2.0 */ +#define BTA_OP_VNOTE_FMT 5 /* vNote */ +#define BTA_OP_VMSG_FMT 6 /* vMessage */ +#define BTA_OP_OTHER_FMT 0xFF /* other format */ + +typedef UINT8 tBTA_OP_FMT; + +/* Object format mask */ +#define BTA_OP_VCARD21_MASK 0x01 /* vCard 2.1 */ +#define BTA_OP_VCARD30_MASK 0x02 /* vCard 3.0 */ +#define BTA_OP_VCAL_MASK 0x04 /* vCal 1.0 */ +#define BTA_OP_ICAL_MASK 0x08 /* iCal 2.0 */ +#define BTA_OP_VNOTE_MASK 0x10 /* vNote */ +#define BTA_OP_VMSG_MASK 0x20 /* vMessage */ +#define BTA_OP_ANY_MASK 0x40 /* Any type of object. */ + +typedef UINT8 tBTA_OP_FMT_MASK; + +#endif /* BTA_OP_API_H */ + diff --git a/bta/include/bta_pan_api.h b/bta/include/bta_pan_api.h new file mode 100644 index 0000000..2166766 --- /dev/null +++ b/bta/include/bta_pan_api.h @@ -0,0 +1,201 @@ +/****************************************************************************** + * + * 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 public interface file for the Personal Area Networking (PAN) + * subsystem of BTA, Broadcom's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ +#ifndef BTA_PAN_API_H +#define BTA_PAN_API_H + +#include "bta_api.h" +#include "pan_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +#define BTA_PAN_SUCCESS 0 +#define BTA_PAN_FAIL 1 + +typedef UINT8 tBTA_PAN_STATUS; + + +/* PAN Callback events */ +#define BTA_PAN_ENABLE_EVT 0 /* PAN service is enabled. */ +#define BTA_PAN_SET_ROLE_EVT 1 /* PAN roles registered */ +#define BTA_PAN_OPENING_EVT 2 /* Connection is being opened. */ +#define BTA_PAN_OPEN_EVT 3 /* Connection has been opened. */ +#define BTA_PAN_CLOSE_EVT 4 /* Connection has been closed. */ + +typedef UINT8 tBTA_PAN_EVT; + + +/* pan roles */ +#define BTA_PAN_ROLE_PANU PAN_ROLE_CLIENT +#define BTA_PAN_ROLE_GN PAN_ROLE_GN_SERVER +#define BTA_PAN_ROLE_NAP PAN_ROLE_NAP_SERVER + + +typedef UINT8 tBTA_PAN_ROLE; + +/* information regarding PAN roles */ +typedef struct +{ + char *p_srv_name; /* service name for the PAN role */ + UINT8 app_id; /* application id */ + tBTA_SEC sec_mask; /* security setting for the role */ + +} tBTA_PAN_ROLE_INFO; + + +/* Event associated with BTA_PAN_SET_ROLE_EVT */ +typedef struct +{ + tBTA_PAN_STATUS status; /* status of set role event */ + tBTA_PAN_ROLE role; /* PAN roles successfully registered */ +} tBTA_PAN_SET_ROLE; + +/* Event associated with BTA_PAN_OPENING_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address of peer device. */ + UINT16 handle; /* Handle associated with this connection. */ + +} tBTA_PAN_OPENING; + + +/* Event associated with BTA_PAN_OPEN_EVT */ +typedef struct +{ + BD_ADDR bd_addr; /* BD address of peer device. */ + UINT16 handle; /* Handle associated with this connection. */ + tBTA_PAN_STATUS status; /* status of open event */ + tBTA_PAN_ROLE local_role; /* Local device PAN role for the connection */ + tBTA_PAN_ROLE peer_role; /* Peer device PAN role for the connection */ + +} tBTA_PAN_OPEN; + +/* Event associated with BTA_PAN_CLOSE_EVT */ +typedef struct +{ + UINT16 handle; /* Handle associated with the connection. */ +} tBTA_PAN_CLOSE; + +/* Union of all PAN callback structures */ +typedef union +{ + tBTA_PAN_SET_ROLE set_role; /* set_role event */ + tBTA_PAN_OPEN open; /* Connection has been opened. */ + tBTA_PAN_OPENING opening; /* Connection being opened */ + tBTA_PAN_CLOSE close; /* Connection has been closed. */ +} tBTA_PAN; + +/* Number of PAN connections */ +#ifndef BTA_PAN_NUM_CONN +#define BTA_PAN_NUM_CONN 4 +#endif + +/* PAN callback */ +typedef void (tBTA_PAN_CBACK)(tBTA_PAN_EVT event, tBTA_PAN *p_data); + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function BTA_PanEnable +** +** Description Enable PAN service. This function must be +** called before any other functions in the PAN API are called. +** When the enable operation is complete the callback function +** will be called with a BTA_PAN_ENABLE_EVT. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_PanEnable(tBTA_PAN_CBACK p_cback); + +/******************************************************************************* +** +** Function BTA_PanDisable +** +** Description Disable PAN service. +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_PanDisable(void); + + +/******************************************************************************* +** +** Function BTA_PanSetRole +** +** Description Sets PAN roles. When the enable operation is complete +** the callback function will be called with a BTA_PAN_SET_ROLE_EVT. +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_PanSetRole(tBTA_PAN_ROLE role, tBTA_PAN_ROLE_INFO *p_user_info, tBTA_PAN_ROLE_INFO *p_gn_info, + tBTA_PAN_ROLE_INFO *p_nap_info); + + +/******************************************************************************* +** +** Function BTA_PanOpen +** +** Description Opens a connection to a peer device. +** When connection is open callback function is called +** with a BTA_PAN_OPEN_EVT. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_PanOpen(BD_ADDR bd_addr, tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role); + + + +/******************************************************************************* +** +** Function BTA_PanClose +** +** Description Close a PAN connection to a peer device. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void BTA_PanClose(UINT16 handle); + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_PAN_API_H */ + diff --git a/bta/include/bta_pan_ci.h b/bta/include/bta_pan_ci.h new file mode 100644 index 0000000..faeef54 --- /dev/null +++ b/bta/include/bta_pan_ci.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * 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 interface file for pan call-in functions. + * + ******************************************************************************/ +#ifndef BTA_PAN_CI_H +#define BTA_PAN_CI_H + +#include "bta_pan_api.h" + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_pan_ci_tx_ready +** +** Description This function sends an event to PAN indicating the phone is +** ready for more data and PAN should call bta_pan_co_tx_path(). +** This function is used when the TX data path is configured +** to use a pull interface. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_ci_tx_ready(UINT16 handle); + +/******************************************************************************* +** +** Function bta_pan_ci_rx_ready +** +** Description This function sends an event to PAN indicating the phone +** has data available to send to PAN and PAN should call +** bta_pan_co_rx_path(). This function is used when the RX +** data path is configured to use a pull interface. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_ci_rx_ready(UINT16 handle); + +/******************************************************************************* +** +** Function bta_pan_ci_tx_flow +** +** Description This function is called to enable or disable data flow on +** the TX path. The phone should call this function to +** disable data flow when it is congested and cannot handle +** any more data sent by bta_pan_co_tx_write() or +** bta_pan_co_tx_writebuf(). This function is used when the +** TX data path is configured to use a push interface. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_ci_tx_flow(UINT16 handle, BOOLEAN enable); + +/******************************************************************************* +** +** Function bta_pan_ci_rx_writebuf +** +** Description This function is called to send data to the phone when +** the RX path is configured to use a push interface with +** zero copy. The function sends an event to PAN containing +** the data buffer. The buffer must be allocated using +** functions GKI_getbuf() or GKI_getpoolbuf(). The buffer +** will be freed by BTA; the phone must not free the buffer. +** +** +** Returns TRUE if flow enabled +** +*******************************************************************************/ +BTA_API extern void bta_pan_ci_rx_writebuf(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf, BOOLEAN ext); + +/******************************************************************************* +** +** Function bta_pan_ci_readbuf +** +** Description This function is called by the phone to read data from PAN +** when the TX path is configured to use a pull interface. +** The phone must free the buffer using function GKI_freebuf() when +** it is through processing the buffer. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern BT_HDR * bta_pan_ci_readbuf(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 *p_protocol, + BOOLEAN* p_ext, BOOLEAN* p_forward); + +/******************************************************************************* +** +** Function bta_pan_ci_set_pfilters +** +** Description This function is called to set protocol filters +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_ci_set_pfilters(UINT16 handle, UINT16 num_filters, UINT16 *p_start_array, UINT16 *p_end_array); + + +/******************************************************************************* +** +** Function bta_pan_ci_set_mfilters +** +** Description This function is called to set multicast filters +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_ci_set_mfilters(UINT16 handle, UINT16 num_mcast_filters, UINT8 *p_start_array, + UINT8 *p_end_array); + + + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_PAN_CI_H */ + diff --git a/bta/include/bta_pan_co.h b/bta/include/bta_pan_co.h new file mode 100644 index 0000000..5b20fad --- /dev/null +++ b/bta/include/bta_pan_co.h @@ -0,0 +1,201 @@ +/****************************************************************************** + * + * 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 interface file for data gateway call-out functions. + * + ******************************************************************************/ +#ifndef BTA_PAN_CO_H +#define BTA_PAN_CO_H + +#include "bta_pan_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + + + +/* BT_HDR buffer offset */ +#define BTA_PAN_MIN_OFFSET PAN_MINIMUM_OFFSET + + +/* Data Flow Mask */ +#define BTA_PAN_RX_PUSH 0x00 /* RX push. */ +#define BTA_PAN_RX_PUSH_BUF 0x01 /* RX push with zero copy. */ +#define BTA_PAN_RX_PULL 0x02 /* RX pull. */ +#define BTA_PAN_TX_PUSH 0x00 /* TX push. */ +#define BTA_PAN_TX_PUSH_BUF 0x10 /* TX push with zero copy. */ +#define BTA_PAN_TX_PULL 0x20 /* TX pull. */ + + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function bta_pan_co_init +** +** Description This callout function is executed by PAN when a server is +** started by calling BTA_PanEnable(). This function can be +** used by the phone to initialize data paths or for other +** initialization purposes. The function must return the +** data flow mask as described below. +** +** +** Returns Data flow mask. +** +*******************************************************************************/ +BTA_API extern UINT8 bta_pan_co_init(UINT8 *q_level); + +/******************************************************************************* +** +** Function bta_pan_co_open +** +** Description This function is executed by PAN when a connection +** is opened. The phone can use this function to set +** up data paths or perform any required initialization. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_co_open(UINT16 handle, UINT8 app_id, tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role, BD_ADDR peer_addr); + +/******************************************************************************* +** +** Function bta_pan_co_close +** +** Description This function is called by PAN when a connection to a +** server is closed. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_co_close(UINT16 handle, UINT8 app_id); + +/******************************************************************************* +** +** 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. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_co_tx_path(UINT16 handle, UINT8 app_id); + +/******************************************************************************* +** +** Function bta_pan_co_rx_path +** +** Description This function is called by PAN to transfer data on the +** RX path; that is, data being sent from the phone to BTA. +** This function is used when the RX data path is configured +** to use the pull interface. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_co_rx_path(UINT16 handle, UINT8 app_id); + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern 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); + +/******************************************************************************* +** +** 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 void +** +*******************************************************************************/ +BTA_API extern 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); + + +/******************************************************************************* +** +** 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 +** +*******************************************************************************/ +BTA_API extern void bta_pan_co_rx_flow(UINT16 handle, UINT8 app_id, BOOLEAN enable); + + +/******************************************************************************* +** +** Function bta_pan_co_filt_ind +** +** Description protocol filter indication from peer device +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_co_pfilt_ind(UINT16 handle, BOOLEAN indication, tBTA_PAN_STATUS result, + UINT16 len, UINT8 *p_filters); + +/******************************************************************************* +** +** Function bta_pan_co_mfilt_ind +** +** Description multicast filter indication from peer device +** +** Returns void +** +*******************************************************************************/ +BTA_API extern void bta_pan_co_mfilt_ind(UINT16 handle, BOOLEAN indication, tBTA_PAN_STATUS result, + UINT16 len, UINT8 *p_filters); + +#endif /* BTA_PAN_CO_H */ + diff --git a/bta/include/bta_pbs_api.h b/bta/include/bta_pbs_api.h new file mode 100644 index 0000000..c3563c2 --- /dev/null +++ b/bta/include/bta_pbs_api.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 public interface file for the phone book access (PB) server + * subsystem of BTA, Broadcom's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ +#ifndef BTA_PB_API_H +#define BTA_PB_API_H + +#include "bta_api.h" +#include "btm_api.h" +#include "bta_sys.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/************************** +** Common Definitions +***************************/ + +/* Profile supported features */ +#define BTA_PBS_SUPF_DOWNLOAD 0x0001 +#define BTA_PBS_SURF_BROWSE 0x0002 + +/* Profile supported repositories */ +#define BTA_PBS_REPOSIT_LOCAL 0x01 /* Local PhoneBook */ +#define BTA_PBS_REPOSIT_SIM 0x02 /* SIM card PhoneBook */ + +#endif diff --git a/bta/include/bta_sys_ci.h b/bta/include/bta_sys_ci.h new file mode 100644 index 0000000..4818386 --- /dev/null +++ b/bta/include/bta_sys_ci.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * Copyright (C) 2010-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 interface file for system call-in functions. + * + ******************************************************************************/ +#ifndef BTA_SYS_CI_H +#define BTA_SYS_CI_H + +#include "bta_api.h" + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_sys_hw_ci_enabled +** +** Description This function must be called in response to function +** bta_sys_hw_co_enable(), when HW is indeed enabled +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void bta_sys_hw_ci_enabled(tBTA_SYS_HW_MODULE module ); + + +/******************************************************************************* +** +** Function bta_sys_hw_ci_disabled +** +** Description This function must be called in response to function +** bta_sys_hw_co_disable() when HW is really OFF +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void bta_sys_hw_ci_disabled( tBTA_SYS_HW_MODULE module ); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/bta/include/bta_sys_co.h b/bta/include/bta_sys_co.h new file mode 100644 index 0000000..92118a3 --- /dev/null +++ b/bta/include/bta_sys_co.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Copyright (C) 2010-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 interface file for system callout functions. + * + ******************************************************************************/ +#ifndef BTA_SYS_CO_H +#define BTA_SYS_CO_H + +#include "bta_sys.h" + + + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + + +/******************************************************************************* +** +** Function bta_sys_hw_co_enable +** +** Description This function is called by the stack to power up the HW +** +** Returns void +** +*******************************************************************************/ +BTA_API void bta_sys_hw_co_enable( tBTA_SYS_HW_MODULE module ); + +/******************************************************************************* +** +** Function bta_sys_hw_co_disable +** +** Description This function is called by the stack to power down the HW +** +** Returns void +** +*******************************************************************************/ +BTA_API void bta_sys_hw_co_disable( tBTA_SYS_HW_MODULE module ); + + +#endif diff --git a/bta/include/ptim.h b/bta/include/ptim.h new file mode 100644 index 0000000..80e50bd --- /dev/null +++ b/bta/include/ptim.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Protocol timer services. + * + ******************************************************************************/ +#ifndef PTIM_H +#define PTIM_H + +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +typedef struct +{ + TIMER_LIST_Q timer_queue; /* GKI timer queue */ + INT32 period; /* Timer period in milliseconds */ + UINT32 last_gki_ticks; /* GKI ticks since last time update called */ + UINT8 timer_id; /* GKI timer id */ +} tPTIM_CB; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function ptim_init +** +** Description Initialize a protocol timer service control block. +** +** Returns void +** +*******************************************************************************/ +extern void ptim_init(tPTIM_CB *p_cb, UINT16 period, UINT8 timer_id); + +/******************************************************************************* +** +** Function ptim_timer_update +** +** Description Update the protocol timer list and handle expired timers. +** +** Returns void +** +*******************************************************************************/ +extern void ptim_timer_update(tPTIM_CB *p_cb); + +/******************************************************************************* +** +** Function ptim_start_timer +** +** Description Start a protocol timer for the specified amount +** of time in milliseconds. +** +** Returns void +** +*******************************************************************************/ +extern void ptim_start_timer(tPTIM_CB *p_cb, TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout); + +/******************************************************************************* +** +** Function ptim_stop_timer +** +** Description Stop a protocol timer. +** +** Returns void +** +*******************************************************************************/ +extern void ptim_stop_timer(tPTIM_CB *p_cb, TIMER_LIST_ENT *p_tle); + +#ifdef __cplusplus +} +#endif + +#endif /* PTIM_H */ diff --git a/bta/include/utl.h b/bta/include/utl.h new file mode 100644 index 0000000..df08b5a --- /dev/null +++ b/bta/include/utl.h @@ -0,0 +1,169 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Basic utility functions. + * + ******************************************************************************/ +#ifndef UTL_H +#define UTL_H + +#include "data_types.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +/*** class of device settings ***/ +#define BTA_UTL_SET_COD_MAJOR_MINOR 0x01 +#define BTA_UTL_SET_COD_SERVICE_CLASS 0x02 /* only set the bits in the input */ +#define BTA_UTL_CLR_COD_SERVICE_CLASS 0x04 +#define BTA_UTL_SET_COD_ALL 0x08 /* take service class as the input (may clear some set bits!!) */ +#define BTA_UTL_INIT_COD 0x0a + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +/** for utl_set_device_class() **/ +typedef struct +{ + UINT8 minor; + UINT8 major; + UINT16 service; +} tBTA_UTL_COD; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function utl_str2int +** +** Description This utility function converts a character string to an +** integer. Acceptable values in string are 0-9. If invalid +** string or string value too large, -1 is returned. +** +** +** Returns Integer value or -1 on error. +** +*******************************************************************************/ +extern INT16 utl_str2int(const char *p_s); + +/******************************************************************************* +** +** Function utl_strucmp +** +** Description This utility function compares two strings in uppercase. +** String p_s must be uppercase. String p_t is converted to +** uppercase if lowercase. If p_s ends first, the substring +** match is counted as a match. +** +** +** Returns 0 if strings match, nonzero otherwise. +** +*******************************************************************************/ +extern int utl_strucmp(const char *p_s, const char *p_t); + +/******************************************************************************* +** +** Function utl_itoa +** +** Description This utility function converts a UINT16 to a string. The +** string is NULL-terminated. The length of the string is +** returned. +** +** +** Returns Length of string. +** +*******************************************************************************/ +extern UINT8 utl_itoa(UINT16 i, char *p_s); + +/******************************************************************************* +** +** Function utl_freebuf +** +** Description This function calls GKI_freebuf to free the buffer passed +** in, if buffer pointer is not NULL, and also initializes +** buffer pointer to NULL. +** +** +** Returns Nothing. +** +*******************************************************************************/ +extern void utl_freebuf(void **p); + +/******************************************************************************* +** +** Function utl_set_device_class +** +** Description This function updates the local Device Class. +** +** Parameters: +** p_cod - Pointer to the device class to set to +** +** cmd - the fields of the device class to update. +** BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major, minor class +** BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in the input +** BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in the input +** BTA_UTL_SET_COD_ALL - overwrite major, minor, set the bits in service class +** BTA_UTL_INIT_COD - overwrite major, minor, and service class +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +extern BOOLEAN utl_set_device_class(tBTA_UTL_COD *p_cod, UINT8 cmd); + +/******************************************************************************* +** +** Function utl_isintstr +** +** Description This utility function checks if the given string is an +** integer string or not +** +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +extern BOOLEAN utl_isintstr(const char *p_s); + +/******************************************************************************* +** +** Function utl_isdialstr +** +** Description This utility function checks if the given string contains +** only dial digits or not +** +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +extern BOOLEAN utl_isdialstr(const char *p_s); + +#ifdef __cplusplus +} +#endif + +#endif /* UTL_H */ diff --git a/bta/jv/bta_jv_act.c b/bta/jv/bta_jv_act.c new file mode 100644 index 0000000..77d18d9 --- /dev/null +++ b/bta/jv/bta_jv_act.c @@ -0,0 +1,2360 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains action functions for advanced audio. + * + ******************************************************************************/ + +#include <hardware/bluetooth.h> +#include <arpa/inet.h> + +#include "bt_types.h" +#include "gki.h" +#include "bd.h" +#include "utl.h" +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_jv_api.h" +#include "bta_jv_int.h" +#include "bta_jv_co.h" +#include "btm_api.h" +#include "btm_int.h" +#include "sdp_api.h" +#include "l2c_api.h" +#include "port_api.h" +#include <string.h> +#include "rfcdefs.h" +#include "avct_api.h" +#include "avdt_api.h" + + +#include <cutils/log.h> +#define info(fmt, ...) ALOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__) +#define debug(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__) +#define error(fmt, ...) ALOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__) +#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__) + + + +#define HDL2CB(handle) \ + UINT32 __hi = ((handle) & BTA_JV_RFC_HDL_MASK) - 1; \ + UINT32 __si = BTA_JV_RFC_HDL_TO_SIDX(handle); \ + tBTA_JV_RFC_CB *p_cb = &bta_jv_cb.rfc_cb[__hi]; \ + tBTA_JV_PCB *p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[__si] - 1] + +extern void uuid_to_string(bt_uuid_t *p_uuid, char *str); +static inline void logu(const char* title, const uint8_t * p_uuid) +{ + char uuids[128]; + uuid_to_string((bt_uuid_t*)p_uuid, uuids); + ALOGD("%s: %s", title, uuids); +} + + +static tBTA_JV_PCB * bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb); + +/******************************************************************************* +** +** Function bta_jv_get_local_device_addr_cback +** +** Description Callback from btm after local bdaddr is read +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_get_local_device_addr_cback(BD_ADDR bd_addr) +{ + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_LOCAL_ADDR_EVT, (tBTA_JV *)bd_addr, 0); +} + +/******************************************************************************* +** +** Function bta_jv_get_remote_device_name_cback +** +** Description Callback from btm after remote name is read +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_get_remote_device_name_cback(tBTM_REMOTE_DEV_NAME *p_name) +{ + tBTA_JV evt_data; + evt_data.p_name = p_name->remote_bd_name; + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_REMOTE_NAME_EVT, &evt_data, 0); +} + +/******************************************************************************* +** +** Function bta_jv_alloc_sec_id +** +** Description allocate a security id +** +** Returns +** +*******************************************************************************/ +UINT8 bta_jv_alloc_sec_id(void) +{ + UINT8 ret = 0; + int i; + for(i=0; i<BTA_JV_NUM_SERVICE_ID; i++) + { + if(0 == bta_jv_cb.sec_id[i]) + { + bta_jv_cb.sec_id[i] = BTA_JV_FIRST_SERVICE_ID + i; + ret = bta_jv_cb.sec_id[i]; + break; + } + } + return ret; + +} + +/******************************************************************************* +** +** Function bta_jv_free_sec_id +** +** Description free the given security id +** +** Returns +** +*******************************************************************************/ +static void bta_jv_free_sec_id(UINT8 *p_sec_id) +{ + UINT8 sec_id = *p_sec_id; + *p_sec_id = 0; + if(sec_id >= BTA_JV_FIRST_SERVICE_ID && sec_id <= BTA_JV_LAST_SERVICE_ID) + { + BTM_SecClrService(sec_id); + bta_jv_cb.sec_id[sec_id - BTA_JV_FIRST_SERVICE_ID] = 0; + } +} + +/******************************************************************************* +** +** Function bta_jv_alloc_rfc_cb +** +** Description allocate a control block for the given port handle +** +** Returns +** +*******************************************************************************/ +tBTA_JV_RFC_CB * bta_jv_alloc_rfc_cb(UINT16 port_handle, tBTA_JV_PCB **pp_pcb) +{ + tBTA_JV_RFC_CB *p_cb = NULL; + tBTA_JV_PCB *p_pcb; + int i; + for(i=0; i<BTA_JV_MAX_RFC_CONN; i++) + { + if(0 == bta_jv_cb.rfc_cb[i].handle ) + { + p_cb = &bta_jv_cb.rfc_cb[i]; + p_cb->handle = i + 1; + p_cb->max_sess = 1; + p_cb->rfc_hdl[0] = port_handle; + APPL_TRACE_DEBUG2( "bta_jv_alloc_rfc_cb port_handle:%d handle:%d", + port_handle, p_cb->handle); + p_pcb = &bta_jv_cb.port_cb[port_handle - 1]; + p_pcb->handle = p_cb->handle; + p_pcb->port_handle = port_handle; + *pp_pcb = p_pcb; + break; + } + } + return p_cb; +} + +/******************************************************************************* +** +** Function bta_jv_rfc_port_to_pcb +** +** Description find the port control block associated with the given port handle +** +** Returns +** +*******************************************************************************/ +tBTA_JV_PCB * bta_jv_rfc_port_to_pcb(UINT16 port_handle) +{ + tBTA_JV_PCB *p_pcb = NULL; + + if ((port_handle > 0) && (port_handle <= MAX_RFC_PORTS) && bta_jv_cb.port_cb[port_handle - 1].handle) + { + p_pcb = &bta_jv_cb.port_cb[port_handle - 1]; + } + + return p_pcb; +} + +/******************************************************************************* +** +** Function bta_jv_rfc_port_to_cb +** +** Description find the RFCOMM control block associated with the given port handle +** +** Returns +** +*******************************************************************************/ +tBTA_JV_RFC_CB * bta_jv_rfc_port_to_cb(UINT16 port_handle) +{ + tBTA_JV_RFC_CB *p_cb = NULL; + UINT32 handle; + + if ((port_handle > 0) && (port_handle <= MAX_RFC_PORTS) && bta_jv_cb.port_cb[port_handle - 1].handle) + { + handle = bta_jv_cb.port_cb[port_handle - 1].handle; + handle &= BTA_JV_RFC_HDL_MASK; + if (handle) + p_cb = &bta_jv_cb.rfc_cb[handle - 1]; + } + return p_cb; +} + +/******************************************************************************* +** +** Function bta_jv_free_rfc_pcb +** +** Description free the given port control block +** +** Returns +** +*******************************************************************************/ +tBTA_JV_STATUS bta_jv_free_rfc_pcb(tBTA_JV_PCB *p_pcb) +{ + tBTA_JV_STATUS status = BTA_JV_SUCCESS; + BOOLEAN remove = FALSE; + BOOLEAN is_server = TRUE; + UINT16 port_handle; + + APPL_TRACE_DEBUG2( "bta_jv_free_rfc_pcb handle:%d s:%d", p_pcb->port_handle, p_pcb->state); + + if (p_pcb->port_handle) + { + if(BTA_JV_ST_NONE != p_pcb->state) + { + remove = TRUE; + if(p_pcb->state <= BTA_JV_ST_CL_MAX) + is_server = FALSE; + port_handle = p_pcb->port_handle; + } + p_pcb->port_handle = 0; + p_pcb->state = BTA_JV_ST_NONE; + + //Initialize congestion flags + p_pcb->cong = FALSE; + + if(remove) + { + if(is_server) + { + if(RFCOMM_RemoveServer(port_handle) != PORT_SUCCESS) + status = BTA_JV_FAILURE; + } + else + { + if(RFCOMM_RemoveConnection(port_handle) != PORT_SUCCESS) + status = BTA_JV_FAILURE; + } + } + } + return status; +} + +/******************************************************************************* +** +** Function bta_jv_free_rfc_cb +** +** Description free the given RFCOMM control block +** +** Returns +** +*******************************************************************************/ +tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB *p_cb) +{ + tBTA_JV_STATUS status = BTA_JV_SUCCESS; + UINT8 i; + APPL_TRACE_DEBUG1( "bta_jv_free_rfc_cb max_sess:%d", p_cb->max_sess); + for (i=0; i<p_cb->max_sess; i++) + { + APPL_TRACE_DEBUG2( "[%d]: port=%d", i, p_cb->rfc_hdl[i]); + if (p_cb->rfc_hdl[i]) + bta_jv_free_rfc_pcb (&bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1]); + } + + p_cb->scn = 0; + bta_jv_free_sec_id(&p_cb->sec_id); + p_cb->p_cback = NULL; + p_cb->handle = 0; + + return status; +} +static tBTA_JV_STATUS bta_jv_free_rfc_listen_cb(tBTA_JV_RFC_CB *p_cb) +{ + tBTA_JV_STATUS status = BTA_JV_SUCCESS; + UINT8 i; + debug( "max_sess:%d", p_cb->max_sess); + for (i=0; i<p_cb->max_sess; i++) + { + APPL_TRACE_DEBUG2( "[%d]: port=%d", i, p_cb->rfc_hdl[i]); + if (p_cb->rfc_hdl[i]) + { + tBTA_JV_PCB *p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1]; + if(p_pcb->state == BTA_JV_ST_SR_LISTEN) + { + debug( "free listen pcb: scn:%d, ueser_data:%d", p_cb->scn, (int)p_pcb->user_data); + p_pcb->user_data = 0; + bta_jv_free_rfc_pcb (p_pcb); + p_cb->max_sess = 1; + break; + } + } + } + //p_cb->scn = 0; + bta_jv_free_sec_id(&p_cb->sec_id); + //p_cb->p_cback = NULL; + //p_cb->handle = 0; + return status; +} + +/******************************************************************************* +** +** Function bta_jv_free_l2c_cb +** +** Description free the given L2CAP control block +** +** Returns +** +*******************************************************************************/ +tBTA_JV_STATUS bta_jv_free_l2c_cb(tBTA_JV_L2C_CB *p_cb) +{ +#if 0 + tBTA_JV_STATUS status = BTA_JV_SUCCESS; + + if(BTA_JV_ST_NONE != p_cb->state) + { +#if SDP_FOR_JV_INCLUDED == TRUE + if(BTA_JV_L2C_FOR_SDP_HDL == p_cb->handle) + { + bta_jv_cb.sdp_data_size = 0; + if(SDP_ConnClose(bta_jv_cb.sdp_for_jv)) + { + bta_jv_cb.sdp_for_jv = 0; + } + else + status = BTA_JV_FAILURE; + } + else +#endif + if(GAP_ConnClose(p_cb->handle) != BT_PASS) + status = BTA_JV_FAILURE; + } + p_cb->psm = 0; + p_cb->state = BTA_JV_ST_NONE; + bta_jv_free_sec_id(&p_cb->sec_id); + p_cb->p_cback = NULL; + return status; +#endif + return 0; +} + +/******************************************************************************* +** +** Function bta_jv_alloc_sdp_id +** +** Description allocate a SDP id for the given SDP record handle +** +** Returns +** +*******************************************************************************/ +UINT32 bta_jv_alloc_sdp_id(UINT32 sdp_handle) +{ + int j; + UINT32 id = 0; + + /* find a free entry */ + for (j = 0; j < BTA_JV_MAX_SDP_REC; j++) + { + if (bta_jv_cb.sdp_handle[j] == 0) + { + bta_jv_cb.sdp_handle[j] = sdp_handle; + id = (UINT32)(j + 1); + break; + } + } + /* the SDP record handle reported is the (index + 1) to control block */ + return id; +} + +/******************************************************************************* +** +** Function bta_jv_free_sdp_id +** +** Description free the sdp id +** +** Returns +** +*******************************************************************************/ +void bta_jv_free_sdp_id(UINT32 sdp_id) +{ + if(sdp_id > 0 && sdp_id <= BTA_JV_MAX_SDP_REC) + { + bta_jv_cb.sdp_handle[sdp_id - 1] = 0; + } +} + +/******************************************************************************* +** +** Function bta_jv_get_sdp_handle +** +** Description find the SDP handle associated with the given sdp id +** +** Returns +** +*******************************************************************************/ +UINT32 bta_jv_get_sdp_handle(UINT32 sdp_id) +{ + UINT32 sdp_handle = 0; + + if(sdp_id > 0 && sdp_id <= BTA_JV_MAX_SDP_REC) + { + sdp_handle = bta_jv_cb.sdp_handle[sdp_id - 1]; + } + return sdp_handle; +} + +/******************************************************************************* +** +** Function bta_jv_check_psm +** +** Description for now use only the legal PSM per JSR82 spec +** +** Returns TRUE, if allowed +** +*******************************************************************************/ +BOOLEAN bta_jv_check_psm(UINT16 psm) +{ + BOOLEAN ret = FALSE; + + if(L2C_IS_VALID_PSM(psm) ) + { + if(psm < 0x1001) + { + /* see if this is defined by spec */ + switch(psm) + { + case SDP_PSM: /* 1 */ + case BT_PSM_RFCOMM: /* 3 */ + /* do not allow java app to use these 2 PSMs */ + break; + + case TCS_PSM_INTERCOM: /* 5 */ + case TCS_PSM_CORDLESS: /* 7 */ + if( FALSE == bta_sys_is_register(BTA_ID_CT) && + FALSE == bta_sys_is_register(BTA_ID_CG) ) + ret = TRUE; + break; + + case BT_PSM_BNEP: /* F */ + if(FALSE == bta_sys_is_register(BTA_ID_PAN)) + ret = TRUE; + break; + + case HID_PSM_CONTROL: /* 0x11 */ + case HID_PSM_INTERRUPT: /* 0x13 */ + //FIX: allow HID Device and HID Host to coexist + if( FALSE == bta_sys_is_register(BTA_ID_HD) || + FALSE == bta_sys_is_register(BTA_ID_HH) ) + ret = TRUE; + break; + + case AVCT_PSM: /* 0x17 */ + case AVDT_PSM: /* 0x19 */ + if ((FALSE == bta_sys_is_register(BTA_ID_AV)) && + (FALSE == bta_sys_is_register(BTA_ID_AVK))) + ret = TRUE; + break; + + default: + ret = TRUE; + break; + } + } + else + ret = TRUE; + } + return ret; + +} + +/******************************************************************************* +** +** Function bta_jv_enable +** +** Description Initialises the JAVA I/F +** +** Returns void +** +*******************************************************************************/ +void bta_jv_enable(tBTA_JV_MSG *p_data) +{ + tBTA_JV_STATUS status = BTA_JV_SUCCESS; + bta_jv_cb.p_dm_cback = p_data->enable.p_cback; + bta_jv_cb.p_dm_cback(BTA_JV_ENABLE_EVT, (tBTA_JV *)&status, 0); +} + +/******************************************************************************* +** +** Function bta_jv_disable +** +** Description Disables the BT device manager +** free the resources used by java +** +** Returns void +** +*******************************************************************************/ +void bta_jv_disable (tBTA_JV_MSG *p_data) +{ + int i; + + bta_jv_cb.p_dm_cback = NULL; + /* delete the SDP records created by java apps */ + for(i=0; i<BTA_JV_MAX_SDP_REC; i++) + { + if(bta_jv_cb.sdp_handle[i]) + { + APPL_TRACE_DEBUG1( "delete SDP record: %d", bta_jv_cb.sdp_handle[i]); + SDP_DeleteRecord(bta_jv_cb.sdp_handle[i]); + bta_jv_cb.sdp_handle[i] = 0; + } + } + + /* free the SCNs allocated by java apps */ + for(i=0; i<BTA_JV_MAX_SCN; i++) + { + if(bta_jv_cb.scn[i]) + { + APPL_TRACE_DEBUG1( "free scn: %d", (i+1)); + BTM_FreeSCN((UINT8)(i+1)); + bta_jv_cb.scn[i] = FALSE; + } + } + + /* disconnect L2CAP connections */ + for(i=0; i<BTA_JV_MAX_L2C_CONN; i++) + { + bta_jv_free_l2c_cb(&bta_jv_cb.l2c_cb[i]); + } + + /* disconnect RFCOMM connections */ + for(i=0; i<BTA_JV_MAX_RFC_CONN; i++) + { + bta_jv_free_rfc_cb(&bta_jv_cb.rfc_cb[i]); + } + + /* free the service records allocated by java apps */ + for(i=0; i<BTA_JV_NUM_SERVICE_ID; i++) + { + if(bta_jv_cb.sec_id[i]) + { + BTM_SecClrService(bta_jv_cb.sec_id[i]); + bta_jv_cb.sec_id[i] = 0; + } + } +} + +/******************************************************************************* +** +** Function bta_jv_set_discoverability +** +** Description Sets discoverability +** +** Returns void +** +*******************************************************************************/ +void bta_jv_set_discoverability (tBTA_JV_MSG *p_data) +{ + tBTA_JV evt_data; + + evt_data.set_discover.status = BTA_JV_FAILURE; + /* initialize the default value for the event as the current mode */ + evt_data.set_discover.disc_mode = BTM_ReadDiscoverability(NULL, NULL); + + if(BTM_SUCCESS == BTM_SetDiscoverability((UINT8)p_data->set_discoverability.disc_mode, 0, 0)) + { + evt_data.set_discover.status = BTA_JV_SUCCESS; + /* update the mode, after BTM_SetDiscoverability() is successful */ + evt_data.set_discover.disc_mode = p_data->set_discoverability.disc_mode; + } + + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_SET_DISCOVER_EVT, &evt_data, 0); +} + +/******************************************************************************* +** +** Function bta_jv_get_local_device_addr +** +** Description Reads the local Bluetooth device address +** +** Returns void +** +*******************************************************************************/ +void bta_jv_get_local_device_addr(tBTA_JV_MSG *p_data) +{ + BTM_ReadLocalDeviceAddr((tBTM_CMPL_CB *)bta_jv_get_local_device_addr_cback); +} + +/******************************************************************************* +** +** Function bta_jv_get_local_device_name +** +** Description Reads the local Bluetooth device name +** +** Returns void +** +*******************************************************************************/ +void bta_jv_get_local_device_name(tBTA_JV_MSG *p_data) +{ + tBTA_JV evt_data; + char *name; + + BTM_ReadLocalDeviceName(&name); + evt_data.p_name = (UINT8*)name; + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_LOCAL_NAME_EVT, &evt_data, 0); +} + +/******************************************************************************* +** +** Function bta_jv_get_remote_device_name +** +** Description Reads the local Bluetooth device name +** +** Returns void +** +*******************************************************************************/ +void bta_jv_get_remote_device_name(tBTA_JV_MSG *p_data) +{ + + BTM_ReadRemoteDeviceName(p_data->get_rmt_name.bd_addr, + (tBTM_CMPL_CB *)bta_jv_get_remote_device_name_cback); +} + +/******************************************************************************* +** +** Function bta_jv_set_service_class +** +** Description update the service class field of device class +** +** Returns void +** +*******************************************************************************/ +void bta_jv_set_service_class (tBTA_JV_MSG *p_data) +{ + tBTA_UTL_COD cod; + + /* set class of device */ + /* BTA_JvSetServiceClass(UINT32 service) assumes that the service class passed to the API function as defined in the assigned number page. + For example: the object transfer bit is bit 20 of the 24-bit Class of device; the value of this bit is 0x00100000 (value 1) + Our btm_api.h defines this bit as #define BTM_COD_SERVICE_OBJ_TRANSFER 0x1000 // (value 2) + This reflects that the service class defined at btm is UINT16, which starts at bit 8 of the 24 bit Class of Device + The following statement converts from (value 1) into (value 2) */ + cod.service = (p_data->set_service.service >> 8); + utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); +} + +/******************************************************************************* +** +** Function bta_jv_sec_cback +** +** Description callback function to handle set encryption complete event +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_sec_cback (BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result) +{ + tBTA_JV_SET_ENCRYPTION set_enc; + if(bta_jv_cb.p_dm_cback) + { + bdcpy(set_enc.bd_addr, bd_addr); + set_enc.status = result; + if (result > BTA_JV_BUSY) + set_enc.status = BTA_JV_FAILURE; + bta_jv_cb.p_dm_cback(BTA_JV_SET_ENCRYPTION_EVT, (tBTA_JV *)&set_enc, 0); + } +} + +/******************************************************************************* +** +** Function bta_jv_set_encryption +** +** Description Reads the local Bluetooth device name +** +** Returns void +** +*******************************************************************************/ +void bta_jv_set_encryption(tBTA_JV_MSG *p_data) +{ + BTM_SetEncryption(p_data->set_encrypt.bd_addr, bta_jv_sec_cback, NULL); +} + +/******************************************************************************* +** +** Function bta_jv_get_scn +** +** Description obtain a free SCN +** +** Returns void +** +*******************************************************************************/ +void bta_jv_get_scn(tBTA_JV_MSG *p_data) +{ +#if 0 + UINT8 scn; + scn = BTM_AllocateSCN(); + if(scn) + bta_jv_cb.scn[scn-1] = TRUE; + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, (tBTA_JV *)&scn); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_free_scn +** +** Description free a SCN +** +** Returns void +** +*******************************************************************************/ +void bta_jv_free_scn(tBTA_JV_MSG *p_data) +{ + UINT8 scn = p_data->free_scn.scn; + + if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn-1]) + { + /* this scn is used by JV */ + bta_jv_cb.scn[scn-1] = FALSE; + BTM_FreeSCN(scn); + } +} +static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u) +{ + static uint8_t bt_base_uuid[] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }; + + logu("in, uuid:", u); + debug("uuid len:%d", u->len); + if(u->len == 16) + { + if(memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) == 0) + { + tBT_UUID su; + memset(&su, 0, sizeof(su)); + if(u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0) + { + su.len = 2; + uint16_t u16; + memcpy(&u16, &u->uu.uuid128[2], sizeof(u16)); + su.uu.uuid16 = ntohs(u16); + debug("shorten to 16 bits uuid: %x", su.uu.uuid16); + } + else + { + su.len = 4; + uint32_t u32; + memcpy(&u32, &u->uu.uuid128[0], sizeof(u32)); + su.uu.uuid32 = ntohl(u32); + debug("shorten to 32 bits uuid: %x", su.uu.uuid32); + } + return su; + } + } + debug("cannot shorten none-reserved 128 bits uuid"); + return *u; +} + +/******************************************************************************* +** +** Function bta_jv_start_discovery_cback +** +** Description Callback for Start Discovery +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_start_discovery_cback(UINT16 result, void * user_data) +{ + tBTA_JV_STATUS status; + UINT8 old_sdp_act = bta_jv_cb.sdp_active; + + debug( "bta_jv_start_discovery_cback res: 0x%x", result); + + bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE; + if(bta_jv_cb.p_dm_cback) + { + if (old_sdp_act == BTA_JV_SDP_ACT_CANCEL) + { + debug("BTA_JV_SDP_ACT_CANCEL"); + status = BTA_JV_SUCCESS; + bta_jv_cb.p_dm_cback(BTA_JV_CANCEL_DISCVRY_EVT, (tBTA_JV *)&status, user_data); + } + else + { + tBTA_JV_DISCOVERY_COMP dcomp; + dcomp.scn = 0; + status = BTA_JV_FAILURE; + if (result == SDP_SUCCESS || result == SDP_DB_FULL) + { + tSDP_DISC_REC *p_sdp_rec = NULL; + tSDP_PROTOCOL_ELEM pe; + logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128); + tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid); + logu("shorten uuid:", su.uu.uuid128); + p_sdp_rec = SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec); + debug("p_sdp_rec:%p", p_sdp_rec); + if(p_sdp_rec && SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) + { + dcomp.scn = (UINT8) pe.params[0]; + status = BTA_JV_SUCCESS; + } + } + + dcomp.status = status; + bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&dcomp, user_data); + } + //free sdp db + //utl_freebuf(&(p_bta_jv_cfg->p_sdp_db)); + } +} + +/******************************************************************************* +** +** Function bta_jv_start_discovery +** +** Description Discovers services on a remote device +** +** Returns void +** +*******************************************************************************/ +void bta_jv_start_discovery(tBTA_JV_MSG *p_data) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + debug("in, sdp_active:%d", bta_jv_cb.sdp_active); + if (bta_jv_cb.sdp_active != BTA_JV_SDP_ACT_NONE) + { + /* SDP is still in progress */ + status = BTA_JV_BUSY; + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&status, p_data->start_discovery.user_data); + return; + } +/* + if(p_data->start_discovery.num_uuid == 0) + { + p_data->start_discovery.num_uuid = 1; + p_data->start_discovery.uuid_list[0].len = 2; + p_data->start_discovery.uuid_list[0].uu.uuid16 = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + } +*/ + /* init the database/set up the filter */ + debug("call SDP_InitDiscoveryDb, p_data->start_discovery.num_uuid:%d", + p_data->start_discovery.num_uuid); + SDP_InitDiscoveryDb (p_bta_jv_cfg->p_sdp_db, p_bta_jv_cfg->sdp_db_size, + p_data->start_discovery.num_uuid, p_data->start_discovery.uuid_list, 0, NULL); + + /* tell SDP to keep the raw data */ + p_bta_jv_cfg->p_sdp_db->raw_data = p_bta_jv_cfg->p_sdp_raw_data; + p_bta_jv_cfg->p_sdp_db->raw_size = p_bta_jv_cfg->sdp_raw_size; + + bta_jv_cb.p_sel_raw_data = 0; + bta_jv_cb.uuid = p_data->start_discovery.uuid_list[0]; + + bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_YES; + if (!SDP_ServiceSearchAttributeRequest2(p_data->start_discovery.bd_addr, + p_bta_jv_cfg->p_sdp_db, + bta_jv_start_discovery_cback, p_data->start_discovery.user_data)) + { + bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE; + /* failed to start SDP. report the failure right away */ + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV *)&status, p_data->start_discovery.user_data); + } + /* + else report the result when the cback is called + */ +} + +/******************************************************************************* +** +** Function bta_jv_cancel_discovery +** +** Description Cancels an active discovery +** +** Returns void +** +*******************************************************************************/ +void bta_jv_cancel_discovery(tBTA_JV_MSG *p_data) +{ + tBTA_JV_STATUS status = BTA_JV_SUCCESS; + if (bta_jv_cb.sdp_active == BTA_JV_SDP_ACT_YES) + { + if (SDP_CancelServiceSearch (p_bta_jv_cfg->p_sdp_db)) + { + bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_CANCEL; + return; + } + } + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_CANCEL_DISCVRY_EVT, (tBTA_JV *)&status, p_data->cancel_discovery.user_data); +} + +/******************************************************************************* +** +** Function bta_jv_get_services_length +** +** Description Obtain the length of each record in the SDP DB. +** +** Returns void +** +*******************************************************************************/ +void bta_jv_get_services_length(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_SERVICES_LEN evt_data; + UINT8 *p, *np, *op, type; + UINT32 raw_used, raw_cur; + UINT32 len; + + evt_data.num_services = -1; + evt_data.p_services_len = p_data->get_services_length.p_services_len; + if(p_bta_jv_cfg->p_sdp_db->p_first_rec) + { + /* the database is valid */ + evt_data.num_services = 0; + p = p_bta_jv_cfg->p_sdp_db->raw_data; + raw_used = p_bta_jv_cfg->p_sdp_db->raw_used; + while(raw_used && p) + { + op = p; + type = *p++; + np = sdpu_get_len_from_type(p, type, &len); + p = np + len; + raw_cur = p - op; + if(raw_used >= raw_cur) + { + raw_used -= raw_cur; + } + else + { + /* error. can not continue */ + break; + } + if(p_data->get_services_length.inc_hdr) + { + evt_data.p_services_len[evt_data.num_services++] = len + np - op; + } + else + { + evt_data.p_services_len[evt_data.num_services++] = len; + } + } /* end of while */ + } + + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_SERVICES_LEN_EVT, (tBTA_JV *)&evt_data); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_service_select +** +** Description Obtain the length of given UUID in the SDP DB. +** +** Returns void +** +*******************************************************************************/ +void bta_jv_service_select(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_SERVICE_SEL serv_sel; + tSDP_DISC_REC *p_rec, *p_tmp; + UINT8 *p, *np, *op, type; + UINT32 raw_used, raw_cur; + UINT32 len; + + serv_sel.service_len = 0; + bta_jv_cb.p_sel_raw_data = 0; + p_rec = SDP_FindServiceInDb (p_bta_jv_cfg->p_sdp_db, p_data->service_select.uuid, NULL); + if(p_rec) + { + /* found the record in the database */ + /* the database must be valid */ + p = p_bta_jv_cfg->p_sdp_db->raw_data; + raw_used = p_bta_jv_cfg->p_sdp_db->raw_used; + p_tmp = p_bta_jv_cfg->p_sdp_db->p_first_rec; + while(raw_used && p && p_tmp) + { + op = p; + type = *p++; + np = sdpu_get_len_from_type(p, type, &len); + if(p_tmp == p_rec) + { + bta_jv_cb.p_sel_raw_data = op; + bta_jv_cb.sel_len = len; + serv_sel.service_len = len; + bdcpy(serv_sel.bd_addr, p_rec->remote_bd_addr); + APPL_TRACE_DEBUG1( "bta_jv_service_select found uuid: 0x%x", + p_data->service_select.uuid); + break; + } + p = np + len; + raw_cur = p - op; + if(raw_used >= raw_cur) + { + raw_used -= raw_cur; + } + else + { + /* error. can not continue */ + break; + } + p_tmp = p_tmp->p_next_rec; + } /* end of while */ + } + APPL_TRACE_DEBUG1( "service_len: %d", serv_sel.service_len); + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_SERVICE_SEL_EVT, (tBTA_JV *)&serv_sel); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_create_record +** +** Description Create an SDP record with the given attributes +** +** Returns void +** +*******************************************************************************/ +void bta_jv_create_record(tBTA_JV_MSG *p_data) +{ + tBTA_JV_API_CREATE_RECORD *cr = &(p_data->create_record); + tBTA_JV_CREATE_RECORD evt_data; + evt_data.status = BTA_JV_SUCCESS; + if(bta_jv_cb.p_dm_cback) + //callback user immediately to create his own sdp record in stack thread context + bta_jv_cb.p_dm_cback(BTA_JV_CREATE_RECORD_EVT, (tBTA_JV *)&evt_data, cr->user_data); +} + +/******************************************************************************* +** +** Function bta_jv_update_record +** +** Description Update an SDP record with the given attributes +** +** Returns void +** +*******************************************************************************/ +void bta_jv_update_record(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_API_UPDATE_RECORD *ur = &(p_data->update_record); + tBTA_JV_UPDATE_RECORD evt_data; + UINT32 handle; + INT32 i; + UINT8 *ptr; + UINT8 *next_ptr; + UINT8 *end; + UINT32 len; + UINT8 type; + + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = ur->handle; + + handle = bta_jv_get_sdp_handle(ur->handle); + + if(handle) + { + /* this is a record created by JV */ + for (i = 0; i < ur->array_len; i++) + { + ptr = ur->p_values[i]; + end = ptr + ur->p_value_sizes[i]; + + while (ptr < end) + { + type = *ptr; + next_ptr = sdpu_get_len_from_type(ptr + 1, *ptr, &len); + + if(ATTR_ID_SERVICE_RECORD_HDL != ur->p_ids[i]) + { + if (!SDP_AddAttribute(handle, ur->p_ids[i], (UINT8)((type >> 3) & 0x1f), + len, next_ptr)) + { + /* failed on updating attributes. */ + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_UPDATE_RECORD_EVT, (tBTA_JV *)&evt_data); + return; + } + } + + ptr = next_ptr + len; + } /* end of while */ + } /* end of for */ + evt_data.status = BTA_JV_SUCCESS; + } + + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_UPDATE_RECORD_EVT, (tBTA_JV *)&evt_data); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_add_attribute +** +** Description Add an attribute to an SDP record +** +** Returns void +** +*******************************************************************************/ +void bta_jv_add_attribute(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_API_ADD_ATTRIBUTE *aa = &(p_data->add_attr); + tBTA_JV_ADD_ATTR evt_data; + UINT32 handle; + UINT8 type; + UINT32 len; + UINT8 *ptr; + UINT8 *next_ptr; + + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = aa->handle; + handle = bta_jv_get_sdp_handle(aa->handle); + + if(handle) + { + /* this is a record created by JV */ + ptr = aa->p_value; + type = *ptr; + next_ptr = sdpu_get_len_from_type(ptr + 1, *ptr, &len); + APPL_TRACE_DEBUG3( "bta_jv_add_attribute: ptr chg:%d len:%d, size:%d", + (next_ptr - ptr), len, aa->value_size); + if(ATTR_ID_SERVICE_RECORD_HDL != aa->attr_id && /* do not allow the SDP record handle to be updated */ + ((INT32)(next_ptr - ptr + len) == aa->value_size) && /* double check data size */ + SDP_AddAttribute(handle, aa->attr_id, (UINT8)((type >> 3) & 0x1f), + len, next_ptr)) + { + evt_data.status = BTA_JV_SUCCESS; + } + } + + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_ADD_ATTR_EVT, (tBTA_JV *)&evt_data); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_delete_attribute +** +** Description Delete an attribute from the given SDP record +** +** Returns void +** +*******************************************************************************/ +void bta_jv_delete_attribute(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_API_ADD_ATTRIBUTE *da = &(p_data->add_attr); + tBTA_JV_DELETE_ATTR evt_data; + UINT32 handle; + + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = da->handle; + handle = bta_jv_get_sdp_handle(da->handle); + + if(handle) + { + /* this is a record created by JV */ + if(SDP_DeleteAttribute(handle, da->attr_id)) + evt_data.status = BTA_JV_SUCCESS; + } + + if(bta_jv_cb.p_dm_cback) + bta_jv_cb.p_dm_cback(BTA_JV_DELETE_ATTR_EVT, (tBTA_JV *)&evt_data); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_delete_record +** +** Description Delete an SDP record +** +** +** Returns void +** +*******************************************************************************/ +void bta_jv_delete_record(tBTA_JV_MSG *p_data) +{ + tBTA_JV_API_ADD_ATTRIBUTE *dr = &(p_data->add_attr); + UINT32 handle; + + handle = bta_jv_get_sdp_handle(dr->handle); + + if(handle) + { + /* this is a record created by JV */ + SDP_DeleteRecord(handle); + bta_jv_free_sdp_id(dr->handle); + } +} + +/******************************************************************************* +** +** Function bta_jv_l2cap_client_cback +** +** Description handles the l2cap client events +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_l2cap_client_cback(UINT16 gap_handle, UINT16 event) +{ +#if 0 + tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[gap_handle]; + tBTA_JV evt_data; + + if(gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) + return; + + APPL_TRACE_DEBUG2( "bta_jv_l2cap_client_cback: %d evt:x%x", + gap_handle, event); + evt_data.l2c_open.status = BTA_JV_SUCCESS; + evt_data.l2c_open.handle = gap_handle; + switch (event) + { + case GAP_EVT_CONN_OPENED: + bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle)); + evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle); + p_cb->state = BTA_JV_ST_CL_OPEN; + p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data); + break; + + case GAP_EVT_CONN_CLOSED: + p_cb->state = BTA_JV_ST_NONE; + bta_jv_free_sec_id(&p_cb->sec_id); + evt_data.l2c_close.async = TRUE; + p_cb->p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data); + p_cb->p_cback = NULL; + break; + + case GAP_EVT_CONN_DATA_AVAIL: + evt_data.handle = gap_handle; + p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data); + break; + + case GAP_EVT_CONN_CONGESTED: + case GAP_EVT_CONN_UNCONGESTED: + p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE; + evt_data.l2c_cong.cong = p_cb->cong; + p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data); + break; + + default: + break; + } +#endif +} + +#if SDP_FOR_JV_INCLUDED == TRUE +/******************************************************************************* +** +** Function bta_jv_sdp_res_cback +** +** Description Callback for Start Discovery +** +** Returns void +** +*******************************************************************************/ +void bta_jv_sdp_res_cback (UINT16 event, tSDP_DATA *p_data) +{ + tBTA_JV evt_data; + tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[BTA_JV_L2C_FOR_SDP_HDL]; + + APPL_TRACE_DEBUG2( "bta_jv_sdp_res_cback: %d evt:x%x", + bta_jv_cb.sdp_for_jv, event); + + if(!bta_jv_cb.sdp_for_jv) + return; + + evt_data.l2c_open.status = BTA_JV_SUCCESS; + evt_data.l2c_open.handle = BTA_JV_L2C_FOR_SDP_HDL; + + switch(event) + { + case SDP_EVT_OPEN: + bdcpy(evt_data.l2c_open.rem_bda, p_data->open.peer_addr); + evt_data.l2c_open.tx_mtu = p_data->open.peer_mtu; + p_cb->state = BTA_JV_ST_SR_OPEN; + p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data); + break; + case SDP_EVT_DATA_IND: + evt_data.handle = BTA_JV_L2C_FOR_SDP_HDL; + memcpy(p_bta_jv_cfg->p_sdp_raw_data, p_data->data.p_data, p_data->data.data_len); + APPL_TRACE_DEBUG2( "data size: %d/%d ", bta_jv_cb.sdp_data_size, p_data->data.data_len); + bta_jv_cb.sdp_data_size = p_data->data.data_len; + p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data); + break; + } +} + +/******************************************************************************* +** +** Function bta_jv_sdp_cback +** +** Description Callback for Start Discovery +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_sdp_cback(UINT16 result) +{ + tBTA_JV_L2CAP_CLOSE close; + tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[BTA_JV_L2C_FOR_SDP_HDL]; + APPL_TRACE_DEBUG1( "bta_jv_sdp_cback: result:x%x", result); + + if(p_cb->p_cback) + { + close.handle = BTA_JV_L2C_FOR_SDP_HDL; + close.async = FALSE; + close.status = BTA_JV_SUCCESS; + bta_jv_free_sec_id(&p_cb->sec_id); + p_cb->p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&close); + } + + bta_jv_cb.sdp_for_jv = 0; + p_cb->p_cback = NULL; + +} +#endif + +/******************************************************************************* +** +** Function bta_jv_l2cap_connect +** +** Description makes an l2cap client connection +** +** Returns void +** +*******************************************************************************/ +void bta_jv_l2cap_connect(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_L2C_CB *p_cb; + tBTA_JV_L2CAP_CL_INIT evt_data; + UINT16 handle=GAP_INVALID_HANDLE; + UINT8 sec_id; + tL2CAP_CFG_INFO cfg; + tBTA_JV_API_L2CAP_CONNECT *cc = &(p_data->l2cap_connect); + + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = cc->rx_mtu; + /* TODO: DM role manager + L2CA_SetDesireRole(cc->role); + */ + + sec_id = bta_jv_alloc_sec_id(); + evt_data.sec_id = sec_id; + evt_data.status = BTA_JV_FAILURE; + if (sec_id) + { +#if SDP_FOR_JV_INCLUDED == TRUE + if(SDP_PSM == cc->remote_psm && 0 == bta_jv_cb.sdp_for_jv) + { + bta_jv_cb.sdp_for_jv = SDP_ConnOpen(cc->peer_bd_addr, + bta_jv_sdp_res_cback, + bta_jv_sdp_cback); + if(bta_jv_cb.sdp_for_jv) + { + bta_jv_cb.sdp_data_size = 0; + handle = BTA_JV_L2C_FOR_SDP_HDL; + evt_data.status = BTA_JV_SUCCESS; + } + } + else +#endif + if(bta_jv_check_psm(cc->remote_psm)) /* allowed */ + { + if( (handle = GAP_ConnOpen("", sec_id, 0, cc->peer_bd_addr, cc->remote_psm, + &cfg, cc->sec_mask, GAP_FCR_CHAN_OPT_BASIC, + bta_jv_l2cap_client_cback)) != GAP_INVALID_HANDLE ) + { + evt_data.status = BTA_JV_SUCCESS; + } + } + } + + if (evt_data.status == BTA_JV_SUCCESS) + { + p_cb = &bta_jv_cb.l2c_cb[handle]; + p_cb->handle = handle; + p_cb->p_cback = cc->p_cback; + p_cb->psm = 0; /* not a server */ + p_cb->sec_id = sec_id; + p_cb->state = BTA_JV_ST_CL_OPENING; + } + else + { + bta_jv_free_sec_id(&sec_id); + } + evt_data.handle = handle; + cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV *)&evt_data); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_l2cap_close +** +** Description Close an L2CAP client connection +** +** Returns void +** +*******************************************************************************/ +void bta_jv_l2cap_close(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_L2CAP_CLOSE evt_data; + tBTA_JV_API_L2CAP_CLOSE *cc = &(p_data->l2cap_close); + tBTA_JV_L2CAP_CBACK *p_cback = cc->p_cb->p_cback; + + evt_data.handle = cc->handle; + evt_data.status = bta_jv_free_l2c_cb(cc->p_cb); + evt_data.async = FALSE; + + if (p_cback) + p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data); + else + APPL_TRACE_ERROR0("### NO CALLBACK SET !!! ###"); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_l2cap_server_cback +** +** Description handles the l2cap server callback +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_l2cap_server_cback(UINT16 gap_handle, UINT16 event) +{ +#if 0 + tBTA_JV_L2C_CB *p_cb = &bta_jv_cb.l2c_cb[gap_handle]; + tBTA_JV evt_data; + tBTA_JV_L2CAP_CBACK *p_cback; + + if(gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) + return; + + APPL_TRACE_DEBUG2( "bta_jv_l2cap_server_cback: %d evt:x%x", + gap_handle, event); + evt_data.l2c_open.status = BTA_JV_SUCCESS; + evt_data.l2c_open.handle = gap_handle; + + switch (event) + { + case GAP_EVT_CONN_OPENED: + bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle)); + evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle); + p_cb->state = BTA_JV_ST_SR_OPEN; + p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data); + break; + + case GAP_EVT_CONN_CLOSED: + evt_data.l2c_close.async = TRUE; + evt_data.l2c_close.handle = p_cb->handle; + p_cback = p_cb->p_cback; + evt_data.l2c_close.status = bta_jv_free_l2c_cb(p_cb); + p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data); + break; + + case GAP_EVT_CONN_DATA_AVAIL: + evt_data.handle = gap_handle; + p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data); + break; + + case GAP_EVT_CONN_CONGESTED: + case GAP_EVT_CONN_UNCONGESTED: + p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? TRUE : FALSE; + evt_data.l2c_cong.cong = p_cb->cong; + p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data); + break; + + default: + break; + } +#endif +} + +/******************************************************************************* +** +** Function bta_jv_l2cap_start_server +** +** Description starts an L2CAP server +** +** Returns void +** +*******************************************************************************/ +void bta_jv_l2cap_start_server(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_L2C_CB *p_cb; + UINT8 sec_id; + UINT16 handle; + tL2CAP_CFG_INFO cfg; + tBTA_JV_L2CAP_START evt_data; + tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server); + + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + + //FIX: MTU=0 means not present + if (ls->rx_mtu >0) + { + cfg.mtu_present = TRUE; + cfg.mtu = ls->rx_mtu; + } + else + { + cfg.mtu_present = FALSE; + cfg.mtu = 0; + } + + /* TODO DM role manager + L2CA_SetDesireRole(ls->role); + */ + + sec_id = bta_jv_alloc_sec_id(); + if (0 == sec_id || (FALSE == bta_jv_check_psm(ls->local_psm)) || + (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, 0, ls->local_psm, &cfg, + ls->sec_mask, GAP_FCR_CHAN_OPT_BASIC, bta_jv_l2cap_server_cback)) == GAP_INVALID_HANDLE) + { + bta_jv_free_sec_id(&sec_id); + evt_data.status = BTA_JV_FAILURE; + } + else + { + /* default JV implementation requires explicit call + to allow incoming connections when ready*/ + + GAP_SetAcceptReady(handle, FALSE); + + p_cb = &bta_jv_cb.l2c_cb[handle]; + evt_data.status = BTA_JV_SUCCESS; + evt_data.handle = handle; + evt_data.sec_id = sec_id; + p_cb->p_cback = ls->p_cback; + p_cb->handle = handle; + p_cb->sec_id = sec_id; + p_cb->state = BTA_JV_ST_SR_LISTEN; + p_cb->psm = ls->local_psm; + } + ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV *)&evt_data); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_l2cap_stop_server +** +** Description stops an L2CAP server +** +** Returns void +** +*******************************************************************************/ +void bta_jv_l2cap_stop_server(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_L2C_CB *p_cb; + tBTA_JV_L2CAP_CLOSE evt_data; + tBTA_JV_API_L2CAP_SERVER *ls = &(p_data->l2cap_server); + tBTA_JV_L2CAP_CBACK *p_cback; + int i; + + for(i=0; i<BTA_JV_MAX_L2C_CONN; i++) + { + if(bta_jv_cb.l2c_cb[i].psm == ls->local_psm) + { + p_cb = &bta_jv_cb.l2c_cb[i]; + p_cback = p_cb->p_cback; + evt_data.handle = p_cb->handle; + evt_data.status = bta_jv_free_l2c_cb(p_cb); + evt_data.async = FALSE; + p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV *)&evt_data); + break; + } + } +#endif +} + +/******************************************************************************* +** +** Function bta_jv_l2cap_read +** +** Description Read data from an L2CAP connection +** +** Returns void +** +*******************************************************************************/ +void bta_jv_l2cap_read(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_L2CAP_READ evt_data; + tBTA_JV_API_L2CAP_READ *rc = &(p_data->l2cap_read); + + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = rc->handle; + evt_data.req_id = rc->req_id; + evt_data.p_data = rc->p_data; + evt_data.len = 0; +#if SDP_FOR_JV_INCLUDED == TRUE + if(BTA_JV_L2C_FOR_SDP_HDL == rc->handle) + { + evt_data.len = rc->len; + if(evt_data.len > bta_jv_cb.sdp_data_size) + evt_data.len = bta_jv_cb.sdp_data_size; + + memcpy(rc->p_data, p_bta_jv_cfg->p_sdp_raw_data, evt_data.len); + bta_jv_cb.sdp_data_size = 0; + evt_data.status = BTA_JV_SUCCESS; + } + else +#endif + if (BT_PASS == GAP_ConnReadData(rc->handle, rc->p_data, rc->len, &evt_data.len)) + { + evt_data.status = BTA_JV_SUCCESS; + } + + rc->p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data); +#endif +} + + +/******************************************************************************* +** +** Function bta_jv_l2cap_write +** +** Description Write data to an L2CAP connection +** +** Returns void +** +*******************************************************************************/ +void bta_jv_l2cap_write(tBTA_JV_MSG *p_data) +{ +#if 0 + tBTA_JV_L2CAP_WRITE evt_data; + tBTA_JV_API_L2CAP_WRITE *ls = &(p_data->l2cap_write); + + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = ls->handle; + evt_data.req_id = ls->req_id; + evt_data.cong = ls->p_cb->cong; + evt_data.len = 0; +#if SDP_FOR_JV_INCLUDED == TRUE + if(BTA_JV_L2C_FOR_SDP_HDL == ls->handle) + { + UINT8 *p; + BT_HDR *p_msg = (BT_HDR *) GKI_getbuf ((UINT16)(ls->len + BT_HDR_SIZE + L2CAP_MIN_OFFSET)); + if(p_msg) + { + p_msg->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET; + p_msg->len = ls->len; + memcpy(p, ls->p_data, p_msg->len); + if(SDP_WriteData (bta_jv_cb.sdp_for_jv, p_msg)) + { + evt_data.len = ls->len; + evt_data.status = BTA_JV_SUCCESS; + } + } + } + else +#endif + if (!evt_data.cong && + BT_PASS == GAP_ConnWriteData(ls->handle, ls->p_data, ls->len, &evt_data.len)) + { + evt_data.status = BTA_JV_SUCCESS; + } + + ls->p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, (tBTA_JV *)&evt_data); +#endif +} + +/******************************************************************************* +** +** Function bta_jv_port_data_co_cback +** +** Description port data callback function of rfcomm +** connections +** +** Returns void +** +*******************************************************************************/ +/* +#define DATA_CO_CALLBACK_TYPE_INCOMING 1 +#define DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE 2 +#define DATA_CO_CALLBACK_TYPE_OUTGOING 3 +*/ +static int bta_jv_port_data_co_cback(UINT16 port_handle, UINT8 *buf, UINT16 len, int type) +{ + tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle); + tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(port_handle); + + if (p_cb != NULL) + { + switch(type) + { + case DATA_CO_CALLBACK_TYPE_INCOMING: + return bta_co_rfc_data_incoming(p_pcb->user_data, (BT_HDR*)buf); + case DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE: + return bta_co_rfc_data_outgoing_size(p_pcb->user_data, (int*)buf); + case DATA_CO_CALLBACK_TYPE_OUTGOING: + return bta_co_rfc_data_outgoing(p_pcb->user_data, buf, len); + default: + APPL_TRACE_ERROR1("unknown callout type:%d", type); + break; + } + } + return 0; +} + +/******************************************************************************* +** +** Function bta_jv_port_mgmt_cl_cback +** +** Description callback for port mamangement function of rfcomm +** client connections +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_port_mgmt_cl_cback(UINT32 code, UINT16 port_handle) +{ + tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle); + tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(port_handle); + tBTA_JV evt_data; + BD_ADDR rem_bda; + UINT16 lcid; + tBTA_JV_RFCOMM_CBACK *p_cback; /* the callback function */ + + APPL_TRACE_DEBUG1( "bta_jv_port_mgmt_cl_cback:%d", port_handle); + if(NULL == p_cb || NULL == p_cb->p_cback) + return; + + APPL_TRACE_DEBUG3( "bta_jv_port_mgmt_cl_cback code=%d port_handle:%d handle:%d", + code, port_handle, p_cb->handle); + + PORT_CheckConnection(port_handle, rem_bda, &lcid); + + if(code == PORT_SUCCESS) + { + evt_data.rfc_open.handle = p_cb->handle; + evt_data.rfc_open.status = BTA_JV_SUCCESS; + bdcpy(evt_data.rfc_open.rem_bda, rem_bda); + p_pcb->state = BTA_JV_ST_CL_OPEN; + p_cb->p_cback(BTA_JV_RFCOMM_OPEN_EVT, &evt_data, p_pcb->user_data); + } + else + { + evt_data.rfc_close.handle = p_cb->handle; + evt_data.rfc_close.status = BTA_JV_FAILURE; + evt_data.rfc_close.port_status = code; + evt_data.rfc_close.async = TRUE; + if (p_pcb->state == BTA_JV_ST_CL_CLOSING) + { + evt_data.rfc_close.async = FALSE; + } + p_pcb->state = BTA_JV_ST_NONE; + p_pcb->cong = FALSE; + p_cback = p_cb->p_cback; + bta_jv_free_rfc_cb(p_cb); + + p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, p_pcb->user_data); + } + +} + +/******************************************************************************* +** +** Function bta_jv_port_event_cl_cback +** +** Description Callback for RFCOMM client port events +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_port_event_cl_cback(UINT32 code, UINT16 port_handle) +{ + tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle); + tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(port_handle); + tBTA_JV evt_data; + + APPL_TRACE_DEBUG1( "bta_jv_port_event_cl_cback:%d", port_handle); + if(NULL == p_cb || NULL == p_cb->p_cback) + return; + + APPL_TRACE_DEBUG3( "bta_jv_port_event_cl_cback code=x%x port_handle:%d handle:%d", + code, port_handle, p_cb->handle); + if (code & PORT_EV_RXCHAR) + { + evt_data.data_ind.handle = p_cb->handle; + p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, p_pcb->user_data); + } + + if (code & PORT_EV_FC) + { + p_pcb->cong = (code & PORT_EV_FCS) ? FALSE : TRUE; + evt_data.rfc_cong.cong = p_pcb->cong; + evt_data.rfc_cong.handle = p_cb->handle; + evt_data.rfc_cong.status = BTA_JV_SUCCESS; + p_cb->p_cback(BTA_JV_RFCOMM_CONG_EVT, &evt_data, p_pcb->user_data); + } +} + +/******************************************************************************* +** +** Function bta_jv_rfcomm_connect +** +** Description Client initiates an RFCOMM connection +** +** Returns void +** +*******************************************************************************/ +void bta_jv_rfcomm_connect(tBTA_JV_MSG *p_data) +{ + UINT16 handle = 0; + UINT32 event_mask = (PORT_EV_RXCHAR | PORT_EV_FC | PORT_EV_FCS); + tPORT_STATE port_state; + UINT8 sec_id; + tBTA_JV_RFC_CB *p_cb = NULL; + tBTA_JV_PCB *p_pcb; + tBTA_JV_API_RFCOMM_CONNECT *cc = &(p_data->rfcomm_connect); + tBTA_JV_RFCOMM_CL_INIT evt_data; + + /* TODO DM role manager + L2CA_SetDesireRole(cc->role); + */ + + sec_id = bta_jv_alloc_sec_id(); + evt_data.sec_id = sec_id; + evt_data.status = BTA_JV_SUCCESS; + if (0 == sec_id || + BTM_SetSecurityLevel(TRUE, "", sec_id, cc->sec_mask, BT_PSM_RFCOMM, + BTM_SEC_PROTO_RFCOMM, cc->remote_scn) == FALSE) + { + evt_data.status = BTA_JV_FAILURE; + error("sec_id:%d is zero or BTM_SetSecurityLevel failed, remote_scn:%d", sec_id, cc->remote_scn); + } + + if (evt_data.status == BTA_JV_SUCCESS && + RFCOMM_CreateConnection(UUID_SERVCLASS_SERIAL_PORT, cc->remote_scn, FALSE, + BTA_JV_DEF_RFC_MTU, cc->peer_bd_addr, &handle, bta_jv_port_mgmt_cl_cback) != PORT_SUCCESS) + { + evt_data.status = BTA_JV_FAILURE; + } + if (evt_data.status == BTA_JV_SUCCESS) + { + p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb); + if(p_cb) + { + p_cb->p_cback = cc->p_cback; + p_cb->sec_id = sec_id; + p_cb->scn = 0; + p_pcb->state = BTA_JV_ST_CL_OPENING; + p_pcb->user_data = cc->user_data; + evt_data.use_co = TRUE; + + PORT_SetEventCallback(handle, bta_jv_port_event_cl_cback); + PORT_SetEventMask(handle, event_mask); + PORT_SetDataCOCallback (handle, bta_jv_port_data_co_cback); + + PORT_GetState(handle, &port_state); + + port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT); + + /* coverity[uninit_use_in_call] + FALSE-POSITIVE: port_state is initialized at PORT_GetState() */ + PORT_SetState(handle, &port_state); + + evt_data.handle = p_cb->handle; + } + else + { + evt_data.status = BTA_JV_FAILURE; + APPL_TRACE_ERROR0("run out of rfc control block"); + } + } + cc->p_cback(BTA_JV_RFCOMM_CL_INIT_EVT, (tBTA_JV *)&evt_data, cc->user_data); + } + +/******************************************************************************* +** +** Function bta_jv_rfcomm_close +** +** Description Close an RFCOMM connection +** +** Returns void +** +*******************************************************************************/ +void bta_jv_rfcomm_close(tBTA_JV_MSG *p_data) +{ + tBTA_JV_RFCOMM_CLOSE evt_data; + tBTA_JV_API_RFCOMM_CLOSE *cc = &(p_data->rfcomm_close); + tBTA_JV_RFC_CB *p_cb = cc->p_cb; + tBTA_JV_PCB *p_pcb = cc->p_pcb; + tBTA_JV_RFCOMM_CBACK *p_cback = p_cb->p_cback; + + evt_data.handle = p_cb->handle; + evt_data.status = BTA_JV_FAILURE; + + void* user_data = p_pcb->user_data; + p_pcb->cong = FALSE; + if(p_pcb->state <= BTA_JV_ST_CL_MAX) + { + if(p_pcb->state == BTA_JV_ST_CL_OPEN) + { + if(PORT_SUCCESS == RFCOMM_RemoveConnection(p_pcb->port_handle)) + { + p_pcb->state = BTA_JV_ST_CL_CLOSING; + return; + } + } + evt_data.status = bta_jv_free_rfc_cb(p_cb); + } + else if(BTA_JV_ST_SR_OPEN == p_pcb->state) + { + /* server is connected */ + if(PORT_SUCCESS == RFCOMM_RemoveConnection(p_pcb->port_handle)) + { + p_pcb->state = BTA_JV_ST_SR_CLOSING; + return; + } + } + + evt_data.async = FALSE; + + if (p_cback) + p_cback(BTA_JV_RFCOMM_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data); + else + error("### NO CALLBACK SET !!! ###"); +} + +/******************************************************************************* +** +** Function bta_jv_get_num_rfc_listen +** +** Description when a RFCOMM connection goes down, make sure that there's only +** one port stays listening on this scn. +** +** Returns +** +*******************************************************************************/ +static UINT8 bta_jv_get_num_rfc_listen(tBTA_JV_RFC_CB *p_cb) +{ + UINT8 i, listen=1; + tBTA_JV_PCB *p_pcb; + + if (p_cb->max_sess > 1) + { + listen = 0; + for (i=0; i<p_cb->max_sess; i++) + { + if (p_cb->rfc_hdl[i] != 0) + { + p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1]; + if (BTA_JV_ST_SR_LISTEN == p_pcb->state) + { + listen++; + } + } + } + } + return listen; +} + +/******************************************************************************* +** +** Function bta_jv_port_mgmt_sr_cback +** +** Description callback for port mamangement function of rfcomm +** server connections +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_port_mgmt_sr_cback(UINT32 code, UINT16 port_handle) +{ + tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(port_handle); + tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle); + tBTA_JV evt_data; + BD_ADDR rem_bda; + UINT16 lcid; + UINT8 num; + tBTA_JV_RFCOMM_CBACK *p_cback; + UINT32 si; + + if(NULL == p_cb || NULL == p_cb->p_cback) + return; + void *user_data = p_pcb->user_data; + APPL_TRACE_DEBUG4( "bta_jv_port_mgmt_sr_cback code=%d port_handle:%d handle:%d/0x%x", + code, port_handle, p_cb->handle, p_pcb->handle); + + PORT_CheckConnection(port_handle, rem_bda, &lcid); + int failed = TRUE; + if(code == PORT_SUCCESS) + { + evt_data.rfc_srv_open.handle = p_pcb->handle; + evt_data.rfc_srv_open.status = BTA_JV_SUCCESS; + bdcpy(evt_data.rfc_srv_open.rem_bda, rem_bda); + p_pcb->state = BTA_JV_ST_SR_OPEN; + tBTA_JV_PCB *p_pcb_new_listen = bta_jv_add_rfc_port(p_cb); + if(p_pcb_new_listen) + { + evt_data.rfc_srv_open.new_listen_handle = p_pcb_new_listen->handle; + p_pcb_new_listen->user_data = p_cb->p_cback(BTA_JV_RFCOMM_SRV_OPEN_EVT, &evt_data, user_data); + failed = FALSE; + } + else error("bta_jv_add_rfc_port failed to create new listen port"); + } + if(failed) + { + evt_data.rfc_close.handle = p_cb->handle; + evt_data.rfc_close.status = BTA_JV_SUCCESS; + evt_data.rfc_close.async = TRUE; + if(BTA_JV_ST_SR_CLOSING == p_pcb->state) + { + evt_data.rfc_close.async = FALSE; + } + p_pcb->cong = FALSE; + p_cback = p_cb->p_cback; + APPL_TRACE_DEBUG1( "removing rfc handle:0x%x", p_pcb->handle); + si = BTA_JV_RFC_HDL_TO_SIDX(p_pcb->handle); + p_cb->rfc_hdl[si] = 0; + p_pcb->state = BTA_JV_ST_NONE; + p_pcb->handle = 0; + RFCOMM_RemoveServer(port_handle); + evt_data.rfc_close.port_status = code; + p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, user_data); + } +} + +/******************************************************************************* +** +** Function bta_jv_port_event_sr_cback +** +** Description Callback for RFCOMM server port events +** +** Returns void +** +*******************************************************************************/ +static void bta_jv_port_event_sr_cback(UINT32 code, UINT16 port_handle) +{ + tBTA_JV_PCB *p_pcb = bta_jv_rfc_port_to_pcb(port_handle); + tBTA_JV_RFC_CB *p_cb = bta_jv_rfc_port_to_cb(port_handle); + tBTA_JV evt_data; + + if(NULL == p_cb || NULL == p_cb->p_cback) + return; + + APPL_TRACE_DEBUG3( "bta_jv_port_event_sr_cback code=x%x port_handle:%d handle:%d", + code, port_handle, p_cb->handle); + + void *user_data = p_pcb->user_data; + if (code & PORT_EV_RXCHAR) + { + evt_data.data_ind.handle = p_cb->handle; + p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, user_data); + } + + if (code & PORT_EV_FC) + { + p_pcb->cong = (code & PORT_EV_FCS) ? FALSE : TRUE; + evt_data.rfc_cong.cong = p_pcb->cong; + evt_data.rfc_cong.handle = p_cb->handle; + evt_data.rfc_cong.status = BTA_JV_SUCCESS; + p_cb->p_cback(BTA_JV_RFCOMM_CONG_EVT, &evt_data, user_data); + } +} + +/******************************************************************************* +** +** Function bta_jv_add_rfc_port +** +** Description add a port for server when the existing posts is open +** +** Returns return a pointer to tBTA_JV_PCB just added +** +*******************************************************************************/ +static tBTA_JV_PCB * bta_jv_add_rfc_port(tBTA_JV_RFC_CB *p_cb) +{ + UINT8 used = 0, i, listen=0; + UINT32 si = 0; + tBTA_JV_PCB *p_pcb = NULL; + tPORT_STATE port_state; + UINT32 event_mask = (PORT_EV_RXCHAR | PORT_EV_FC | PORT_EV_FCS); + + if (p_cb->max_sess > 1) + { + for (i=0; i<p_cb->max_sess; i++) + { + if (p_cb->rfc_hdl[i] != 0) + { + p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1]; + if (p_pcb->state == BTA_JV_ST_SR_LISTEN) + listen++; + used++; + } + else if (si==0) + { + si = (UINT32)(i + 1); + } + } + + debug("bta_jv_add_rfc_port max_sess=%d used:%d listen:%d si:%d", + p_cb->max_sess, used, listen, si); + if (used <p_cb->max_sess && listen==0 && si) + { + si--; + if (RFCOMM_CreateConnection(p_cb->sec_id, p_cb->scn, TRUE, + BTA_JV_DEF_RFC_MTU, (UINT8 *) bd_addr_any, &(p_cb->rfc_hdl[si]), bta_jv_port_mgmt_sr_cback) == PORT_SUCCESS) + { + p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1]; + p_pcb->state = BTA_JV_ST_SR_LISTEN; + p_pcb->port_handle = p_cb->rfc_hdl[si]; + PORT_SetEventCallback(p_pcb->port_handle, bta_jv_port_event_sr_cback); + PORT_SetDataCOCallback (p_pcb->port_handle, bta_jv_port_data_co_cback); + PORT_SetEventMask(p_pcb->port_handle, event_mask); + PORT_GetState(p_pcb->port_handle, &port_state); + + port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT); + +/* coverity[uninit_use_in_call] +FALSE-POSITIVE: port_state is initialized at PORT_GetState() */ + PORT_SetState(p_pcb->port_handle, &port_state); + p_pcb->handle = BTA_JV_RFC_H_S_TO_HDL(p_cb->handle, si); + APPL_TRACE_DEBUG1( "new rfc handle:0x%x", p_pcb->handle); + } + } + } + return p_pcb; +} + +/******************************************************************************* +** +** Function bta_jv_rfcomm_start_server +** +** Description waits for an RFCOMM client to connect +** +** +** Returns void +** +*******************************************************************************/ +void bta_jv_rfcomm_start_server(tBTA_JV_MSG *p_data) +{ + UINT16 handle = 0; + UINT32 event_mask = (PORT_EV_RXCHAR | PORT_EV_FC | PORT_EV_FCS); + tPORT_STATE port_state; + UINT8 sec_id; + tBTA_JV_RFC_CB *p_cb = NULL; + tBTA_JV_PCB *p_pcb; + tBTA_JV_API_RFCOMM_SERVER *rs = &(p_data->rfcomm_server); + tBTA_JV_RFCOMM_START evt_data; + + /* TODO DM role manager + L2CA_SetDesireRole(rs->role); + */ + evt_data.status = BTA_JV_FAILURE; + do + { + sec_id = bta_jv_alloc_sec_id(); + + if (0 == sec_id || + BTM_SetSecurityLevel(FALSE, "JV PORT", sec_id, rs->sec_mask, + BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, rs->local_scn) == FALSE) + { + break; + } + + if (RFCOMM_CreateConnection(sec_id, rs->local_scn, TRUE, + BTA_JV_DEF_RFC_MTU, (UINT8 *) bd_addr_any, &handle, bta_jv_port_mgmt_sr_cback) != PORT_SUCCESS) + { + break; + } + + p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb); + if(!p_cb) + { + APPL_TRACE_ERROR0("run out of rfc control block"); + break; + } + + p_cb->max_sess = rs->max_session; + p_cb->p_cback = rs->p_cback; + p_cb->sec_id = sec_id; + p_cb->scn = rs->local_scn; + p_pcb->state = BTA_JV_ST_SR_LISTEN; + p_pcb->user_data = rs->user_data; + evt_data.status = BTA_JV_SUCCESS; + evt_data.handle = p_cb->handle; + evt_data.sec_id = sec_id; + evt_data.use_co = TRUE; //FALSE; + + PORT_SetEventCallback(handle, bta_jv_port_event_sr_cback); + PORT_SetEventMask(handle, event_mask); + PORT_GetState(handle, &port_state); + + port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT); + +/* coverity[uninit_use_in_call] +FALSE-POSITIVE: port_state is initialized at PORT_GetState() */ + PORT_SetState(handle, &port_state); + } while (0); + + rs->p_cback(BTA_JV_RFCOMM_START_EVT, (tBTA_JV *)&evt_data, rs->user_data); + if(evt_data.status == BTA_JV_SUCCESS) + { + PORT_SetDataCOCallback (handle, bta_jv_port_data_co_cback); + } +} + +/******************************************************************************* +** +** Function bta_jv_rfcomm_stop_server +** +** Description stops an RFCOMM server +** +** Returns void +** +*******************************************************************************/ + +void bta_jv_rfcomm_stop_server(tBTA_JV_MSG *p_data) +{ + tBTA_JV_RFCOMM_CLOSE evt_data; + int i; + tBTA_JV_API_RFCOMM_SERVER *ls = &(p_data->rfcomm_server); + HDL2CB(ls->rfc_handle); + evt_data.status = BTA_JV_FAILURE; + if(p_cb && p_pcb) + { + evt_data.handle = p_cb->handle; + void* user_data = p_pcb->user_data; + evt_data.status = bta_jv_free_rfc_listen_cb(p_cb); + evt_data.async = FALSE; + + /* occasionally when shutting down stack the callback is already + freed, hence make sure we check for this condition (pending investigatation + of rootcause) */ + debug("send BTA_JV_RFCOMM_CLOSE_EVT"); + if( p_cb->p_cback) + p_cb->p_cback(BTA_JV_RFCOMM_CLOSE_EVT, (tBTA_JV *)&evt_data, user_data); + } + else + { + debug("warning, no jv callback set"); + } +} + +/******************************************************************************* +** +** Function bta_jv_rfcomm_read +** +** Description Read data from an RFCOMM connection +** +** Returns void +** +*******************************************************************************/ +void bta_jv_rfcomm_read(tBTA_JV_MSG *p_data) +{ + tBTA_JV_API_RFCOMM_READ *rc = &(p_data->rfcomm_read); + tBTA_JV_RFC_CB *p_cb = rc->p_cb; + tBTA_JV_PCB *p_pcb = rc->p_pcb; + tBTA_JV_RFCOMM_READ evt_data; + + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = p_cb->handle; + evt_data.req_id = rc->req_id; + evt_data.p_data = rc->p_data; + if (PORT_ReadData(rc->p_pcb->port_handle, (char *)rc->p_data, rc->len, &evt_data.len) == + PORT_SUCCESS) + { + evt_data.status = BTA_JV_SUCCESS; + } + + p_cb->p_cback(BTA_JV_RFCOMM_READ_EVT, (tBTA_JV *)&evt_data, p_pcb->user_data); +} + +/******************************************************************************* +** +** Function bta_jv_rfcomm_write +** +** Description write data to an RFCOMM connection +** +** Returns void +** +*******************************************************************************/ +void bta_jv_rfcomm_write(tBTA_JV_MSG *p_data) +{ + tBTA_JV_API_RFCOMM_WRITE *wc = &(p_data->rfcomm_write); + tBTA_JV_RFC_CB *p_cb = wc->p_cb; + tBTA_JV_PCB *p_pcb = wc->p_pcb; + tBTA_JV_RFCOMM_WRITE evt_data; + + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = p_cb->handle; + evt_data.req_id = wc->req_id; + evt_data.cong = p_pcb->cong; + evt_data.len = 0; + if (!evt_data.cong && + PORT_WriteDataCO(p_pcb->port_handle, &evt_data.len) == + PORT_SUCCESS) + { + evt_data.status = BTA_JV_SUCCESS; + } + //update congestion flag + evt_data.cong = p_pcb->cong; + if (p_cb->p_cback) + { + p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, (tBTA_JV *)&evt_data, p_pcb->user_data); + } + else + { + APPL_TRACE_ERROR0("bta_jv_rfcomm_write :: WARNING ! No JV callback set"); + } +} + diff --git a/bta/jv/bta_jv_api.c b/bta/jv/bta_jv_api.c new file mode 100644 index 0000000..8953886 --- /dev/null +++ b/bta/jv/bta_jv_api.c @@ -0,0 +1,1584 @@ +/****************************************************************************** + * + * Copyright (C) 2006-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 of the JAVA API for Bluetooth Wireless + * Technology (JABWT) as specified by the JSR82 specificiation + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bd.h" +#include "bta_sys.h" +#include "bta_jv_api.h" +#include "bta_jv_int.h" +#include "gki.h" +#include <string.h> +#include "port_api.h" +#include "sdp_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_jv_reg = +{ + bta_jv_sm_execute, + NULL +}; + +/******************************************************************************* +** +** Function BTA_JvEnable +** +** Description Enable the Java I/F service. When the enable +** operation is complete the callback function will be +** called with a BTA_JV_ENABLE_EVT. This function must +** be called before other function in the JV API are +** called. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK *p_cback) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_ENABLE *p_buf; + + APPL_TRACE_API0( "BTA_JvEnable"); + if(p_cback && FALSE == bta_sys_is_register(BTA_ID_JV)) + { + memset(&bta_jv_cb, 0, sizeof(tBTA_JV_CB)); + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_JV, &bta_jv_reg); + GKI_sched_unlock(); + + if (p_cback && (p_buf = (tBTA_JV_API_ENABLE *) GKI_getbuf(sizeof(tBTA_JV_API_ENABLE))) != NULL) + { + p_buf->hdr.event = BTA_JV_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + bta_sys_sendmsg(p_buf); + status = BTA_JV_SUCCESS; + } + } + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvDisable +** +** Description Disable the Java I/F +** +** Returns void +** +*******************************************************************************/ +void BTA_JvDisable(void) +{ + BT_HDR *p_buf; + + APPL_TRACE_API0( "BTA_JvDisable"); + bta_sys_deregister(BTA_ID_JV); + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_JV_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_JvIsEnable +** +** Description Get the JV registration status. +** +** Returns TRUE, if registered +** +*******************************************************************************/ +BOOLEAN BTA_JvIsEnable(void) +{ + return bta_sys_is_register(BTA_ID_JV); +} + +/******************************************************************************* +** +** Function BTA_JvSetDiscoverability +** +** Description This function sets the Bluetooth discoverable modes +** of the local device. This controls whether other +** Bluetooth devices can find the local device. +** +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_SET_DISCOVER_EVT. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvSetDiscoverability(tBTA_JV_DISC disc_mode) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_SET_DISCOVERABILITY *p_msg; + + APPL_TRACE_API0( "BTA_JvSetDiscoverability"); + if ((p_msg = (tBTA_JV_API_SET_DISCOVERABILITY *)GKI_getbuf(sizeof(tBTA_JV_MSG))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_SET_DISCOVERABILITY_EVT; + p_msg->disc_mode = disc_mode; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvGetDiscoverability +** +** Description This function gets the Bluetooth +** discoverable modes of local device +** +** Returns The current Bluetooth discoverable mode. +** +*******************************************************************************/ +tBTA_JV_DISC BTA_JvGetDiscoverability(void) +{ + APPL_TRACE_API0( "BTA_JvGetDiscoverability"); + return BTM_ReadDiscoverability(0, 0); +} + +/******************************************************************************* +** +** Function BTA_JvGetLocalDeviceAddr +** +** Description This function obtains the local Bluetooth device address. +** The local Bluetooth device address is reported by the +** tBTA_JV_DM_CBACK callback with a BTA_JV_LOCAL_ADDR_EVT. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvGetLocalDeviceAddr(void) +{ + tBTA_JV_STATUS ret = BTA_JV_FAILURE; + BT_HDR *p_msg; + + APPL_TRACE_API0( "BTA_JvGetLocalDeviceAddr"); + if ((p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_JV_API_GET_LOCAL_DEVICE_ADDR_EVT; + bta_sys_sendmsg(p_msg); + ret = BTA_JV_SUCCESS; + } + + return(ret); +} + +/******************************************************************************* +** +** Function BTA_JvGetLocalDeviceName +** +** Description This function obtains the name of the local device +** The local Bluetooth device name is reported by the +** tBTA_JV_DM_CBACK callback with a BTA_JV_LOCAL_NAME_EVT. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvGetLocalDeviceName(void) +{ + tBTA_JV_STATUS ret = BTA_JV_FAILURE; + BT_HDR *p_msg; + + APPL_TRACE_API0( "BTA_JvGetLocalDeviceName"); + if ((p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_JV_API_GET_LOCAL_DEVICE_NAME_EVT; + bta_sys_sendmsg(p_msg); + ret = BTA_JV_SUCCESS; + } + + return(ret); +} + +/******************************************************************************* +** +** Function BTA_JvGetRemoteDeviceName +** +** Description This function obtains the name of the specified device. +** The Bluetooth device name is reported by the +** tBTA_JV_DM_CBACK callback with a BTA_JV_REMOTE_NAME_EVT. +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvGetRemoteDeviceName(BD_ADDR bd_addr) +{ + tBTA_JV_STATUS ret = BTA_JV_FAILURE; + tBTA_JV_API_GET_REMOTE_NAME *p_msg; + + APPL_TRACE_API0( "BTA_JvGetRemoteDeviceName"); + if ((p_msg = (tBTA_JV_API_GET_REMOTE_NAME *)GKI_getbuf(sizeof(tBTA_JV_API_GET_REMOTE_NAME))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_GET_REMOTE_DEVICE_NAME_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + bta_sys_sendmsg(p_msg); + ret = BTA_JV_SUCCESS; + } + + return(ret); +} + +/******************************************************************************* +** +** Function BTA_JvGetPreknownDevice +** +** Description This function obtains the Bluetooth address in the inquiry +** database collected via the previous call to BTA_DmSearch(). +** +** Returns The number of preknown devices if p_bd_addr is NULL +** BTA_JV_SUCCESS if successful. +** BTA_JV_INTERNAL_ERR(-1) if internal failure. +** +*******************************************************************************/ +INT32 BTA_JvGetPreknownDevice(UINT8 * p_bd_addr, UINT32 index) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTM_INQ_INFO *p_info; + UINT32 count = 0; + INT32 ret = BTA_JV_INTERNAL_ERR; + + APPL_TRACE_API0( "BTA_JvGetPreknownDevice"); + p_info = BTM_InqFirstResult(); + if(p_info) + { + status = BTA_JV_SUCCESS; + /* the database is valid */ + if(NULL == p_bd_addr) + { + /* p_bd_addr is NULL: count the number of preknown devices */ + /* set the index to an invalid size (too big) */ + index = BTM_INQ_DB_SIZE; + } + else if(index >= BTM_INQ_DB_SIZE) + { + /* invalid index - error */ + status = (tBTA_JV_STATUS)BTA_JV_INTERNAL_ERR; + } + + if(BTA_JV_SUCCESS == status) + { + while(p_info && index > count) + { + count++; + p_info = BTM_InqNextResult(p_info); + } + + if(p_bd_addr) + { + if(index == count && p_info) + { + count = BTA_JV_SUCCESS; + bdcpy(p_bd_addr, p_info->results.remote_bd_addr); + } + else + status = (tBTA_JV_STATUS)BTA_JV_INTERNAL_ERR; + } + /* + else report the count + */ + } + /* + else error had happened. + */ + } + + if(BTA_JV_SUCCESS == status) + { + ret = count; + } + return ret; +} + + +/******************************************************************************* +** +** Function BTA_JvGetDeviceClass +** +** Description This function obtains the local Class of Device. This +** function executes in place. The result is returned right away. +** +** Returns DEV_CLASS, A three-byte array of UINT8 that contains the +** Class of Device information. The definitions are in the +** "Bluetooth Assigned Numbers". +** +*******************************************************************************/ +UINT8 * BTA_JvGetDeviceClass(void) +{ + APPL_TRACE_API0( "BTA_JvGetDeviceClass"); + return BTM_ReadDeviceClass(); +} + +/******************************************************************************* +** +** Function BTA_JvSetServiceClass +** +** Description This function sets the service class of local Class of Device +** +** Returns BTA_JV_SUCCESS if successful. +** BTA_JV_FAIL if internal failure. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvSetServiceClass(UINT32 service) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_SET_SERVICE_CLASS *p_msg; + + APPL_TRACE_API0( "BTA_JvSetServiceClass"); + if ((p_msg = (tBTA_JV_API_SET_SERVICE_CLASS *)GKI_getbuf(sizeof(tBTA_JV_API_SET_SERVICE_CLASS))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_SET_SERVICE_CLASS_EVT; + p_msg->service = service; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvSetEncryption +** +** Description This function ensures that the connection to the given device +** is encrypted. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_SET_ENCRYPTION_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvSetEncryption(BD_ADDR bd_addr) +{ + tBTA_JV_STATUS ret = BTA_JV_FAILURE; + tBTA_JV_API_SET_ENCRYPTION *p_msg; + + APPL_TRACE_API0( "BTA_JvSetEncryption"); + if ((p_msg = (tBTA_JV_API_SET_ENCRYPTION *)GKI_getbuf(sizeof(tBTA_JV_API_SET_ENCRYPTION))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_SET_ENCRYPTION_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + bta_sys_sendmsg(p_msg); + ret = BTA_JV_SUCCESS; + } + + return(ret); +} + +/******************************************************************************* +** +** Function BTA_JvIsAuthenticated +** +** Description This function checks if the peer device is authenticated +** +** Returns TRUE if authenticated. +** FALSE if not. +** +*******************************************************************************/ +BOOLEAN BTA_JvIsAuthenticated(BD_ADDR bd_addr) +{ + BOOLEAN is_authenticated = FALSE; + UINT8 sec_flags; + + if(BTM_GetSecurityFlags(bd_addr, &sec_flags)) + { + if(sec_flags&BTM_SEC_FLAG_AUTHENTICATED) + is_authenticated = TRUE; + } + return is_authenticated; +} + +/******************************************************************************* +** +** Function BTA_JvIsTrusted +** +** Description This function checks if the peer device is trusted +** (previously paired) +** +** Returns TRUE if trusted. +** FALSE if not. +** +*******************************************************************************/ +BOOLEAN BTA_JvIsTrusted(BD_ADDR bd_addr) +{ + BOOLEAN is_trusted = FALSE; + UINT8 sec_flags; + + if(BTM_GetSecurityFlags(bd_addr, &sec_flags)) + { + if ((sec_flags&BTM_SEC_FLAG_AUTHENTICATED) || + (sec_flags&BTM_SEC_FLAG_LKEY_KNOWN)) + { + is_trusted = TRUE; + } + } + return is_trusted; +} + +/******************************************************************************* +** +** Function BTA_JvIsAuthorized +** +** Description This function checks if the peer device is authorized +** +** Returns TRUE if authorized. +** FALSE if not. +** +*******************************************************************************/ +BOOLEAN BTA_JvIsAuthorized(BD_ADDR bd_addr) +{ + BOOLEAN is_authorized = FALSE; + UINT8 sec_flags; + + if(BTM_GetSecurityFlags(bd_addr, &sec_flags)) + { + if(sec_flags&BTM_SEC_FLAG_AUTHORIZED) + is_authorized = TRUE; + } + return is_authorized; +} + +/******************************************************************************* +** +** Function BTA_JvIsEncrypted +** +** Description This function checks if the link to peer device is encrypted +** +** Returns TRUE if encrypted. +** FALSE if not. +** +*******************************************************************************/ +BOOLEAN BTA_JvIsEncrypted(BD_ADDR bd_addr) +{ + BOOLEAN is_encrypted = FALSE; + UINT8 sec_flags; + + if(BTM_GetSecurityFlags(bd_addr, &sec_flags)) + { + if(sec_flags&BTM_SEC_FLAG_ENCRYPTED) + is_encrypted = TRUE; + } + return is_encrypted; +} + +/******************************************************************************* +** +** Function BTA_JvGetSecurityMode +** +** Description This function returns the current Bluetooth security mode +** of the local device +** +** Returns The current Bluetooth security mode. +** +*******************************************************************************/ +tBTA_JV_SEC_MODE BTA_JvGetSecurityMode(void) +{ + return BTM_GetSecurityMode(); +} + +/******************************************************************************* +** +** Function BTA_JvGetSCN +** +** Description This function reserves a SCN (server channel number) for +** applications running over RFCOMM. It is primarily called by +** server profiles/applications to register their SCN into the +** SDP database. The SCN is reported by the tBTA_JV_DM_CBACK +** callback with a BTA_JV_GET_SCN_EVT. +** If the SCN reported is 0, that means all SCN resources are +** exhausted. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvGetSCN(void) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + BT_HDR *p_msg; + + APPL_TRACE_API0( "BTA_JvGetSCN"); + if ((p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = BTA_JV_API_GET_SCN_EVT; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvFreeSCN +** +** Description This function frees a server channel number that was used +** by an application running over RFCOMM. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvFreeSCN(UINT8 scn) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_FREE_SCN *p_msg; + + APPL_TRACE_API0( "BTA_JvFreeSCN"); + if ((p_msg = (tBTA_JV_API_FREE_SCN *)GKI_getbuf(sizeof(tBTA_JV_API_FREE_SCN))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_FREE_SCN_EVT; + p_msg->scn = scn; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvGetPSM +** +** Description This function reserves a PSM (Protocol Service Multiplexer) +** applications running over L2CAP. It is primarily called by +** server profiles/applications to register their PSM into the +** SDP database. +** +** Returns The next free PSM +** +*******************************************************************************/ +UINT16 BTA_JvGetPSM(void) +{ +#if 0 + APPL_TRACE_API0( "BTA_JvGetPSM"); + + return (L2CA_AllocatePSM()); +#endif + return 0; +} + + +/******************************************************************************* +** +** Function BTA_JvStartDiscovery +** +** Description This function performs service discovery for the services +** provided by the given peer device. When the operation is +** complete the tBTA_JV_DM_CBACK callback function will be +** called with a BTA_JV_DISCOVERY_COMP_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, UINT16 num_uuid, + tSDP_UUID *p_uuid_list, void * user_data) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_START_DISCOVERY *p_msg; + + APPL_TRACE_API0( "BTA_JvStartDiscovery"); + if ((p_msg = (tBTA_JV_API_START_DISCOVERY *)GKI_getbuf(sizeof(tBTA_JV_API_START_DISCOVERY))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_START_DISCOVERY_EVT; + bdcpy(p_msg->bd_addr, bd_addr); + p_msg->num_uuid = num_uuid; + memcpy(p_msg->uuid_list, p_uuid_list, num_uuid * sizeof(tSDP_UUID)); + p_msg->num_attr = 0; + p_msg->user_data = user_data; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvCancelDiscovery +** +** Description This function cancels an active service discovery. +** When the operation is +** complete the tBTA_JV_DM_CBACK callback function will be +** called with a BTA_JV_CANCEL_DISCVRY_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvCancelDiscovery(void * user_data) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_CANCEL_DISCOVERY *p_msg; + + APPL_TRACE_API0( "BTA_JvCancelDiscovery"); + if ((p_msg = (tBTA_JV_API_CANCEL_DISCOVERY *)GKI_getbuf(sizeof(tBTA_JV_API_CANCEL_DISCOVERY))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_CANCEL_DISCOVERY_EVT; + p_msg->user_data = user_data; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvGetServicesLength +** +** Description This function obtains the number of services and the length +** of each service found in the SDP database (result of last +** BTA_JvStartDiscovery().When the operation is complete the +** tBTA_JV_DM_CBACK callback function will be called with a +** BTA_JV_SERVICES_LEN_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvGetServicesLength(BOOLEAN inc_hdr, UINT16 *p_services_len) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_GET_SERVICES_LENGTH *p_msg; + + APPL_TRACE_API0( "BTA_JvGetServicesLength"); + if ((p_msg = (tBTA_JV_API_GET_SERVICES_LENGTH *)GKI_getbuf(sizeof(tBTA_JV_API_GET_SERVICES_LENGTH))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_GET_SERVICES_LENGTH_EVT; + p_msg->p_services_len = p_services_len; + p_msg->inc_hdr = inc_hdr; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} +/******************************************************************************* +** +** Function BTA_JvGetServicesResult +** +** Description This function returns a number of service records found +** during current service search, equals to the number returned +** by previous call to BTA_JvGetServicesLength. +** The contents of each SDP record will be returned under a +** TLV (type, len, value) representation in the data buffer +** provided by the caller. +** +** Returns -1, if error. Otherwise, the number of services +** +*******************************************************************************/ +INT32 BTA_JvGetServicesResult(BOOLEAN inc_hdr, UINT8 **TLVs) +{ +#if 0 + INT32 num_services = -1; + UINT8 *p, *np, *op, type; + UINT32 raw_used, raw_cur; + UINT32 len; + UINT32 hdr_len; + + APPL_TRACE_API0( "BTA_JvGetServicesResult"); + if(p_bta_jv_cfg->p_sdp_db->p_first_rec) + { + /* the database is valid */ + num_services = 0; + p = p_bta_jv_cfg->p_sdp_db->raw_data; + raw_used = p_bta_jv_cfg->p_sdp_db->raw_used; + while(raw_used && p) + { + op = p; + type = *p++; + np = sdpu_get_len_from_type(p, type, &len); + p = np + len; + raw_cur = p - op; + if(raw_used >= raw_cur) + { + raw_used -= raw_cur; + } + else + { + /* error. can not continue */ + break; + } + if(inc_hdr) + { + hdr_len = np - op; + memcpy(TLVs[num_services++], op, len+hdr_len); + } + else + { + memcpy(TLVs[num_services++], np, len); + } + } /* end of while */ + } + return(num_services); +#endif + return 0; +} +/******************************************************************************* +** +** Function BTA_JvServiceSelect +** +** Description This function checks if the SDP database contains the given +** service UUID. When the operation is complete the +** tBTA_JV_DM_CBACK callback function will be called with a +** BTA_JV_SERVICE_SEL_EVT with the length of the service record. +** If the service is not found or error, -1 is reported. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvServiceSelect(UINT16 uuid) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_SERVICE_SELECT *p_msg; + + APPL_TRACE_API0( "BTA_JvServiceSelect"); + if ((p_msg = (tBTA_JV_API_SERVICE_SELECT *)GKI_getbuf(sizeof(tBTA_JV_API_SERVICE_SELECT))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_SERVICE_SELECT_EVT; + p_msg->uuid = uuid; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvServiceResult +** +** Description This function returns the contents of the SDP record from +** last BTA_JvServiceSelect. The contents will be returned under +** a TLV (type, len, value) representation in the data buffer +** provided by the caller. +** +** Returns -1, if error. Otherwise, the length of service record. +** +*******************************************************************************/ +INT32 BTA_JvServiceResult(UINT8 *TLV) +{ + INT32 serv_sel = -1; + + APPL_TRACE_API0( "BTA_JvServiceResult"); + if(bta_jv_cb.p_sel_raw_data) + { + serv_sel = bta_jv_cb.sel_len; + memcpy(TLV, bta_jv_cb.p_sel_raw_data, serv_sel); + } + + return serv_sel; +} + + +/******************************************************************************* +** +** Function BTA_JvCreateRecord +** +** Description Create a service record in the local SDP database. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_CREATE_RECORD_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvCreateRecordByUser(void *user_data) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_CREATE_RECORD *p_msg; + + APPL_TRACE_API0( "BTA_JvCreateRecordByUser"); + if ((p_msg = (tBTA_JV_API_CREATE_RECORD *)GKI_getbuf(sizeof(tBTA_JV_API_CREATE_RECORD))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_CREATE_RECORD_EVT; + p_msg->user_data = user_data; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvUpdateRecord +** +** Description Update a service record in the local SDP database. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_UPDATE_RECORD_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvUpdateRecord(UINT32 handle, UINT16 *p_ids, + UINT8 **p_values, INT32 *p_value_sizes, INT32 array_len) +{ +#if 0 + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_UPDATE_RECORD *p_msg; + + APPL_TRACE_API0( "BTA_JvUpdateRecord"); + if ((p_msg = (tBTA_JV_API_UPDATE_RECORD *)GKI_getbuf(sizeof(tBTA_JV_API_UPDATE_RECORD))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_UPDATE_RECORD_EVT; + p_msg->handle = handle; + p_msg->p_ids = p_ids; + p_msg->p_values = p_values; + p_msg->p_value_sizes = p_value_sizes; + p_msg->array_len = array_len; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + return(status); +#endif + return -1; +} + +/******************************************************************************* +** +** Function BTA_JvAddAttribute +** +** Description Add an attribute to a service record in the local SDP database. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_ADD_ATTR_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvAddAttribute(UINT32 handle, UINT16 attr_id, + UINT8 *p_value, INT32 value_size) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_ADD_ATTRIBUTE *p_msg; + + APPL_TRACE_API0( "BTA_JvAddAttribute"); + if ((p_msg = (tBTA_JV_API_ADD_ATTRIBUTE *)GKI_getbuf(sizeof(tBTA_JV_API_ADD_ATTRIBUTE))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_ADD_ATTRIBUTE_EVT; + p_msg->handle = handle; + p_msg->attr_id = attr_id; + p_msg->p_value = p_value; + p_msg->value_size = value_size; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvDeleteAttribute +** +** Description Delete an attribute from a service record in the local SDP database. +** When the operation is complete the tBTA_JV_DM_CBACK callback +** function will be called with a BTA_JV_DELETE_ATTR_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvDeleteAttribute(UINT32 handle, UINT16 attr_id) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_ADD_ATTRIBUTE *p_msg; + + APPL_TRACE_API0( "BTA_JvDeleteAttribute"); + if ((p_msg = (tBTA_JV_API_ADD_ATTRIBUTE *)GKI_getbuf(sizeof(tBTA_JV_API_ADD_ATTRIBUTE))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_DELETE_ATTRIBUTE_EVT; + p_msg->handle = handle; + p_msg->attr_id = attr_id; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvDeleteRecord +** +** Description Delete a service record in the local SDP database. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvDeleteRecord(UINT32 handle) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_ADD_ATTRIBUTE *p_msg; + + APPL_TRACE_API0( "BTA_JvDeleteRecord"); + if ((p_msg = (tBTA_JV_API_ADD_ATTRIBUTE *)GKI_getbuf(sizeof(tBTA_JV_API_ADD_ATTRIBUTE))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_DELETE_RECORD_EVT; + p_msg->handle = handle; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvReadRecord +** +** Description Read a service record in the local SDP database. +** +** Returns -1, if the record is not found. +** Otherwise, the offset (0 or 1) to start of data in p_data. +** +** The size of data copied into p_data is in *p_data_len. +** +*******************************************************************************/ +INT32 BTA_JvReadRecord(UINT32 handle, UINT8 *p_data, INT32 *p_data_len) +{ + UINT32 sdp_handle; + + sdp_handle = bta_jv_get_sdp_handle(handle); + + if(sdp_handle) + { + return SDP_ReadRecord(sdp_handle, p_data, p_data_len); + } + + return -1; +} + +/******************************************************************************* +** +** Function BTA_JvL2capConnect +** +** Description Initiate a connection as a L2CAP client to the given BD +** Address. +** When the connection is initiated or failed to initiate, +** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT +** When the connection is established or failed, +** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvL2capConnect(tBTA_SEC sec_mask, + tBTA_JV_ROLE role, UINT16 remote_psm, UINT16 rx_mtu, + BD_ADDR peer_bd_addr, tBTA_JV_L2CAP_CBACK *p_cback) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_L2CAP_CONNECT *p_msg; + + APPL_TRACE_API0( "BTA_JvL2capConnect"); + if (p_cback && + (p_msg = (tBTA_JV_API_L2CAP_CONNECT *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CONNECT))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_EVT; + p_msg->sec_mask = sec_mask; + p_msg->role = role; + p_msg->remote_psm = remote_psm; + p_msg->rx_mtu = rx_mtu; + memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR)); + p_msg->p_cback = p_cback; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvL2capClose +** +** Description This function closes an L2CAP client connection +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvL2capClose(UINT32 handle) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_L2CAP_CLOSE *p_msg; + + APPL_TRACE_API0( "BTA_JvL2capClose"); + if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback && + (p_msg = (tBTA_JV_API_L2CAP_CLOSE *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_CLOSE))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_EVT; + p_msg->handle = handle; + p_msg->p_cb = &bta_jv_cb.l2c_cb[handle]; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvL2capStartServer +** +** Description This function starts an L2CAP server and listens for an L2CAP +** connection from a remote Bluetooth device. When the server +** is started successfully, tBTA_JV_L2CAP_CBACK is called with +** BTA_JV_L2CAP_START_EVT. When the connection is established, +** tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvL2capStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role, + UINT16 local_psm, UINT16 rx_mtu, + tBTA_JV_L2CAP_CBACK *p_cback) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_L2CAP_SERVER *p_msg; + + APPL_TRACE_API0( "BTA_JvL2capStartServer"); + if (p_cback && + (p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_EVT; + p_msg->sec_mask = sec_mask; + p_msg->role = role; + p_msg->local_psm = local_psm; + p_msg->rx_mtu = rx_mtu; + p_msg->p_cback = p_cback; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvL2capStopServer +** +** Description This function stops the L2CAP server. If the server has an +** active connection, it would be closed. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvL2capStopServer(UINT16 local_psm) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_L2CAP_SERVER *p_msg; + + APPL_TRACE_API0( "BTA_JvL2capStopServer"); + if ((p_msg = (tBTA_JV_API_L2CAP_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_SERVER))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_EVT; + p_msg->local_psm = local_psm; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvL2capRead +** +** Description This function reads data from an L2CAP connecti; + tBTA_JV_RFC_CB *p_cb = rc->p_cb; +on +** When the operation is complete, tBTA_JV_L2CAP_CBACK is +** called with BTA_JV_L2CAP_READ_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len) +{ +#if 0 + tBTA_JV_STATUS status = BTA_JV_FAILURE; +#if SDP_FOR_JV_INCLUDED == TRUE + tBTA_JV_API_L2CAP_READ *p_msg; +#endif + tBTA_JV_L2CAP_READ evt_data; + + APPL_TRACE_API0( "BTA_JvL2capRead"); + +#if SDP_FOR_JV_INCLUDED == TRUE + if(BTA_JV_L2C_FOR_SDP_HDL == handle) + { + if (bta_jv_cb.l2c_cb[handle].p_cback && + (p_msg = (tBTA_JV_API_L2CAP_READ *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_READ))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_L2CAP_READ_EVT; + p_msg->handle = handle; + p_msg->req_id = req_id; + p_msg->p_data = p_data; + p_msg->len = len; + p_msg->p_cback = bta_jv_cb.l2c_cb[handle].p_cback; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + } + else +#endif + if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) + { + status = BTA_JV_SUCCESS; + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = handle; + evt_data.req_id = req_id; + evt_data.p_data = p_data; + evt_data.len = 0; + + if (BT_PASS == GAP_ConnReadData((UINT16)handle, p_data, len, &evt_data.len)) + { + evt_data.status = BTA_JV_SUCCESS; + } + bta_jv_cb.l2c_cb[handle].p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV *)&evt_data); + } + + return(status); +#endif + return -1; +} + +/******************************************************************************* +** +** Function BTA_JvL2capReceive +** +** Description This function reads data from an L2CAP connection +** When the operation is complete, tBTA_JV_L2CAP_CBACK is +** called with BTA_JV_L2CAP_RECEIVE_EVT. +** If there are more data queued in L2CAP than len, the extra data will be discarded. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvL2capReceive(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len) +{ +#if 0 + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_L2CAP_RECEIVE evt_data; + UINT32 left_over = 0; + UINT16 max_len, read_len; + + APPL_TRACE_API0( "BTA_JvL2capReceive"); + + if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) + { + status = BTA_JV_SUCCESS; + evt_data.status = BTA_JV_FAILURE; + evt_data.handle = handle; + evt_data.req_id = req_id; + evt_data.p_data = p_data; + evt_data.len = 0; + + if (BT_PASS == GAP_ConnReadData((UINT16)handle, p_data, len, &evt_data.len)) + { + evt_data.status = BTA_JV_SUCCESS; + GAP_GetRxQueueCnt ((UINT16)handle, &left_over); + while (left_over) + { + max_len = (left_over > 0xFFFF)?0xFFFF:left_over; + GAP_ConnReadData ((UINT16)handle, NULL, max_len, &read_len); + left_over -= read_len; + } + } + bta_jv_cb.l2c_cb[handle].p_cback(BTA_JV_L2CAP_RECEIVE_EVT, (tBTA_JV *)&evt_data); + } + + return(status); +#endif + return -1; +} +/******************************************************************************* +** +** Function BTA_JvL2capReady +** +** Description This function determined if there is data to read from +** an L2CAP connection +** +** Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size. +** BTA_JV_FAILURE, if error. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvL2capReady(UINT32 handle, UINT32 *p_data_size) +{ +#if 0 + tBTA_JV_STATUS status = BTA_JV_FAILURE; + + APPL_TRACE_API1( "BTA_JvL2capReady: %d", handle); + if (p_data_size && handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) + { + *p_data_size = 0; +#if SDP_FOR_JV_INCLUDED == TRUE + if(BTA_JV_L2C_FOR_SDP_HDL == handle) + { + *p_data_size = bta_jv_cb.sdp_data_size; + status = BTA_JV_SUCCESS; + } + else +#endif + if(BT_PASS == GAP_GetRxQueueCnt((UINT16)handle, p_data_size) ) + { + status = BTA_JV_SUCCESS; + } + } + + return(status); +#endif + return -1; +} + + +/******************************************************************************* +** +** Function BTA_JvL2capWrite +** +** Description This function writes data to an L2CAP connection +** When the operation is complete, tBTA_JV_L2CAP_CBACK is +** called with BTA_JV_L2CAP_WRITE_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvL2capWrite(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_L2CAP_WRITE *p_msg; + + APPL_TRACE_API0( "BTA_JvL2capWrite"); + if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback && + (p_msg = (tBTA_JV_API_L2CAP_WRITE *)GKI_getbuf(sizeof(tBTA_JV_API_L2CAP_WRITE))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_EVT; + p_msg->handle = handle; + p_msg->req_id = req_id; + p_msg->p_data = p_data; + p_msg->p_cb = &bta_jv_cb.l2c_cb[handle]; + p_msg->len = len; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvRfcommConnect +** +** Description This function makes an RFCOMM conection to a remote BD +** Address. +** When the connection is initiated or failed to initiate, +** tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_CL_INIT_EVT +** When the connection is established or failed, +** tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_OPEN_EVT +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, + tBTA_JV_ROLE role, UINT8 remote_scn, BD_ADDR peer_bd_addr, + tBTA_JV_RFCOMM_CBACK *p_cback, void* user_data) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_RFCOMM_CONNECT *p_msg; + + APPL_TRACE_API0( "BTA_JvRfcommConnect"); + if (p_cback && + (p_msg = (tBTA_JV_API_RFCOMM_CONNECT *)GKI_getbuf(sizeof(tBTA_JV_API_RFCOMM_CONNECT))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_RFCOMM_CONNECT_EVT; + p_msg->sec_mask = sec_mask; + p_msg->role = role; + p_msg->remote_scn = remote_scn; + memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR)); + p_msg->p_cback = p_cback; + p_msg->user_data = user_data; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvRfcommClose +** +** Description This function closes an RFCOMM connection +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvRfcommClose(UINT32 handle) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_RFCOMM_CLOSE *p_msg; + UINT32 hi = (handle & BTA_JV_RFC_HDL_MASK) - 1; + UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(handle); + + APPL_TRACE_API0( "BTA_JvRfcommClose"); + if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback && + si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si] && + (p_msg = (tBTA_JV_API_RFCOMM_CLOSE *)GKI_getbuf(sizeof(tBTA_JV_API_RFCOMM_CLOSE))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_RFCOMM_CLOSE_EVT; + p_msg->handle = handle; + p_msg->p_cb = &bta_jv_cb.rfc_cb[hi]; + p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1]; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvRfcommStartServer +** +** Description This function starts listening for an RFCOMM connection +** request from a remote Bluetooth device. When the server is +** started successfully, tBTA_JV_RFCOMM_CBACK is called +** with BTA_JV_RFCOMM_START_EVT. +** When the connection is established, tBTA_JV_RFCOMM_CBACK +** is called with BTA_JV_RFCOMM_OPEN_EVT. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, + tBTA_JV_ROLE role, UINT8 local_scn, UINT8 max_session, + tBTA_JV_RFCOMM_CBACK *p_cback, void* user_data) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_RFCOMM_SERVER *p_msg; + + APPL_TRACE_API0( "BTA_JvRfcommStartServer"); + if (p_cback && + (p_msg = (tBTA_JV_API_RFCOMM_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_RFCOMM_SERVER))) != NULL) + { + if (max_session == 0) + max_session = 1; + if (max_session > BTA_JV_MAX_RFC_SR_SESSION) + { + APPL_TRACE_DEBUG2( "max_session is too big. use max (%d)", max_session, BTA_JV_MAX_RFC_SR_SESSION); + max_session = BTA_JV_MAX_RFC_SR_SESSION; + } + p_msg->hdr.event = BTA_JV_API_RFCOMM_START_SERVER_EVT; + p_msg->sec_mask = sec_mask; + p_msg->role = role; + p_msg->local_scn = local_scn; + p_msg->max_session = max_session; + p_msg->p_cback = p_cback; + p_msg->user_data = user_data; //caller's private data + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvRfcommStopServer +** +** Description This function stops the RFCOMM server. If the server has an +** active connection, it would be closed. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvRfcommStopServer(UINT32 handle) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_RFCOMM_SERVER *p_msg; + APPL_TRACE_API0( "BTA_JvRfcommStopServer"); + if ((p_msg = (tBTA_JV_API_RFCOMM_SERVER *)GKI_getbuf(sizeof(tBTA_JV_API_RFCOMM_SERVER))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_RFCOMM_STOP_SERVER_EVT; + p_msg->rfc_handle = handle; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvRfcommRead +** +** Description This function reads data from an RFCOMM connection +** The actual size of data read is returned in p_len. +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvRfcommRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_RFCOMM_READ *p_msg; + UINT32 hi = (handle & BTA_JV_RFC_HDL_MASK) - 1; + UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(handle); + + APPL_TRACE_API0( "BTA_JvRfcommRead"); + if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback && + si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si] && + (p_msg = (tBTA_JV_API_RFCOMM_READ *)GKI_getbuf(sizeof(tBTA_JV_API_RFCOMM_READ))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_RFCOMM_READ_EVT; + p_msg->handle = handle; + p_msg->req_id = req_id; + p_msg->p_data = p_data; + p_msg->len = len; + p_msg->p_cb = &bta_jv_cb.rfc_cb[hi]; + p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1]; + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvRfcommGetPortHdl +** +** Description This function fetches the rfcomm port handle +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +UINT16 BTA_JvRfcommGetPortHdl(UINT32 handle) +{ + UINT32 hi = (handle & BTA_JV_RFC_HDL_MASK) - 1; + UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(handle); + + if (hi < BTA_JV_MAX_RFC_CONN && + si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) + return bta_jv_cb.port_cb[bta_jv_cb.rfc_cb[hi].rfc_hdl[si] - 1].port_handle; + else + return 0xffff; +} + + +/******************************************************************************* +** +** Function BTA_JvRfcommReady +** +** Description This function determined if there is data to read from +** an RFCOMM connection +** +** Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size. +** BTA_JV_FAILURE, if error. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvRfcommReady(UINT32 handle, UINT32 *p_data_size) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + UINT16 size = 0; + UINT32 hi = (handle & BTA_JV_RFC_HDL_MASK) - 1; + UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(handle); + + APPL_TRACE_API0( "BTA_JvRfcommReady"); + if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback && + si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) + { + if(PORT_GetRxQueueCnt(bta_jv_cb.rfc_cb[hi].rfc_hdl[si], &size) == PORT_SUCCESS) + { + status = BTA_JV_SUCCESS; + } + } + *p_data_size = size; + return(status); +} + +/******************************************************************************* +** +** Function BTA_JvRfcommWrite +** +** Description This function writes data to an RFCOMM connection +** +** Returns BTA_JV_SUCCESS, if the request is being processed. +** BTA_JV_FAILURE, otherwise. +** +*******************************************************************************/ +tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id) +{ + tBTA_JV_STATUS status = BTA_JV_FAILURE; + tBTA_JV_API_RFCOMM_WRITE *p_msg; + UINT32 hi = (handle & BTA_JV_RFC_HDL_MASK) - 1; + UINT32 si = BTA_JV_RFC_HDL_TO_SIDX(handle); + + APPL_TRACE_API0( "BTA_JvRfcommWrite"); + APPL_TRACE_DEBUG3( "handle:0x%x, hi:%d, si:%d", handle, hi, si); + if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback && + si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si] && + (p_msg = (tBTA_JV_API_RFCOMM_WRITE *)GKI_getbuf(sizeof(tBTA_JV_API_RFCOMM_WRITE))) != NULL) + { + p_msg->hdr.event = BTA_JV_API_RFCOMM_WRITE_EVT; + p_msg->handle = handle; + p_msg->req_id = req_id; + p_msg->p_cb = &bta_jv_cb.rfc_cb[hi]; + p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1]; + APPL_TRACE_API0( "write ok"); + bta_sys_sendmsg(p_msg); + status = BTA_JV_SUCCESS; + } + + return(status); +} + diff --git a/bta/jv/bta_jv_cfg.c b/bta/jv/bta_jv_cfg.c new file mode 100644 index 0000000..675801f --- /dev/null +++ b/bta/jv/bta_jv_cfg.c @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * 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 file contains compile-time configurable constants for advanced + * audio + * + ******************************************************************************/ + +#include "gki.h" +#include "bta_api.h" +#include "bd.h" +#include "bta_jv_api.h" + +#ifndef BTA_JV_SDP_DB_SIZE +#define BTA_JV_SDP_DB_SIZE 4500 +#endif + +#ifndef BTA_JV_SDP_RAW_DATA_SIZE +#define BTA_JV_SDP_RAW_DATA_SIZE 1800 +#endif + +/* The platform may choose to use dynamic memory for these data buffers. + * p_bta_jv_cfg->p_sdp_db must be allocated/stay allocated + * between BTA_JvEnable and BTA_JvDisable + * p_bta_jv_cfg->p_sdp_raw_data can be allocated before calling BTA_JvStartDiscovery + * it can be de-allocated after the last call to access the database */ +static UINT8 bta_jv_sdp_raw_data[BTA_JV_SDP_RAW_DATA_SIZE]; +static UINT8 bta_jv_sdp_db_data[BTA_JV_SDP_DB_SIZE]; + +/* JV configuration structure */ +const tBTA_JV_CFG bta_jv_cfg = +{ + BTA_JV_SDP_RAW_DATA_SIZE, /* The size of p_sdp_raw_data */ + BTA_JV_SDP_DB_SIZE, /* The size of p_sdp_db_data */ + bta_jv_sdp_raw_data, /* The data buffer to keep raw data */ + (tSDP_DISCOVERY_DB *)bta_jv_sdp_db_data /* The data buffer to keep SDP database */ +}; + +tBTA_JV_CFG *p_bta_jv_cfg = (tBTA_JV_CFG *) &bta_jv_cfg; + + diff --git a/bta/jv/bta_jv_int.h b/bta/jv/bta_jv_int.h new file mode 100644 index 0000000..5a0aaed --- /dev/null +++ b/bta/jv/bta_jv_int.h @@ -0,0 +1,461 @@ +/****************************************************************************** + * + * Copyright (C) 2006-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 private interface file for the BTA Java I/F + * + ******************************************************************************/ +#ifndef BTA_JV_INT_H +#define BTA_JV_INT_H + +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_jv_api.h" +#include "rfcdefs.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +enum +{ + /* these events are handled by the state machine */ + BTA_JV_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_JV), + BTA_JV_API_DISABLE_EVT, + BTA_JV_API_SET_DISCOVERABILITY_EVT, + BTA_JV_API_GET_LOCAL_DEVICE_ADDR_EVT, + BTA_JV_API_GET_LOCAL_DEVICE_NAME_EVT, + BTA_JV_API_GET_REMOTE_DEVICE_NAME_EVT, + BTA_JV_API_SET_SERVICE_CLASS_EVT, + BTA_JV_API_SET_ENCRYPTION_EVT, + BTA_JV_API_GET_SCN_EVT, + BTA_JV_API_FREE_SCN_EVT, + BTA_JV_API_START_DISCOVERY_EVT, + BTA_JV_API_CANCEL_DISCOVERY_EVT, + BTA_JV_API_GET_SERVICES_LENGTH_EVT, + BTA_JV_API_SERVICE_SELECT_EVT, + BTA_JV_API_CREATE_RECORD_EVT, + BTA_JV_API_UPDATE_RECORD_EVT, + BTA_JV_API_ADD_ATTRIBUTE_EVT, + BTA_JV_API_DELETE_ATTRIBUTE_EVT, + BTA_JV_API_DELETE_RECORD_EVT, + BTA_JV_API_L2CAP_CONNECT_EVT, + BTA_JV_API_L2CAP_CLOSE_EVT, + BTA_JV_API_L2CAP_START_SERVER_EVT, + BTA_JV_API_L2CAP_STOP_SERVER_EVT, + BTA_JV_API_L2CAP_READ_EVT, + BTA_JV_API_L2CAP_WRITE_EVT, + BTA_JV_API_RFCOMM_CONNECT_EVT, + BTA_JV_API_RFCOMM_CLOSE_EVT, + BTA_JV_API_RFCOMM_START_SERVER_EVT, + BTA_JV_API_RFCOMM_STOP_SERVER_EVT, + BTA_JV_API_RFCOMM_READ_EVT, + BTA_JV_API_RFCOMM_WRITE_EVT, + BTA_JV_MAX_INT_EVT +}; + +/* data type for BTA_JV_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_JV_DM_CBACK *p_cback; +} tBTA_JV_API_ENABLE; + +/* data type for BTA_JV_API_SET_DISCOVERABILITY_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_JV_DISC disc_mode; +} tBTA_JV_API_SET_DISCOVERABILITY; + + +/* data type for BTA_JV_API_SET_SERVICE_CLASS_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT32 service; +} tBTA_JV_API_SET_SERVICE_CLASS; + +/* data type for BTA_JV_API_SET_ENCRYPTION_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_JV_API_SET_ENCRYPTION; + +/* data type for BTA_JV_API_GET_REMOTE_DEVICE_NAME_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_JV_API_GET_REMOTE_NAME; + +/* data type for BTA_JV_API_START_DISCOVERY_EVT */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR bd_addr; + UINT16 num_uuid; + tSDP_UUID uuid_list[BTA_JV_MAX_UUIDS]; + UINT16 num_attr; + UINT16 attr_list[BTA_JV_MAX_ATTRS]; + void *user_data; /* piggyback caller's private data*/ +} tBTA_JV_API_START_DISCOVERY; + +/* data type for BTA_JV_API_CANCEL_DISCOVERY_EVT */ +typedef struct +{ + BT_HDR hdr; + void *user_data; /* piggyback caller's private data*/ +} tBTA_JV_API_CANCEL_DISCOVERY; + + +/* data type for BTA_JV_API_GET_SERVICES_LENGTH_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 *p_services_len; + BOOLEAN inc_hdr; +} tBTA_JV_API_GET_SERVICES_LENGTH; + +/* data type for BTA_JV_API_GET_SERVICE_RESULT_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 **TLVs; +} tBTA_JV_API_GET_SERVICE_RESULT; + +/* data type for BTA_JV_API_SERVICE_SELECT_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 uuid; +} tBTA_JV_API_SERVICE_SELECT; + +enum +{ + BTA_JV_ST_NONE = 0, + BTA_JV_ST_CL_OPENING, + BTA_JV_ST_CL_OPEN, + BTA_JV_ST_CL_CLOSING, + BTA_JV_ST_SR_LISTEN, + BTA_JV_ST_SR_OPEN, + BTA_JV_ST_SR_CLOSING +} ; +typedef UINT8 tBTA_JV_STATE; +#define BTA_JV_ST_CL_MAX BTA_JV_ST_CL_CLOSING + +/* JV L2CAP control block */ +typedef struct +{ + tBTA_JV_L2CAP_CBACK *p_cback; /* the callback function */ + UINT16 psm; /* the psm used for this server connection */ + tBTA_JV_STATE state; /* the state of this control block */ + tBTA_SERVICE_ID sec_id; /* service id */ + UINT16 handle; /* the handle reported to java app (same as gap handle) */ + BOOLEAN cong; /* TRUE, if congested */ +} tBTA_JV_L2C_CB; + +#define BTA_JV_RFC_HDL_MASK 0xFF +#define BTA_JV_RFC_HDL_TO_SIDX(r) (((r)&0xFF00) >> 8) +#define BTA_JV_RFC_H_S_TO_HDL(h, s) ((h)|(s<<8)) + +/* port control block */ +typedef struct +{ + UINT32 handle; /* the rfcomm session handle at jv */ + UINT16 port_handle; /* port handle */ + tBTA_JV_STATE state; /* the state of this control block */ + UINT8 max_sess; /* max sessions */ + void *user_data; /* piggyback caller's private data*/ + BOOLEAN cong; /* TRUE, if congested */ +} tBTA_JV_PCB; + +/* JV RFCOMM control block */ +typedef struct +{ + tBTA_JV_RFCOMM_CBACK *p_cback; /* the callback function */ + UINT16 rfc_hdl[BTA_JV_MAX_RFC_SR_SESSION]; + tBTA_SERVICE_ID sec_id; /* service id */ + UINT8 handle; /* index: the handle reported to java app */ + UINT8 scn; /* the scn of the server */ + UINT8 max_sess; /* max sessions */ +} tBTA_JV_RFC_CB; + +/* data type for BTA_JV_API_L2CAP_CONNECT_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_SEC sec_mask; + tBTA_JV_ROLE role; + UINT16 remote_psm; + UINT16 rx_mtu; + BD_ADDR peer_bd_addr; + tBTA_JV_L2CAP_CBACK *p_cback; +} tBTA_JV_API_L2CAP_CONNECT; + +/* data type for BTA_JV_API_L2CAP_SERVER_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_SEC sec_mask; + tBTA_JV_ROLE role; + UINT16 local_psm; + UINT16 rx_mtu; + tBTA_JV_L2CAP_CBACK *p_cback; +} tBTA_JV_API_L2CAP_SERVER; + +/* data type for BTA_JV_API_L2CAP_CLOSE_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 handle; + tBTA_JV_L2C_CB *p_cb; +} tBTA_JV_API_L2CAP_CLOSE; + +/* data type for BTA_JV_API_L2CAP_READ_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 handle; + UINT32 req_id; + tBTA_JV_L2CAP_CBACK *p_cback; + UINT8* p_data; + UINT16 len; +} tBTA_JV_API_L2CAP_READ; + +/* data type for BTA_JV_API_L2CAP_WRITE_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 handle; + UINT32 req_id; + tBTA_JV_L2C_CB *p_cb; + UINT8 *p_data; + UINT16 len; +} tBTA_JV_API_L2CAP_WRITE; + +/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_SEC sec_mask; + tBTA_JV_ROLE role; + UINT8 remote_scn; + BD_ADDR peer_bd_addr; + tBTA_JV_RFCOMM_CBACK *p_cback; + void *user_data; +} tBTA_JV_API_RFCOMM_CONNECT; + +/* data type for BTA_JV_API_RFCOMM_SERVER_EVT */ +typedef struct +{ + BT_HDR hdr; + tBTA_SEC sec_mask; + tBTA_JV_ROLE role; + UINT8 local_scn; + UINT8 max_session; + int rfc_handle; + tBTA_JV_RFCOMM_CBACK *p_cback; + void *user_data; +} tBTA_JV_API_RFCOMM_SERVER; + +/* data type for BTA_JV_API_RFCOMM_READ_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 handle; + UINT32 req_id; + UINT8 *p_data; + UINT16 len; + tBTA_JV_RFC_CB *p_cb; + tBTA_JV_PCB *p_pcb; +} tBTA_JV_API_RFCOMM_READ; + +/* data type for BTA_JV_API_RFCOMM_WRITE_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 handle; + UINT32 req_id; + UINT8 *p_data; + int len; + tBTA_JV_RFC_CB *p_cb; + tBTA_JV_PCB *p_pcb; +} tBTA_JV_API_RFCOMM_WRITE; + +/* data type for BTA_JV_API_RFCOMM_CLOSE_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT16 handle; + tBTA_JV_RFC_CB *p_cb; + tBTA_JV_PCB *p_pcb; +} tBTA_JV_API_RFCOMM_CLOSE; + +/* data type for BTA_JV_API_CREATE_RECORD_EVT */ +typedef struct +{ + BT_HDR hdr; + void *user_data; +} tBTA_JV_API_CREATE_RECORD; + +/* data type for BTA_JV_API_UPDATE_RECORD_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT32 handle; + UINT16 *p_ids; + UINT8 **p_values; + INT32 *p_value_sizes; + INT32 array_len; +} tBTA_JV_API_UPDATE_RECORD; + +/* data type for BTA_JV_API_ADD_ATTRIBUTE_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT32 handle; + UINT16 attr_id; + UINT8 *p_value; + INT32 value_size; +} tBTA_JV_API_ADD_ATTRIBUTE; + +/* data type for BTA_JV_API_FREE_SCN_EVT */ +typedef struct +{ + BT_HDR hdr; + UINT8 scn; +} tBTA_JV_API_FREE_SCN; +/* union of all data types */ +typedef union +{ + /* GKI event buffer header */ + BT_HDR hdr; + tBTA_JV_API_ENABLE enable; + tBTA_JV_API_SET_DISCOVERABILITY set_discoverability; + tBTA_JV_API_GET_REMOTE_NAME get_rmt_name; + tBTA_JV_API_SET_SERVICE_CLASS set_service; + tBTA_JV_API_SET_ENCRYPTION set_encrypt; + tBTA_JV_API_START_DISCOVERY start_discovery; + tBTA_JV_API_CANCEL_DISCOVERY cancel_discovery; + tBTA_JV_API_GET_SERVICES_LENGTH get_services_length; + tBTA_JV_API_GET_SERVICE_RESULT get_service_result; + tBTA_JV_API_SERVICE_SELECT service_select; + tBTA_JV_API_FREE_SCN free_scn; + tBTA_JV_API_CREATE_RECORD create_record; + tBTA_JV_API_UPDATE_RECORD update_record; + tBTA_JV_API_ADD_ATTRIBUTE add_attr; + tBTA_JV_API_L2CAP_CONNECT l2cap_connect; + tBTA_JV_API_L2CAP_READ l2cap_read; + tBTA_JV_API_L2CAP_WRITE l2cap_write; + tBTA_JV_API_L2CAP_CLOSE l2cap_close; + tBTA_JV_API_L2CAP_SERVER l2cap_server; + tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect; + tBTA_JV_API_RFCOMM_READ rfcomm_read; + tBTA_JV_API_RFCOMM_WRITE rfcomm_write; + tBTA_JV_API_RFCOMM_CLOSE rfcomm_close; + tBTA_JV_API_RFCOMM_SERVER rfcomm_server; +} tBTA_JV_MSG; + +#if SDP_FOR_JV_INCLUDED == TRUE +#define BTA_JV_L2C_FOR_SDP_HDL GAP_MAX_CONNECTIONS +#endif + +/* JV control block */ +typedef struct +{ +#if SDP_FOR_JV_INCLUDED == TRUE + UINT32 sdp_for_jv; /* The SDP client connection handle */ + UINT32 sdp_data_size; /* the data len */ +#endif + /* the SDP handle reported to JV user is the (index + 1) to sdp_handle[]. + * if sdp_handle[i]==0, it's not used. + * otherwise sdp_handle[i] is the stack SDP handle. */ + UINT32 sdp_handle[BTA_JV_MAX_SDP_REC]; /* SDP records created */ + UINT8 *p_sel_raw_data;/* the raw data of last service select */ + INT32 sel_len; /* the SDP record size of last service select */ + tBTA_JV_DM_CBACK *p_dm_cback; + tBTA_JV_L2C_CB l2c_cb[BTA_JV_MAX_L2C_CONN]; /* index is GAP handle (index) */ + tBTA_JV_RFC_CB rfc_cb[BTA_JV_MAX_RFC_CONN]; + tBTA_JV_PCB port_cb[MAX_RFC_PORTS]; /* index of this array is the port_handle, */ + UINT8 sec_id[BTA_JV_NUM_SERVICE_ID]; /* service ID */ + BOOLEAN scn[BTA_JV_MAX_SCN]; /* SCN allocated by java */ + UINT8 sdp_active; /* see BTA_JV_SDP_ACT_* */ + tSDP_UUID uuid; /* current uuid of sdp discovery*/ + void *user_data; /* piggyback user data*/ +} tBTA_JV_CB; + +enum +{ + BTA_JV_SDP_ACT_NONE = 0, + BTA_JV_SDP_ACT_YES, /* waiting for SDP result */ + BTA_JV_SDP_ACT_CANCEL /* waiting for cancel complete */ +}; + +/* JV control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_JV_CB bta_jv_cb; +#else +extern tBTA_JV_CB *bta_jv_cb_ptr; +#define bta_jv_cb (*bta_jv_cb_ptr) +#endif + +/* config struct */ +extern tBTA_JV_CFG *p_bta_jv_cfg; + +/* this is defined in stack/sdp. used by bta jv */ +extern UINT8 *sdpu_get_len_from_type (UINT8 *p, UINT8 type, UINT32 *p_len); + +extern BOOLEAN bta_jv_sm_execute(BT_HDR *p_msg); + +extern UINT32 bta_jv_get_sdp_handle(UINT32 sdp_id); +extern void bta_jv_enable (tBTA_JV_MSG *p_data); +extern void bta_jv_disable (tBTA_JV_MSG *p_data); +extern void bta_jv_set_discoverability (tBTA_JV_MSG *p_data); +extern void bta_jv_get_local_device_addr (tBTA_JV_MSG *p_data); +extern void bta_jv_get_local_device_name (tBTA_JV_MSG *p_data); +extern void bta_jv_get_remote_device_name (tBTA_JV_MSG *p_data); +extern void bta_jv_set_service_class (tBTA_JV_MSG *p_data); +extern void bta_jv_set_encryption (tBTA_JV_MSG *p_data); +extern void bta_jv_get_scn (tBTA_JV_MSG *p_data); +extern void bta_jv_free_scn (tBTA_JV_MSG *p_data); +extern void bta_jv_start_discovery (tBTA_JV_MSG *p_data); +extern void bta_jv_cancel_discovery (tBTA_JV_MSG *p_data); +extern void bta_jv_get_services_length (tBTA_JV_MSG *p_data); +extern void bta_jv_service_select (tBTA_JV_MSG *p_data); +extern void bta_jv_create_record (tBTA_JV_MSG *p_data); +extern void bta_jv_update_record (tBTA_JV_MSG *p_data); +extern void bta_jv_add_attribute (tBTA_JV_MSG *p_data); +extern void bta_jv_delete_attribute (tBTA_JV_MSG *p_data); +extern void bta_jv_delete_record (tBTA_JV_MSG *p_data); +extern void bta_jv_l2cap_connect (tBTA_JV_MSG *p_data); +extern void bta_jv_l2cap_close (tBTA_JV_MSG *p_data); +extern void bta_jv_l2cap_start_server (tBTA_JV_MSG *p_data); +extern void bta_jv_l2cap_stop_server (tBTA_JV_MSG *p_data); +extern void bta_jv_l2cap_read (tBTA_JV_MSG *p_data); +extern void bta_jv_l2cap_write (tBTA_JV_MSG *p_data); +extern void bta_jv_rfcomm_connect (tBTA_JV_MSG *p_data); +extern void bta_jv_rfcomm_close (tBTA_JV_MSG *p_data); +extern void bta_jv_rfcomm_start_server (tBTA_JV_MSG *p_data); +extern void bta_jv_rfcomm_stop_server (tBTA_JV_MSG *p_data); +extern void bta_jv_rfcomm_read (tBTA_JV_MSG *p_data); +extern void bta_jv_rfcomm_write (tBTA_JV_MSG *p_data); + +#endif /* BTA_JV_INT_H */ diff --git a/bta/jv/bta_jv_main.c b/bta/jv/bta_jv_main.c new file mode 100644 index 0000000..0cba56b --- /dev/null +++ b/bta/jv/bta_jv_main.c @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * Copyright (C) 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 main implementation file for the BTA Java I/F + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_jv_api.h" +#include "bta_jv_int.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_JV_CB bta_jv_cb; +#endif + +/* state machine action enumeration list */ +#define BTA_JV_NUM_ACTIONS (BTA_JV_MAX_INT_EVT & 0x00ff) + +/* type for action functions */ +typedef void (*tBTA_JV_ACTION)(tBTA_JV_MSG *p_data); + +/* action function list */ +const tBTA_JV_ACTION bta_jv_action[] = +{ + bta_jv_enable, /* BTA_JV_API_ENABLE_EVT */ + bta_jv_disable, /* BTA_JV_API_DISABLE_EVT */ + bta_jv_set_discoverability, /* BTA_JV_API_SET_DISCOVERABILITY_EVT */ + bta_jv_get_local_device_addr, /* BTA_JV_API_GET_LOCAL_DEVICE_ADDR_EVT */ + bta_jv_get_local_device_name, /* BTA_JV_API_GET_LOCAL_DEVICE_NAME_EVT */ + bta_jv_get_remote_device_name, /* BTA_JV_API_GET_REMOTE_DEVICE_NAME_EVT */ + bta_jv_set_service_class, /* BTA_JV_API_SET_SERVICE_CLASS_EVT */ + bta_jv_set_encryption, /* BTA_JV_API_SET_ENCRYPTION_EVT */ + bta_jv_get_scn, /* BTA_JV_API_GET_SCN_EVT */ + bta_jv_free_scn, /* BTA_JV_API_FREE_SCN_EVT */ + bta_jv_start_discovery, /* BTA_JV_API_START_DISCOVERY_EVT */ + bta_jv_cancel_discovery, /* BTA_JV_API_CANCEL_DISCOVERY_EVT */ + bta_jv_get_services_length, /* BTA_JV_API_GET_SERVICES_LENGTH_EVT */ + bta_jv_service_select, /* BTA_JV_API_SERVICE_SELECT_EVT */ + bta_jv_create_record, /* BTA_JV_API_CREATE_RECORD_EVT */ + bta_jv_update_record, /* BTA_JV_API_UPDATE_RECORD_EVT */ + bta_jv_add_attribute, /* BTA_JV_API_ADD_ATTRIBUTE_EVT */ + bta_jv_delete_attribute, /* BTA_JV_API_DELETE_ATTRIBUTE_EVT */ + bta_jv_delete_record, /* BTA_JV_API_DELETE_RECORD_EVT */ + bta_jv_l2cap_connect, /* BTA_JV_API_L2CAP_CONNECT_EVT */ + bta_jv_l2cap_close, /* BTA_JV_API_L2CAP_CLOSE_EVT */ + bta_jv_l2cap_start_server, /* BTA_JV_API_L2CAP_START_SERVER_EVT */ + bta_jv_l2cap_stop_server, /* BTA_JV_API_L2CAP_STOP_SERVER_EVT */ + bta_jv_l2cap_read, /* BTA_JV_API_L2CAP_READ_EVT */ + bta_jv_l2cap_write, /* BTA_JV_API_L2CAP_WRITE_EVT */ + bta_jv_rfcomm_connect, /* BTA_JV_API_RFCOMM_CONNECT_EVT */ + bta_jv_rfcomm_close, /* BTA_JV_API_RFCOMM_CLOSE_EVT */ + bta_jv_rfcomm_start_server, /* BTA_JV_API_RFCOMM_START_SERVER_EVT */ + bta_jv_rfcomm_stop_server, /* BTA_JV_API_RFCOMM_STOP_SERVER_EVT */ + bta_jv_rfcomm_read, /* BTA_JV_API_RFCOMM_READ_EVT */ + bta_jv_rfcomm_write /* BTA_JV_API_RFCOMM_WRITE_EVT */ +}; + +/******************************************************************************* +** +** Function bta_jv_sm_execute +** +** Description State machine event handling function for JV +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_jv_sm_execute(BT_HDR *p_msg) +{ + BOOLEAN ret = FALSE; + UINT16 action = (p_msg->event & 0x00ff); + /* execute action functions */ + + if(action < BTA_JV_NUM_ACTIONS) + { + (*bta_jv_action[action])((tBTA_JV_MSG*)p_msg); + ret = TRUE; + } + + return(ret); +} diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c new file mode 100644 index 0000000..b29920f --- /dev/null +++ b/bta/pan/bta_pan_act.c @@ -0,0 +1,728 @@ +/****************************************************************************** + * + * 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 file contains the pan action functions for the state machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(PAN_INCLUDED) && (PAN_INCLUDED == TRUE) + +#include "bta_api.h" +#include "bta_sys.h" +#include "bd.h" +#include "gki.h" +#include "pan_api.h" +#include "bta_pan_api.h" +#include "bta_pan_int.h" +#include "bta_pan_co.h" +#include <string.h> + + +/* RX and TX data flow mask */ +#define BTA_PAN_RX_MASK 0x0F +#define BTA_PAN_TX_MASK 0xF0 + +/******************************************************************************* +** +** Function bta_pan_conn_state_cback +** +** Description Connection state callback from Pan profile +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_conn_state_cback(UINT16 handle, BD_ADDR bd_addr, tPAN_RESULT state, + BOOLEAN is_role_change, UINT8 src_role, UINT8 dst_role) +{ + + tBTA_PAN_CONN * p_buf; + tBTA_PAN_SCB *p_scb; + + + if ((p_buf = (tBTA_PAN_CONN *) GKI_getbuf(sizeof(tBTA_PAN_CONN))) != NULL) + { + if((state == PAN_SUCCESS) && !is_role_change) + { + p_buf->hdr.event = BTA_PAN_CONN_OPEN_EVT; + if((p_scb = bta_pan_scb_by_handle(handle)) == NULL) + { + /* allocate an scb */ + p_scb = bta_pan_scb_alloc(); + + } + /* we have exceeded maximum number of connections */ + if(!p_scb) + { + PAN_Disconnect (handle); + return; + } + + p_scb->handle = handle; + p_scb->local_role = src_role; + p_scb->peer_role = dst_role; + p_scb->pan_flow_enable = TRUE; + bdcpy(p_scb->bd_addr, bd_addr); + GKI_init_q(&p_scb->data_queue); + + if(src_role == PAN_ROLE_CLIENT) + p_scb->app_id = bta_pan_cb.app_id[0]; + else if (src_role == PAN_ROLE_GN_SERVER) + p_scb->app_id = bta_pan_cb.app_id[1]; + else if (src_role == PAN_ROLE_NAP_SERVER) + p_scb->app_id = bta_pan_cb.app_id[2]; + + } + else if((state != PAN_SUCCESS) && !is_role_change) + { + p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT; + + } + else + { + return; + } + + p_buf->result = state; + p_buf->hdr.layer_specific = handle; + bta_sys_sendmsg(p_buf); + + } + + + +} + +/******************************************************************************* +** +** Function bta_pan_data_flow_cb +** +** Description Data flow status callback from PAN +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_data_flow_cb(UINT16 handle, tPAN_RESULT result) +{ + BT_HDR *p_buf; + tBTA_PAN_SCB *p_scb; + + if((p_scb = bta_pan_scb_by_handle(handle)) == NULL) + return; + + if(result == PAN_TX_FLOW_ON) + { + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->layer_specific = handle; + p_buf->event = BTA_PAN_BNEP_FLOW_ENABLE_EVT; + bta_sys_sendmsg(p_buf); + } + bta_pan_co_rx_flow(handle, p_scb->app_id, TRUE); + + } + else if(result == PAN_TX_FLOW_OFF) + { + + p_scb->pan_flow_enable = FALSE; + bta_pan_co_rx_flow(handle, p_scb->app_id, FALSE); + + } + + +} + + +/******************************************************************************* +** +** Function bta_pan_data_buf_ind_cback +** +** Description data indication callback from pan profile +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_data_buf_ind_cback(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16 protocol, BT_HDR *p_buf, + BOOLEAN ext, BOOLEAN forward) +{ + tBTA_PAN_SCB *p_scb; + BT_HDR * p_event; + BT_HDR *p_new_buf; + + if ( sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset ) + { + /* offset smaller than data structure in front of actual data */ + p_new_buf = (BT_HDR *)GKI_getpoolbuf( PAN_POOL_ID ); + if(!p_new_buf) + { + APPL_TRACE_WARNING0("Cannot get a PAN GKI buffer"); + GKI_freebuf( p_buf ); + return; + } + else + { + memcpy( (UINT8 *)(p_new_buf+1)+sizeof(tBTA_PAN_DATA_PARAMS), (UINT8 *)(p_buf+1)+p_buf->offset, p_buf->len ); + p_new_buf->len = p_buf->len; + p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS); + GKI_freebuf( p_buf ); + } + } + else + { + p_new_buf = p_buf; + } + /* copy params into the space before the data */ + bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->src, src); + bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->dst, dst); + ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->protocol = protocol; + ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->ext = ext; + ((tBTA_PAN_DATA_PARAMS *)p_new_buf)->forward = forward; + + + if((p_scb = bta_pan_scb_by_handle(handle)) == NULL) + { + + GKI_freebuf( p_new_buf ); + return; + } + + GKI_enqueue(&p_scb->data_queue, p_new_buf); + if ((p_event = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_event->layer_specific = handle; + p_event->event = BTA_PAN_RX_FROM_BNEP_READY_EVT; + bta_sys_sendmsg(p_event); + } + +} + + +/******************************************************************************* +** +** Function bta_pan_pfilt_ind_cback +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_pfilt_ind_cback(UINT16 handle, BOOLEAN indication,tBNEP_RESULT result, + UINT16 num_filters, UINT8 *p_filters) +{ + + bta_pan_co_pfilt_ind(handle, indication, (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS : BTA_PAN_FAIL), + num_filters, p_filters); + + +} + + +/******************************************************************************* +** +** Function bta_pan_mfilt_ind_cback +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_mfilt_ind_cback(UINT16 handle, BOOLEAN indication,tBNEP_RESULT result, + UINT16 num_mfilters, UINT8 *p_mfilters) +{ + + bta_pan_co_mfilt_ind(handle, indication, (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS : BTA_PAN_FAIL), + num_mfilters, p_mfilters); +} + + + +/******************************************************************************* +** +** Function bta_pan_enable +** +** Description +** +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_enable(tBTA_PAN_DATA *p_data) +{ + tPAN_REGISTER reg_data; + UINT16 initial_discoverability; + UINT16 initial_connectability; + UINT16 d_window; + UINT16 d_interval; + UINT16 c_window; + UINT16 c_interval; + + bta_pan_cb.p_cback = p_data->api_enable.p_cback; + + reg_data.pan_conn_state_cb = bta_pan_conn_state_cback; + reg_data.pan_bridge_req_cb = NULL; + reg_data.pan_data_buf_ind_cb = bta_pan_data_buf_ind_cback; + reg_data.pan_data_ind_cb = NULL; + reg_data.pan_pfilt_ind_cb = bta_pan_pfilt_ind_cback; + reg_data.pan_mfilt_ind_cb = bta_pan_mfilt_ind_cback; + reg_data.pan_tx_data_flow_cb = bta_pan_data_flow_cb; + + /* read connectability and discoverability settings. + Pan profile changes the settings. We have to change it back to + be consistent with other bta subsystems */ + initial_connectability = BTM_ReadConnectability(&c_window, &c_interval); + initial_discoverability = BTM_ReadDiscoverability(&d_window, &d_interval); + + + PAN_Register (®_data); + + + /* set it back to original value */ + BTM_SetDiscoverability(initial_discoverability, d_window, d_interval); + BTM_SetConnectability(initial_connectability, c_window, c_interval); + + bta_pan_cb.flow_mask = bta_pan_co_init(&bta_pan_cb.q_level); + bta_pan_cb.p_cback(BTA_PAN_ENABLE_EVT, NULL); + +} + +/******************************************************************************* +** +** Function bta_pan_set_role +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_pan_set_role(tBTA_PAN_DATA *p_data) +{ + tPAN_RESULT status; + tBTA_PAN_SET_ROLE set_role; + UINT8 sec[3]; + + + bta_pan_cb.app_id[0] = p_data->api_set_role.user_app_id; + bta_pan_cb.app_id[1] = p_data->api_set_role.gn_app_id; + bta_pan_cb.app_id[2] = p_data->api_set_role.nap_app_id; + + sec[0] = p_data->api_set_role.user_sec_mask; + sec[1] = p_data->api_set_role.gn_sec_mask; + sec[2] = p_data->api_set_role.nap_sec_mask; + + /* set security correctly in api and here */ + status = PAN_SetRole(p_data->api_set_role.role, sec, + p_data->api_set_role.user_name, + p_data->api_set_role.gn_name, + p_data->api_set_role.nap_name); + + set_role.role = p_data->api_set_role.role; + if(status == PAN_SUCCESS) + { + if(p_data->api_set_role.role & PAN_ROLE_NAP_SERVER ) + bta_sys_add_uuid(UUID_SERVCLASS_NAP); + else + bta_sys_remove_uuid(UUID_SERVCLASS_NAP); + + if(p_data->api_set_role.role & PAN_ROLE_GN_SERVER ) + bta_sys_add_uuid(UUID_SERVCLASS_GN); + else + bta_sys_remove_uuid(UUID_SERVCLASS_GN); + + if(p_data->api_set_role.role & PAN_ROLE_CLIENT ) + bta_sys_add_uuid(UUID_SERVCLASS_PANU); + else + bta_sys_remove_uuid(UUID_SERVCLASS_PANU); + + set_role.status = BTA_PAN_SUCCESS; + } + /* if status is not success clear everything */ + else + { + PAN_SetRole(0, 0, NULL, NULL, NULL); + bta_sys_remove_uuid(UUID_SERVCLASS_NAP); + bta_sys_remove_uuid(UUID_SERVCLASS_GN); + bta_sys_remove_uuid(UUID_SERVCLASS_PANU); + set_role.status = BTA_PAN_FAIL; + } + bta_pan_cb.p_cback(BTA_PAN_SET_ROLE_EVT, (tBTA_PAN *)&set_role); +} + + + +/******************************************************************************* +** +** Function bta_pan_disable +** +** Description +** +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_disable(void) +{ + + BT_HDR *p_buf; + tBTA_PAN_SCB *p_scb = &bta_pan_cb.scb[0]; + UINT8 i; + + + /* close all connections */ + PAN_SetRole (0, NULL, NULL, NULL, NULL); + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) + bta_sys_remove_uuid(UUID_SERVCLASS_NAP); + bta_sys_remove_uuid(UUID_SERVCLASS_GN); + bta_sys_remove_uuid(UUID_SERVCLASS_PANU); +#endif + /* free all queued up data buffers */ + for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) + { + if (p_scb->in_use) + { + while((p_buf = (BT_HDR *)GKI_dequeue(&p_scb->data_queue)) != NULL) + GKI_freebuf(p_buf); + + bta_pan_co_close(p_scb->handle, p_scb->app_id); + + } + } + + + + PAN_Deregister(); + +} + +/******************************************************************************* +** +** Function bta_pan_open +** +** Description +** +** Returns void +** +*******************************************************************************/ +void bta_pan_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + tPAN_RESULT status; + tBTA_PAN_OPEN data; + tBTA_PAN_OPENING opening; + + + status = PAN_Connect (p_data->api_open.bd_addr, p_data->api_open.local_role, p_data->api_open.peer_role, + &p_scb->handle); + + + if(status == PAN_SUCCESS) + { + + bdcpy(p_scb->bd_addr, p_data->api_open.bd_addr); + p_scb->local_role = p_data->api_open.local_role; + p_scb->peer_role = p_data->api_open.peer_role; + bdcpy(opening.bd_addr, p_data->api_open.bd_addr); + opening.handle = p_scb->handle; + bta_pan_cb.p_cback(BTA_PAN_OPENING_EVT, (tBTA_PAN *)&opening); + + + } + else + { + bta_pan_scb_dealloc(p_scb); + bdcpy(data.bd_addr, p_data->api_open.bd_addr); + data.status = BTA_PAN_FAIL; + bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data); + } + +} + + +/******************************************************************************* +** +** Function bta_pan_close +** +** Description +** +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_api_close (tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + tBTA_PAN_CONN * p_buf; + + PAN_Disconnect (p_scb->handle); + + + /* send an event to BTA so that application will get the connection + close event */ + if ((p_buf = (tBTA_PAN_CONN *) GKI_getbuf(sizeof(tBTA_PAN_CONN))) != NULL) + { + p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT; + + p_buf->hdr.layer_specific = p_scb->handle; + bta_sys_sendmsg(p_buf); + + } +} + + +/******************************************************************************* +** +** Function bta_pan_conn_open +** +** Description process connection open event +** +** Returns void +** +*******************************************************************************/ +void bta_pan_conn_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + + tBTA_PAN_OPEN data; + + bdcpy(data.bd_addr, p_scb->bd_addr); + data.handle = p_scb->handle; + data.local_role = p_scb->local_role; + data.peer_role = p_scb->peer_role; + + if(p_data->conn.result == PAN_SUCCESS) + { + data.status = BTA_PAN_SUCCESS; + bta_pan_co_open(p_scb->handle, p_scb->app_id, p_scb->local_role, p_scb->peer_role, p_scb->bd_addr); + + } + else + { + bta_pan_scb_dealloc(p_scb); + data.status = BTA_PAN_FAIL; + } + + p_scb->pan_flow_enable = TRUE; + p_scb->app_flow_enable = TRUE; + + bta_sys_conn_open( BTA_ID_PAN ,p_scb->app_id, p_scb->bd_addr); + + bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data); + + +} + +/******************************************************************************* +** +** Function bta_pan_conn_close +** +** Description process connection close event +** +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_conn_close(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + + tBTA_PAN_CLOSE data; + BT_HDR *p_buf; + + data.handle = p_data->hdr.layer_specific; + + + bta_sys_conn_close( BTA_ID_PAN ,p_scb->app_id, p_scb->bd_addr); + + /* free all queued up data buffers */ + while((p_buf = (BT_HDR *)GKI_dequeue(&p_scb->data_queue)) != NULL) + GKI_freebuf(p_buf); + + GKI_init_q(&p_scb->data_queue); + + bta_pan_co_close(p_scb->handle, p_scb->app_id); + + bta_pan_scb_dealloc(p_scb); + + bta_pan_cb.p_cback(BTA_PAN_CLOSE_EVT, (tBTA_PAN *)&data); + +} + + + + +/******************************************************************************* +** +** Function bta_pan_rx_path +** +** Description Handle data on the RX path (data sent from the phone to +** BTA). +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_rx_path(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + /* if data path configured for rx pull */ + if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PULL) + { + /* if we can accept data */ + if (p_scb->pan_flow_enable == TRUE) + { + /* call application callout function for rx path */ + bta_pan_co_rx_path(p_scb->handle, p_scb->app_id); + } + } + /* else data path configured for rx push */ + else + { + + } +} + +/******************************************************************************* +** +** Function bta_pan_tx_path +** +** Description Handle the TX data path (data sent from BTA to the phone). +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_tx_path(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + + BT_HDR * p_buf; + /* if data path configured for tx pull */ + if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PULL) + { + /* call application callout function for tx path */ + bta_pan_co_tx_path(p_scb->handle, p_scb->app_id); + + /* free data that exceeds queue level */ + while(p_scb->data_queue.count > bta_pan_cb.q_level) + GKI_freebuf(GKI_dequeue(&p_scb->data_queue)); + } + /* if configured for zero copy push */ + else if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PUSH_BUF) + { + /* if app can accept data */ + if (p_scb->app_flow_enable == TRUE) + { + /* read data from the queue */ + if ((p_buf = (BT_HDR *)GKI_dequeue(&p_scb->data_queue)) != NULL) + { + /* send data to application */ + bta_pan_co_tx_writebuf(p_scb->handle, + p_scb->app_id, + ((tBTA_PAN_DATA_PARAMS *)p_buf)->src, + ((tBTA_PAN_DATA_PARAMS *)p_buf)->dst, + ((tBTA_PAN_DATA_PARAMS *)p_buf)->protocol, + p_buf, + ((tBTA_PAN_DATA_PARAMS *)p_buf)->ext, + ((tBTA_PAN_DATA_PARAMS *)p_buf)->forward); + + } + /* free data that exceeds queue level */ + while(p_scb->data_queue.count > bta_pan_cb.q_level) + GKI_freebuf(GKI_dequeue(&p_scb->data_queue)); + + /* if there is more data to be passed to + upper layer */ + if(p_scb->data_queue.count) + { + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->layer_specific = p_scb->handle; + p_buf->event = BTA_PAN_RX_FROM_BNEP_READY_EVT; + bta_sys_sendmsg(p_buf); + } + + } + + } + } +} + +/******************************************************************************* +** +** Function bta_pan_tx_flow +** +** Description Set the application flow control state. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_tx_flow(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + p_scb->app_flow_enable = p_data->ci_tx_flow.enable; +} + +/******************************************************************************* +** +** Function bta_pan_write_buf +** +** Description Handle a bta_pan_ci_rx_writebuf() and send data to PAN. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_write_buf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PUSH_BUF) + { + + PAN_WriteBuf (p_scb->handle, + ((tBTA_PAN_DATA_PARAMS *)p_data)->dst, + ((tBTA_PAN_DATA_PARAMS *)p_data)->src, + ((tBTA_PAN_DATA_PARAMS *)p_data)->protocol, + (BT_HDR *)p_data, + ((tBTA_PAN_DATA_PARAMS *)p_data)->ext); + + } +} + +/******************************************************************************* +** +** Function bta_pan_free_buf +** +** Description Frees the data buffer during closing state +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_free_buf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data) +{ + + GKI_freebuf(p_data); + +} + +#endif /* PAN_INCLUDED */ diff --git a/bta/pan/bta_pan_api.c b/bta/pan/bta_pan_api.c new file mode 100644 index 0000000..6588230 --- /dev/null +++ b/bta/pan/bta_pan_api.c @@ -0,0 +1,214 @@ +/****************************************************************************** + * + * 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 implementation of the API for PAN subsystem of BTA, + * Broadcom's Bluetooth application layer for mobile phones. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_PAN_INCLUDED) && (BTA_PAN_INCLUDED == TRUE) + +#include "bta_api.h" +#include "bta_sys.h" +#include "pan_api.h" +#include "gki.h" +#include "bta_pan_api.h" +#include "bta_pan_int.h" +#include "bd.h" +#include <string.h> + +static const tBTA_SYS_REG bta_pan_reg = +{ + bta_pan_hdl_event, + BTA_PanDisable +}; + +/******************************************************************************* +** +** Function BTA_PanEnable +** +** Description Enable PAN service. This function must be +** called before any other functions in the PAN API are called. +** When the enable operation is complete the callback function +** will be called with a BTA_PAN_ENABLE_EVT. +** +** Returns void +** +*******************************************************************************/ +void BTA_PanEnable(tBTA_PAN_CBACK p_cback) +{ + tBTA_PAN_API_ENABLE *p_buf; + + /* register with BTA system manager */ + GKI_sched_lock(); + bta_sys_register(BTA_ID_PAN, &bta_pan_reg); + GKI_sched_unlock(); + + if ((p_buf = (tBTA_PAN_API_ENABLE *) GKI_getbuf(sizeof(tBTA_PAN_API_ENABLE))) != NULL) + { + p_buf->hdr.event = BTA_PAN_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + + bta_sys_sendmsg(p_buf); + } +} + + + +/******************************************************************************* +** +** Function BTA_PanDisable +** +** Description Disables PAN service. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_PanDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_PAN); + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_PAN_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_PanSetRole +** +** Description Sets PAN roles. When the enable operation is complete +** the callback function will be called with a BTA_PAN_SET_ROLE_EVT. +** +** Returns void +** +*******************************************************************************/ +void BTA_PanSetRole(tBTA_PAN_ROLE role, tBTA_PAN_ROLE_INFO *p_user_info, tBTA_PAN_ROLE_INFO *p_gn_info, + tBTA_PAN_ROLE_INFO *p_nap_info) +{ + + tBTA_PAN_API_SET_ROLE *p_buf; + + if ((p_buf = (tBTA_PAN_API_SET_ROLE *) GKI_getbuf(sizeof(tBTA_PAN_API_SET_ROLE))) != NULL) + { + p_buf->hdr.event = BTA_PAN_API_SET_ROLE_EVT; + p_buf->role = role; + + if(p_user_info && (role & BTA_PAN_ROLE_PANU)) + { + if(p_user_info->p_srv_name) + BCM_STRNCPY_S(p_buf->user_name, sizeof(p_buf->user_name), p_user_info->p_srv_name, BTA_SERVICE_NAME_LEN); + else + p_buf->user_name[0] = 0; + + p_buf->user_name[BTA_SERVICE_NAME_LEN] = 0; + p_buf->user_app_id = p_user_info->app_id; + p_buf->user_sec_mask = p_user_info->sec_mask; + } + + if(p_gn_info && (role & BTA_PAN_ROLE_GN)) + { + if(p_gn_info->p_srv_name) + BCM_STRNCPY_S(p_buf->gn_name, sizeof(p_buf->gn_name), p_gn_info->p_srv_name, BTA_SERVICE_NAME_LEN); + else + p_buf->gn_name[0] = 0; + + p_buf->gn_name[BTA_SERVICE_NAME_LEN] = 0; + p_buf->gn_app_id = p_gn_info->app_id; + p_buf->gn_sec_mask = p_gn_info->sec_mask; + + } + + if(p_nap_info && (role & BTA_PAN_ROLE_NAP)) + { + if(p_nap_info->p_srv_name) + BCM_STRNCPY_S(p_buf->nap_name, sizeof(p_buf->nap_name), p_nap_info->p_srv_name, BTA_SERVICE_NAME_LEN); + else + p_buf->nap_name[0] = 0; + + p_buf->nap_name[BTA_SERVICE_NAME_LEN] = 0; + p_buf->nap_app_id = p_nap_info->app_id; + p_buf->nap_sec_mask = p_nap_info->sec_mask; + + } + + bta_sys_sendmsg(p_buf); + } + + + +} + +/******************************************************************************* +** +** Function BTA_PanOpen +** +** Description Opens a connection to a peer device. +** When connection is open callback function is called +** with a BTA_PAN_OPEN_EVT. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_PanOpen(BD_ADDR bd_addr, tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role) +{ + + tBTA_PAN_API_OPEN *p_buf; + + if ((p_buf = (tBTA_PAN_API_OPEN *) GKI_getbuf(sizeof(tBTA_PAN_API_OPEN))) != NULL) + { + p_buf->hdr.event = BTA_PAN_API_OPEN_EVT; + p_buf->local_role = local_role; + p_buf->peer_role = peer_role; + bdcpy(p_buf->bd_addr, bd_addr); + bta_sys_sendmsg(p_buf); + } + +} + +/******************************************************************************* +** +** Function BTA_PanClose +** +** Description Close a PAN connection to a peer device. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void BTA_PanClose(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_PAN_API_CLOSE_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} +#endif /* BTA_PAN_INCLUDED */ diff --git a/bta/pan/bta_pan_ci.c b/bta/pan/bta_pan_ci.c new file mode 100644 index 0000000..f8e5832 --- /dev/null +++ b/bta/pan/bta_pan_ci.c @@ -0,0 +1,260 @@ +/****************************************************************************** + * + * 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 implementation file for data gateway call-in functions. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_PAN_INCLUDED) && (BTA_PAN_INCLUDED == TRUE) + +#include <string.h> + +#include "gki.h" +#include "pan_api.h" +#include "bd.h" +#include "bta_api.h" +#include "bta_pan_api.h" +#include "bta_pan_ci.h" +#include "bta_pan_int.h" + + +/******************************************************************************* +** +** Function bta_pan_ci_tx_ready +** +** Description This function sends an event to PAN indicating the phone is +** ready for more data and PAN should call bta_pan_co_tx_path(). +** This function is used when the TX data path is configured +** to use a pull interface. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_ci_tx_ready(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->layer_specific = handle; + p_buf->event = BTA_PAN_CI_TX_READY_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_pan_ci_rx_ready +** +** Description This function sends an event to PAN indicating the phone +** has data available to send to PAN and PAN should call +** bta_pan_co_rx_path(). This function is used when the RX +** data path is configured to use a pull interface. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_ci_rx_ready(UINT16 handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->layer_specific = handle; + p_buf->event = BTA_PAN_CI_RX_READY_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_pan_ci_tx_flow +** +** Description This function is called to enable or disable data flow on +** the TX path. The phone should call this function to +** disable data flow when it is congested and cannot handle +** any more data sent by bta_pan_co_tx_write() or +** bta_pan_co_tx_writebuf(). This function is used when the +** TX data path is configured to use a push interface. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_ci_tx_flow(UINT16 handle, BOOLEAN enable) +{ + tBTA_PAN_CI_TX_FLOW *p_buf; + + if ((p_buf = (tBTA_PAN_CI_TX_FLOW *) GKI_getbuf(sizeof(tBTA_PAN_CI_TX_FLOW))) != NULL) + { + p_buf->hdr.layer_specific = handle; + p_buf->hdr.event = BTA_PAN_CI_TX_FLOW_EVT; + p_buf->enable = enable; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_pan_ci_rx_write +** +** Description This function is called to send data to PAN when the RX path +** is configured to use a push interface. The function copies +** data to an event buffer and sends it to PAN. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_ci_rx_write(UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol, + UINT8 *p_data, UINT16 len, BOOLEAN ext) +{ + BT_HDR * p_buf; + + if((p_buf = (BT_HDR *) GKI_getpoolbuf(PAN_POOL_ID)) != NULL) + { + + + p_buf->offset = PAN_MINIMUM_OFFSET; + + /* copy all other params before the data */ + bdcpy(((tBTA_PAN_DATA_PARAMS *)p_buf)->src, src); + bdcpy(((tBTA_PAN_DATA_PARAMS *)p_buf)->dst, dst); + ((tBTA_PAN_DATA_PARAMS *)p_buf)->protocol = protocol; + ((tBTA_PAN_DATA_PARAMS *)p_buf)->ext = ext; + p_buf->len=len; + + /* copy data */ + memcpy((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, len); + + p_buf->layer_specific = handle; + p_buf->event = BTA_PAN_CI_RX_WRITEBUF_EVT; + bta_sys_sendmsg(p_buf); + } + +} + +/******************************************************************************* +** +** Function bta_pan_ci_rx_writebuf +** +** Description This function is called to send data to the phone when +** the RX path is configured to use a push interface with +** zero copy. The function sends an event to PAN containing +** the data buffer. The buffer must be allocated using +** functions GKI_getbuf() or GKI_getpoolbuf(). The buffer +** will be freed by BTA; the phone must not free the buffer. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_ci_rx_writebuf(UINT16 handle, BD_ADDR dst, BD_ADDR src, UINT16 protocol, + BT_HDR *p_buf, BOOLEAN ext) +{ + + /* copy all other params before the data */ + bdcpy(((tBTA_PAN_DATA_PARAMS *)p_buf)->src, src); + bdcpy(((tBTA_PAN_DATA_PARAMS *)p_buf)->dst, dst); + ((tBTA_PAN_DATA_PARAMS *)p_buf)->protocol = protocol; + ((tBTA_PAN_DATA_PARAMS *)p_buf)->ext = ext; + + p_buf->layer_specific = handle; + p_buf->event = BTA_PAN_CI_RX_WRITEBUF_EVT; + bta_sys_sendmsg(p_buf); +} + + + + +/******************************************************************************* +** +** Function bta_pan_ci_readbuf +** +** Description +** +** +** Returns void +** +*******************************************************************************/ +BT_HDR * bta_pan_ci_readbuf(UINT16 handle, BD_ADDR src, BD_ADDR dst, UINT16* p_protocol, + BOOLEAN* p_ext, BOOLEAN* p_forward) +{ + tBTA_PAN_SCB * p_scb; + BT_HDR * p_buf; + + p_scb = bta_pan_scb_by_handle(handle); + + p_buf = (BT_HDR *)GKI_dequeue(&p_scb->data_queue); + + if(p_buf) + { + bdcpy(src,((tBTA_PAN_DATA_PARAMS *)p_buf)->src); + bdcpy(dst,((tBTA_PAN_DATA_PARAMS *)p_buf)->dst); + *p_protocol = ((tBTA_PAN_DATA_PARAMS *)p_buf)->protocol; + *p_ext = ((tBTA_PAN_DATA_PARAMS *)p_buf)->ext; + *p_forward = ((tBTA_PAN_DATA_PARAMS *)p_buf)->forward; + } + + return p_buf; +} + + +/******************************************************************************* +** +** Function bta_pan_ci_set_mfilters +** +** Description This function is called to set multicast filters +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_ci_set_mfilters(UINT16 handle, UINT16 num_mcast_filters, UINT8 *p_start_array, + UINT8 *p_end_array) +{ + + PAN_SetMulticastFilters(handle, num_mcast_filters, p_start_array, p_end_array); + +} + + +/******************************************************************************* +** +** Function bta_pan_ci_set_mfilters +** +** Description This function is called to set protocol filters +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_ci_set_pfilters(UINT16 handle, UINT16 num_filters, UINT16 *p_start_array, UINT16 *p_end_array) +{ + + PAN_SetProtocolFilters(handle, num_filters, p_start_array, p_end_array ); + +} + +#endif /* BTA_PAN_API */ diff --git a/bta/pan/bta_pan_int.h b/bta/pan/bta_pan_int.h new file mode 100644 index 0000000..1667e57 --- /dev/null +++ b/bta/pan/bta_pan_int.h @@ -0,0 +1,212 @@ +/****************************************************************************** + * + * 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 private interface file for the BTA data gateway. + * + ******************************************************************************/ +#ifndef BTA_PAN_INT_H +#define BTA_PAN_INT_H + +#include "bta_sys.h" +#include "bta_pan_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + + + + +/* PAN events */ +enum +{ + /* these events are handled by the state machine */ + BTA_PAN_API_CLOSE_EVT = BTA_SYS_EVT_START(BTA_ID_PAN), + BTA_PAN_CI_TX_READY_EVT, + BTA_PAN_CI_RX_READY_EVT, + BTA_PAN_CI_TX_FLOW_EVT, + BTA_PAN_CI_RX_WRITE_EVT, + BTA_PAN_CI_RX_WRITEBUF_EVT, + BTA_PAN_CONN_OPEN_EVT, + BTA_PAN_CONN_CLOSE_EVT, + BTA_PAN_BNEP_FLOW_ENABLE_EVT, + BTA_PAN_RX_FROM_BNEP_READY_EVT, + + /* these events are handled outside of the state machine */ + BTA_PAN_API_ENABLE_EVT, + BTA_PAN_API_DISABLE_EVT, + BTA_PAN_API_SET_ROLE_EVT, + BTA_PAN_API_OPEN_EVT +}; + + + + +/***************************************************************************** +** Data types +*****************************************************************************/ + +/* data type for BTA_PAN_API_ENABLE_EVT */ +typedef struct +{ + BT_HDR hdr; /* Event header */ + tBTA_PAN_CBACK *p_cback; /* PAN callback function */ +} tBTA_PAN_API_ENABLE; + +/* data type for BTA_PAN_API_REG_ROLE_EVT */ +typedef struct +{ + BT_HDR hdr; /* Event header */ + char user_name[BTA_SERVICE_NAME_LEN+1]; /* Service name */ + char gn_name[BTA_SERVICE_NAME_LEN+1]; /* Service name */ + char nap_name[BTA_SERVICE_NAME_LEN+1]; /* Service name */ + tBTA_PAN_ROLE role; + UINT8 user_app_id; + UINT8 gn_app_id; + UINT8 nap_app_id; + tBTA_SEC user_sec_mask; /* Security mask */ + tBTA_SEC gn_sec_mask; /* Security mask */ + tBTA_SEC nap_sec_mask; /* Security mask */ + + +} tBTA_PAN_API_SET_ROLE; + +/* data type for BTA_PAN_API_OPEN_EVT */ +typedef struct +{ + BT_HDR hdr; /* Event header */ + tBTA_PAN_ROLE local_role; /* local role */ + tBTA_PAN_ROLE peer_role; /* peer role */ + BD_ADDR bd_addr; /* peer bdaddr */ +} tBTA_PAN_API_OPEN; + +/* data type for BTA_PAN_CI_TX_FLOW_EVT */ +typedef struct +{ + BT_HDR hdr; /* Event header */ + BOOLEAN enable; /* Flow control setting */ +} tBTA_PAN_CI_TX_FLOW; + +/* data type for BTA_PAN_CONN_OPEN_EVT */ +typedef struct +{ + BT_HDR hdr; /* Event header */ + tPAN_RESULT result; + +} tBTA_PAN_CONN; + + + + +/* union of all data types */ +typedef union +{ + BT_HDR hdr; + tBTA_PAN_API_ENABLE api_enable; + tBTA_PAN_API_SET_ROLE api_set_role; + tBTA_PAN_API_OPEN api_open; + tBTA_PAN_CI_TX_FLOW ci_tx_flow; + tBTA_PAN_CONN conn; +} tBTA_PAN_DATA; + +/* state machine control block */ +typedef struct +{ + BD_ADDR bd_addr; /* peer bdaddr */ + BUFFER_Q data_queue; /* Queue of buffers waiting to be passed to application */ + UINT16 handle; /* BTA PAN/BNEP handle */ + BOOLEAN in_use; /* scb in use */ + tBTA_SEC sec_mask; /* Security mask */ + BOOLEAN pan_flow_enable;/* BNEP flow control state */ + BOOLEAN app_flow_enable;/* Application flow control state */ + UINT8 state; /* State machine state */ + tBTA_PAN_ROLE local_role; /* local role */ + tBTA_PAN_ROLE peer_role; /* peer role */ + UINT8 app_id; /* application id for the connection */ + +} tBTA_PAN_SCB; + + + +/* main control block */ +typedef struct +{ + tBTA_PAN_SCB scb[BTA_PAN_NUM_CONN]; /* state machine control blocks */ + tBTA_PAN_CBACK *p_cback; /* PAN callback function */ + UINT8 app_id[3]; /* application id for PAN roles */ + UINT8 flow_mask; /* Data flow mask */ + UINT8 q_level; /* queue level set by application for TX data */ + +} tBTA_PAN_CB; + + +/* pan data param */ +typedef struct +{ + BT_HDR hdr; + BD_ADDR src; + BD_ADDR dst; + UINT16 protocol; + BOOLEAN ext; + BOOLEAN forward; + +} tBTA_PAN_DATA_PARAMS; + + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* PAN control block */ + +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_PAN_CB bta_pan_cb; +#else +extern tBTA_PAN_CB *bta_pan_cb_ptr; +#define bta_pan_cb (*bta_pan_cb_ptr) +#endif + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +extern tBTA_PAN_SCB *bta_pan_scb_alloc(void); +extern void bta_pan_scb_dealloc(tBTA_PAN_SCB *p_scb); +extern UINT8 bta_pan_scb_to_idx(tBTA_PAN_SCB *p_scb); +extern tBTA_PAN_SCB *bta_pan_scb_by_handle(UINT16 handle); +extern BOOLEAN bta_pan_hdl_event(BT_HDR *p_msg); + +/* action functions */ +extern void bta_pan_enable(tBTA_PAN_DATA *p_data); +extern void bta_pan_disable(void); +extern void bta_pan_set_role(tBTA_PAN_DATA *p_data); +extern void bta_pan_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_api_close(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_set_shutdown(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_rx_path(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_tx_path(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_tx_flow(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_conn_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_conn_close(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_writebuf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_write_buf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); +extern void bta_pan_free_buf(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); + + +#endif /* BTA_PAN_INT_H */ diff --git a/bta/pan/bta_pan_main.c b/bta/pan/bta_pan_main.c new file mode 100644 index 0000000..add1c7c --- /dev/null +++ b/bta/pan/bta_pan_main.c @@ -0,0 +1,421 @@ +/****************************************************************************** + * + * 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 file contains the PAN main functions and state machine. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_PAN_INCLUDED) && (BTA_PAN_INCLUDED == TRUE) + +#include <string.h> +#include "bta_api.h" +#include "bta_sys.h" +#include "gki.h" +#include "pan_api.h" +#include "bta_pan_api.h" +#include "bta_pan_int.h" +#include "bd.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + + + +/* state machine action enumeration list */ +enum +{ + BTA_PAN_API_CLOSE, + BTA_PAN_TX_PATH, + BTA_PAN_RX_PATH, + BTA_PAN_TX_FLOW, + BTA_PAN_WRITE_BUF, + BTA_PAN_CONN_OPEN, + BTA_PAN_CONN_CLOSE, + BTA_PAN_FREE_BUF, + BTA_PAN_IGNORE +}; + + + +/* type for action functions */ +typedef void (*tBTA_PAN_ACTION)(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data); + + + + +/* action function list */ +const tBTA_PAN_ACTION bta_pan_action[] = +{ + bta_pan_api_close, + bta_pan_tx_path, + bta_pan_rx_path, + bta_pan_tx_flow, + bta_pan_write_buf, + bta_pan_conn_open, + bta_pan_conn_close, + bta_pan_free_buf, + +}; + +/* state table information */ +#define BTA_PAN_ACTIONS 1 /* number of actions */ +#define BTA_PAN_NEXT_STATE 1 /* position of next state */ +#define BTA_PAN_NUM_COLS 2 /* number of columns in state tables */ + + +/* state machine states */ +enum +{ + BTA_PAN_IDLE_ST, + BTA_PAN_OPEN_ST, + BTA_PAN_CLOSING_ST +}; + + +/* state table for listen state */ +const UINT8 bta_pan_st_idle[][BTA_PAN_NUM_COLS] = +{ + /* API_CLOSE */ {BTA_PAN_API_CLOSE, BTA_PAN_IDLE_ST}, + /* CI_TX_READY */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}, + /* CI_RX_READY */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}, + /* CI_TX_FLOW */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}, + /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}, + /* CI_RX_WRITEBUF */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}, + /* PAN_CONN_OPEN */ {BTA_PAN_CONN_OPEN, BTA_PAN_OPEN_ST}, + /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_OPEN, BTA_PAN_IDLE_ST}, + /* FLOW_ENABLE */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}, + /* BNEP_DATA */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST} + +}; + + + +/* state table for open state */ +const UINT8 bta_pan_st_open[][BTA_PAN_NUM_COLS] = +{ + /* API_CLOSE */ {BTA_PAN_API_CLOSE, BTA_PAN_OPEN_ST}, + /* CI_TX_READY */ {BTA_PAN_TX_PATH, BTA_PAN_OPEN_ST}, + /* CI_RX_READY */ {BTA_PAN_RX_PATH, BTA_PAN_OPEN_ST}, + /* CI_TX_FLOW */ {BTA_PAN_TX_FLOW, BTA_PAN_OPEN_ST}, + /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_OPEN_ST}, + /* CI_RX_WRITEBUF */ {BTA_PAN_WRITE_BUF, BTA_PAN_OPEN_ST}, + /* PAN_CONN_OPEN */ {BTA_PAN_IGNORE, BTA_PAN_OPEN_ST}, + /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_CLOSE, BTA_PAN_IDLE_ST}, + /* FLOW_ENABLE */ {BTA_PAN_RX_PATH, BTA_PAN_OPEN_ST}, + /* BNEP_DATA */ {BTA_PAN_TX_PATH, BTA_PAN_OPEN_ST} +}; + +/* state table for closing state */ +const UINT8 bta_pan_st_closing[][BTA_PAN_NUM_COLS] = +{ + /* API_CLOSE */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST}, + /* CI_TX_READY */ {BTA_PAN_TX_PATH, BTA_PAN_CLOSING_ST}, + /* CI_RX_READY */ {BTA_PAN_RX_PATH, BTA_PAN_CLOSING_ST}, + /* CI_TX_FLOW */ {BTA_PAN_TX_FLOW, BTA_PAN_CLOSING_ST}, + /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST}, + /* CI_RX_WRITEBUF */ {BTA_PAN_FREE_BUF, BTA_PAN_CLOSING_ST}, + /* PAN_CONN_OPEN */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST}, + /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_CLOSE, BTA_PAN_IDLE_ST}, + /* FLOW_ENABLE */ {BTA_PAN_RX_PATH, BTA_PAN_CLOSING_ST}, + /* BNEP_DATA */ {BTA_PAN_TX_PATH, BTA_PAN_CLOSING_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_PAN_ST_TBL)[BTA_PAN_NUM_COLS]; + +/* state table */ +const tBTA_PAN_ST_TBL bta_pan_st_tbl[] = { + bta_pan_st_idle, + bta_pan_st_open, + bta_pan_st_closing +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* PAN control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_PAN_CB bta_pan_cb; +#endif + +/******************************************************************************* +** +** Function bta_pan_scb_alloc +** +** Description Allocate a PAN server control block. +** +** +** Returns pointer to the scb, or NULL if none could be allocated. +** +*******************************************************************************/ +tBTA_PAN_SCB *bta_pan_scb_alloc(void) +{ + tBTA_PAN_SCB *p_scb = &bta_pan_cb.scb[0]; + int i; + + for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) + { + if (!p_scb->in_use) + { + p_scb->in_use = TRUE; + APPL_TRACE_DEBUG1("bta_pan_scb_alloc %d", i); + break; + } + } + + if (i == BTA_PAN_NUM_CONN) + { + /* out of scbs */ + p_scb = NULL; + APPL_TRACE_WARNING0("Out of scbs"); + } + return p_scb; +} + +/******************************************************************************* +** +** Function bta_pan_sm_execute +** +** Description State machine event handling function for PAN +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_sm_execute(tBTA_PAN_SCB *p_scb, UINT16 event, tBTA_PAN_DATA *p_data) +{ + tBTA_PAN_ST_TBL state_table; + UINT8 action; + int i; + + APPL_TRACE_EVENT3("PAN scb=%d event=0x%x state=%d", bta_pan_scb_to_idx(p_scb), event, p_scb->state); + + /* look up the state table for the current state */ + state_table = bta_pan_st_tbl[p_scb->state]; + + event &= 0x00FF; + + /* set next state */ + p_scb->state = state_table[event][BTA_PAN_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_PAN_ACTIONS; i++) + { + if ((action = state_table[event][i]) != BTA_PAN_IGNORE) + { + (*bta_pan_action[action])(p_scb, p_data); + } + else + { + break; + } + } +} + +/******************************************************************************* +** +** Function bta_pan_api_enable +** +** Description Handle an API enable event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_api_enable(tBTA_PAN_DATA *p_data) +{ + /* initialize control block */ + memset(&bta_pan_cb, 0, sizeof(bta_pan_cb)); + + /* store callback function */ + bta_pan_cb.p_cback = p_data->api_enable.p_cback; + bta_pan_enable(p_data); +} + +/******************************************************************************* +** +** Function bta_pan_api_disable +** +** Description Handle an API disable event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_api_disable(tBTA_PAN_DATA *p_data) +{ + bta_pan_disable(); +} + + +/******************************************************************************* +** +** Function bta_pan_api_open +** +** Description Handle an API listen event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_pan_api_open(tBTA_PAN_DATA *p_data) +{ + tBTA_PAN_SCB *p_scb; + tBTA_PAN_OPEN data; + + /* allocate an scb */ + if ((p_scb = bta_pan_scb_alloc()) != NULL) + { + bta_pan_open(p_scb, p_data); + } + else + { + bdcpy(data.bd_addr, p_data->api_open.bd_addr); + data.status = BTA_PAN_FAIL; + bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data); + + } +} +/******************************************************************************* +** +** Function bta_pan_scb_dealloc +** +** Description Deallocate a link control block. +** +** +** Returns void +** +*******************************************************************************/ +void bta_pan_scb_dealloc(tBTA_PAN_SCB *p_scb) +{ + APPL_TRACE_DEBUG1("bta_pan_scb_dealloc %d", bta_pan_scb_to_idx(p_scb)); + memset(p_scb, 0, sizeof(tBTA_PAN_SCB)); +} + +/******************************************************************************* +** +** Function bta_pan_scb_to_idx +** +** Description Given a pointer to an scb, return its index. +** +** +** Returns Index of scb. +** +*******************************************************************************/ +UINT8 bta_pan_scb_to_idx(tBTA_PAN_SCB *p_scb) +{ + + return ((UINT8) (p_scb - bta_pan_cb.scb)) + 1; +} + + + +/******************************************************************************* +** +** Function bta_pan_scb_by_handle +** +** Description Find scb associated with handle. +** +** +** Returns Pointer to scb or NULL if not found. +** +*******************************************************************************/ +tBTA_PAN_SCB *bta_pan_scb_by_handle(UINT16 handle) +{ + tBTA_PAN_SCB *p_scb = &bta_pan_cb.scb[0]; + UINT8 i; + + for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) + { + if (p_scb->handle == handle) + { + return p_scb;; + } + } + + + APPL_TRACE_WARNING1("No scb for handle %d", handle); + + return NULL; +} + +/******************************************************************************* +** +** Function bta_pan_hdl_event +** +** Description Data gateway main event handling function. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_pan_hdl_event(BT_HDR *p_msg) +{ + tBTA_PAN_SCB *p_scb; + BOOLEAN freebuf = TRUE; + + switch (p_msg->event) + { + /* handle enable event */ + case BTA_PAN_API_ENABLE_EVT: + bta_pan_api_enable((tBTA_PAN_DATA *) p_msg); + break; + + /* handle disable event */ + case BTA_PAN_API_DISABLE_EVT: + bta_pan_api_disable((tBTA_PAN_DATA *) p_msg); + break; + + /* handle set role event */ + case BTA_PAN_API_SET_ROLE_EVT: + bta_pan_set_role((tBTA_PAN_DATA *) p_msg); + break; + + /* handle open event */ + case BTA_PAN_API_OPEN_EVT: + bta_pan_api_open((tBTA_PAN_DATA *) p_msg); + break; + + + /* events that require buffer not be released */ + case BTA_PAN_CI_RX_WRITEBUF_EVT: + freebuf = FALSE; + if ((p_scb = bta_pan_scb_by_handle(p_msg->layer_specific)) != NULL) + { + bta_pan_sm_execute(p_scb, p_msg->event, (tBTA_PAN_DATA *) p_msg); + } + break; + + /* all other events */ + default: + if ((p_scb = bta_pan_scb_by_handle(p_msg->layer_specific)) != NULL) + { + bta_pan_sm_execute(p_scb, p_msg->event, (tBTA_PAN_DATA *) p_msg); + } + break; + + } + return freebuf; +} +#endif /* BTA_PAN_INCLUDED */ diff --git a/bta/pb/bta_pbs_cfg.c b/bta/pb/bta_pbs_cfg.c new file mode 100644 index 0000000..b2782fb --- /dev/null +++ b/bta/pb/bta_pbs_cfg.c @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains compile-time configurable constants for the BTA Phone + * Book Access Server. + * + ******************************************************************************/ + +#include "bt_target.h" + +#if defined(BTA_PBS_INCLUDED) && (BTA_PBS_INCLUDED == TRUE) + +#include "bta_pbs_int.h" + +/* Realm Character Set */ +#ifndef BTA_PBS_REALM_CHARSET +#define BTA_PBS_REALM_CHARSET 0 /* ASCII */ +#endif + +/* Specifies whether or not client's user id is required during obex authentication */ +#ifndef BTA_PBS_USERID_REQ +#define BTA_PBS_USERID_REQ FALSE +#endif + +const tBTA_PBS_CFG bta_pbs_cfg = +{ + BTA_PBS_REALM_CHARSET, /* Server only */ + BTA_PBS_USERID_REQ, /* Server only */ + (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE), + BTA_PBS_REPOSIT_LOCAL, +}; + +tBTA_PBS_CFG *p_bta_pbs_cfg = (tBTA_PBS_CFG *)&bta_pbs_cfg; +#endif /* BTA_PBS_INCLUDED */ diff --git a/bta/pb/bta_pbs_int.h b/bta/pb/bta_pbs_int.h new file mode 100644 index 0000000..a4fce2b --- /dev/null +++ b/bta/pb/bta_pbs_int.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 private file for the phone book access server (PBS). + * + ******************************************************************************/ +#ifndef BTA_PBS_INT_H +#define BTA_PBS_INT_H + +#include "bt_target.h" +#include "bta_pbs_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +#define BTA_PBS_TARGET_UUID "\x79\x61\x35\xf0\xf0\xc5\x11\xd8\x09\x66\x08\x00\x20\x0c\x9a\x66" +#define BTA_PBS_UUID_LENGTH 16 +#define BTA_PBS_MAX_AUTH_KEY_SIZE 16 /* Must not be greater than OBX_MAX_AUTH_KEY_SIZE */ + +#define BTA_PBS_DEFAULT_VERSION 0x0101 /* for PBAP PSE version 1.1 */ + + +/* Configuration structure */ +typedef struct +{ + UINT8 realm_charset; /* Server only */ + BOOLEAN userid_req; /* TRUE if user id is required during obex authentication (Server only) */ + UINT8 supported_features; /* Server supported features */ + UINT8 supported_repositories; /* Server supported repositories */ + +} tBTA_PBS_CFG; + + +/***************************************************************************** +** Global data +*****************************************************************************/ + + +#endif /* BTA_PBS_INT_H */ diff --git a/bta/sys/bd.c b/bta/sys/bd.c new file mode 100644 index 0000000..052f9b9 --- /dev/null +++ b/bta/sys/bd.c @@ -0,0 +1,112 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * BD address services. + * + ******************************************************************************/ + +#include "data_types.h" +#include "bd.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* global constant for "any" bd addr */ +const BD_ADDR bd_addr_any = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +const BD_ADDR bd_addr_null= {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/***************************************************************************** +** Functions +*****************************************************************************/ + +/******************************************************************************* +** +** Function bdcpy +** +** Description Copy bd addr b to a. +** +** +** Returns void +** +*******************************************************************************/ +void bdcpy(BD_ADDR a, const BD_ADDR b) +{ + int i; + + for (i = BD_ADDR_LEN; i != 0; i--) + { + *a++ = *b++; + } +} + +/******************************************************************************* +** +** Function bdcmp +** +** Description Compare bd addr b to a. +** +** +** Returns Zero if b==a, nonzero otherwise (like memcmp). +** +*******************************************************************************/ +int bdcmp(const BD_ADDR a, const BD_ADDR b) +{ + int i; + + for (i = BD_ADDR_LEN; i != 0; i--) + { + if (*a++ != *b++) + { + return -1; + } + } + return 0; +} + +/******************************************************************************* +** +** Function bdcmpany +** +** Description Compare bd addr to "any" bd addr. +** +** +** Returns Zero if a equals bd_addr_any. +** +*******************************************************************************/ +int bdcmpany(const BD_ADDR a) +{ + return bdcmp(a, bd_addr_any); +} + +/******************************************************************************* +** +** Function bdsetany +** +** Description Set bd addr to "any" bd addr. +** +** +** Returns void +** +*******************************************************************************/ +void bdsetany(BD_ADDR a) +{ + bdcpy(a, bd_addr_any); +} diff --git a/bta/sys/bta_sys.h b/bta/sys/bta_sys.h new file mode 100644 index 0000000..5d724e5 --- /dev/null +++ b/bta/sys/bta_sys.h @@ -0,0 +1,308 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 public interface file for the BTA system manager. + * + ******************************************************************************/ +#ifndef BTA_SYS_H +#define BTA_SYS_H + +#include "bt_target.h" +#include "gki.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* event handler function type */ +typedef BOOLEAN (tBTA_SYS_EVT_HDLR)(BT_HDR *p_msg); + +/* disable function type */ +typedef void (tBTA_SYS_DISABLE)(void); + + +/* HW modules */ +enum +{ + BTA_SYS_HW_BLUETOOTH, + BTA_SYS_HW_FMRX, + BTA_SYS_HW_FMTX, + BTA_SYS_HW_GPS, + BTA_SYS_HW_SENSOR, + BTA_SYS_HW_NFC, + BTA_SYS_HW_RT, + + BTA_SYS_MAX_HW_MODULES +}; + +typedef UINT16 tBTA_SYS_HW_MODULE; + +#ifndef BTA_DM_NUM_JV_ID +#define BTA_DM_NUM_JV_ID 2 +#endif + +/* SW sub-systems */ +#define BTA_ID_SYS 0 /* system manager */ +/* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */ +#define BTA_ID_DM 1 /* device manager */ +#define BTA_ID_DM_SEARCH 2 /* device manager search */ +#define BTA_ID_DM_SEC 3 /* device manager security */ +#define BTA_ID_DG 4 /* data gateway */ +#define BTA_ID_AG 5 /* audio gateway */ +#define BTA_ID_OPC 6 /* object push client */ +#define BTA_ID_OPS 7 /* object push server */ +#define BTA_ID_FTS 8 /* file transfer server */ +#define BTA_ID_CT 9 /* cordless telephony terminal */ +#define BTA_ID_FTC 10 /* file transfer client */ +#define BTA_ID_SS 11 /* synchronization server */ +#define BTA_ID_PR 12 /* Printer client */ +#define BTA_ID_BIC 13 /* Basic Imaging Client */ +#define BTA_ID_PAN 14 /* Personal Area Networking */ +#define BTA_ID_BIS 15 /* Basic Imaging Server */ +#define BTA_ID_ACC 16 /* Advanced Camera Client */ +#define BTA_ID_SC 17 /* SIM Card Access server */ +#define BTA_ID_AV 18 /* Advanced audio/video */ +#define BTA_ID_AVK 19 /* Audio/video sink */ +#define BTA_ID_HD 20 /* HID Device */ +#define BTA_ID_CG 21 /* Cordless Gateway */ +#define BTA_ID_BP 22 /* Basic Printing Client */ +#define BTA_ID_HH 23 /* Human Interface Device Host */ +#define BTA_ID_PBS 24 /* Phone Book Access Server */ +#define BTA_ID_PBC 25 /* Phone Book Access Client */ +#define BTA_ID_JV 26 /* Java */ +#define BTA_ID_HS 27 /* Headset */ +#define BTA_ID_MSE 28 /* Message Server Equipment */ +#define BTA_ID_MCE 29 /* Message Client Equipment */ +#define BTA_ID_HL 30 /* Health Device Profile*/ +#define BTA_ID_GATTC 31 /* GATT Client */ +#define BTA_ID_GATTS 32 /* GATT Client */ +#define BTA_ID_BLUETOOTH_MAX 33 /* last BT profile */ + +/* FM */ +#define BTA_ID_FM 34 /* FM */ +#define BTA_ID_FMTX 35 /* FM TX */ + +/* SENSOR */ +#define BTA_ID_SSR 36 /* Sensor */ + +/* GPS */ +#define BTA_ID_GPS 37 /* GPS */ + +/* GENERIC */ +#define BTA_ID_PRM 38 +#define BTA_ID_SYSTEM 39 /* platform-specific */ +#define BTA_ID_SWRAP 40 /* Insight script wrapper */ +#define BTA_ID_MIP 41 /* Multicase Individual Polling */ +#define BTA_ID_RT 42 /* Audio Routing module: This module is always on. */ + + +/* JV */ +#define BTA_ID_JV1 43 /* JV1 */ +#define BTA_ID_JV2 44 /* JV2 */ + +#define BTA_ID_MAX (43 + BTA_DM_NUM_JV_ID) + +typedef UINT8 tBTA_SYS_ID; + + +#define BTA_SYS_CONN_OPEN 0x00 +#define BTA_SYS_CONN_CLOSE 0x01 +#define BTA_SYS_APP_OPEN 0x02 +#define BTA_SYS_APP_CLOSE 0x03 +#define BTA_SYS_SCO_OPEN 0x04 +#define BTA_SYS_SCO_CLOSE 0x05 +#define BTA_SYS_CONN_IDLE 0x06 +#define BTA_SYS_CONN_BUSY 0x07 + +/* for link policy */ +#define BTA_SYS_PLCY_SET 0x10 /* set the link policy to the given addr */ +#define BTA_SYS_PLCY_CLR 0x11 /* clear the link policy to the given addr */ +#define BTA_SYS_PLCY_DEF_SET 0x12 /* set the default link policy */ +#define BTA_SYS_PLCY_DEF_CLR 0x13 /* clear the default link policy */ +#define BTA_SYS_ROLE_CHANGE 0x14 /* role change */ + +typedef UINT8 tBTA_SYS_CONN_STATUS; + +/* Bitmask of sys features */ +#define BTA_SYS_FEAT_PCM2 0x0001 +#define BTA_SYS_FEAT_PCM2_MASTER 0x0002 + +/* tBTA_PREF_ROLES */ +typedef UINT8 tBTA_SYS_PREF_ROLES; + +/* conn callback for role / low power manager*/ +typedef void (tBTA_SYS_CONN_CBACK)(tBTA_SYS_CONN_STATUS status,UINT8 id, UINT8 app_id, BD_ADDR peer_addr); + +/* conn callback for role / low power manager*/ +typedef void (tBTA_SYS_SSR_CFG_CBACK)(UINT8 id, UINT8 app_id, UINT16 latency, UINT16 tout); + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) +/* eir callback for adding/removeing UUID */ +typedef void (tBTA_SYS_EIR_CBACK)(UINT16 uuid16, BOOLEAN adding); +#endif + +/* registration structure */ +typedef struct +{ + tBTA_SYS_EVT_HDLR *evt_hdlr; + tBTA_SYS_DISABLE *disable; +} tBTA_SYS_REG; + +/* system manager configuration structure */ +typedef struct +{ + UINT16 mbox_evt; /* GKI mailbox event */ + UINT8 mbox; /* GKI mailbox id */ + UINT8 timer; /* GKI timer id */ + UINT8 trace_level; /* initial trace level */ +} tBTA_SYS_CFG; + +/* data type to send events to BTA SYS HW manager */ +typedef struct +{ + BT_HDR hdr; + tBTA_SYS_HW_MODULE hw_module; +} tBTA_SYS_HW_MSG; + + + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* trace level */ +extern UINT8 appl_trace_level; + +/***************************************************************************** +** Macros +*****************************************************************************/ + +/* Calculate start of event enumeration; id is top 8 bits of event */ +#define BTA_SYS_EVT_START(id) ((id) << 8) + +/***************************************************************************** +** events for BTA SYS HW manager +*****************************************************************************/ + +/* events sent to SYS HW manager - must be kept synchronized with tables in bta_sys_main.c */ +enum +{ + /* device manager local device API events */ + BTA_SYS_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SYS), + BTA_SYS_EVT_ENABLED_EVT, + BTA_SYS_EVT_STACK_ENABLED_EVT, + BTA_SYS_API_DISABLE_EVT, + BTA_SYS_EVT_DISABLED_EVT, + BTA_SYS_ERROR_EVT, + + BTA_SYS_MAX_EVT +}; + + + +/* SYS HW status events - returned by SYS HW manager to other modules. */ +enum +{ + BTA_SYS_HW_OFF_EVT, + BTA_SYS_HW_ON_EVT, + BTA_SYS_HW_STARTING_EVT, + BTA_SYS_HW_STOPPING_EVT, + BTA_SYS_HW_ERROR_EVT + +}; +typedef UINT8 tBTA_SYS_HW_EVT; + +/* HW enable callback type */ +typedef void (tBTA_SYS_HW_CBACK)(tBTA_SYS_HW_EVT status); + +/***************************************************************************** +** Function declarations +*****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +BTA_API extern void bta_sys_init(void); +BTA_API extern void bta_sys_event(BT_HDR *p_msg); +BTA_API extern void bta_sys_timer_update(void); +BTA_API extern void bta_sys_disable_timers(void); +BTA_API extern void bta_sys_set_trace_level(UINT8 level); +extern void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg); +extern void bta_sys_deregister(UINT8 id); +extern BOOLEAN bta_sys_is_register(UINT8 id); +extern UINT16 bta_sys_get_sys_features(void); +extern void bta_sys_sendmsg(void *p_msg); +extern void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout); +extern void bta_sys_stop_timer(TIMER_LIST_ENT *p_tle); +extern void bta_sys_disable(tBTA_SYS_HW_MODULE module); + +extern void bta_sys_hw_register( tBTA_SYS_HW_MODULE module, tBTA_SYS_HW_CBACK *cback); +extern void bta_sys_hw_unregister( tBTA_SYS_HW_MODULE module ); + + +extern void bta_sys_rm_register(tBTA_SYS_CONN_CBACK * p_cback); +extern void bta_sys_pm_register(tBTA_SYS_CONN_CBACK * p_cback); + +extern void bta_sys_policy_register(tBTA_SYS_CONN_CBACK * p_cback); +extern void bta_sys_sco_register(tBTA_SYS_CONN_CBACK * p_cback); + + +extern void bta_sys_conn_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_conn_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_app_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_app_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_sco_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_sco_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_sco_use(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_sco_unuse(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_idle(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); +extern void bta_sys_busy(UINT8 id, UINT8 app_id, BD_ADDR peer_addr); + +#if (BTM_SSR_INCLUDED == TRUE) +extern void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK * p_cback); +extern void bta_sys_chg_ssr_config (UINT8 id, UINT8 app_id, UINT16 max_latency, UINT16 min_tout); +#endif + +extern void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK * p_cback); +extern void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, UINT8 new_role, UINT8 hci_status); +extern void bta_sys_collision_register(UINT8 bta_id, tBTA_SYS_CONN_CBACK *p_cback); +extern void bta_sys_notify_collision (BD_ADDR_PTR p_bda); + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) +extern void bta_sys_eir_register(tBTA_SYS_EIR_CBACK * p_cback); +extern void bta_sys_add_uuid(UINT16 uuid16); +extern void bta_sys_remove_uuid(UINT16 uuid16); +#else +#define bta_sys_eir_register(ut) +#define bta_sys_add_uuid(ut) +#define bta_sys_remove_uuid(ut) +#endif + +extern void bta_sys_set_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr); +extern void bta_sys_clear_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr); +extern void bta_sys_set_default_policy (UINT8 id, UINT8 policy); +extern void bta_sys_clear_default_policy (UINT8 id, UINT8 policy); + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_SYS_H */ diff --git a/bta/sys/bta_sys_cfg.c b/bta/sys/bta_sys_cfg.c new file mode 100644 index 0000000..bcc7e40 --- /dev/null +++ b/bta/sys/bta_sys_cfg.c @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains compile-time configurable constants for the BTA + * system manager. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "gki.h" +#include "bta_sys.h" + +/* GKI task mailbox event for BTA. */ +#ifndef BTA_MBOX_EVT +#define BTA_MBOX_EVT TASK_MBOX_2_EVT_MASK +#endif + +/* GKI task mailbox for BTA. */ +#ifndef BTA_MBOX +#define BTA_MBOX TASK_MBOX_2 +#endif + +/* GKI timer id used for protocol timer for BTA. */ +#ifndef BTA_TIMER +#define BTA_TIMER TIMER_1 +#endif + +const tBTA_SYS_CFG bta_sys_cfg = +{ + BTA_MBOX_EVT, /* GKI mailbox event */ + BTA_MBOX, /* GKI mailbox id */ + BTA_TIMER, /* GKI timer id */ + APPL_INITIAL_TRACE_LEVEL /* initial trace level */ +}; + +tBTA_SYS_CFG *p_bta_sys_cfg = (tBTA_SYS_CFG *)&bta_sys_cfg; + + diff --git a/bta/sys/bta_sys_ci.c b/bta/sys/bta_sys_ci.c new file mode 100644 index 0000000..d191077 --- /dev/null +++ b/bta/sys/bta_sys_ci.c @@ -0,0 +1,77 @@ +/****************************************************************************** + * + * Copyright (C) 2010-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 BTA system call-in functions. + * + ******************************************************************************/ + +#include "bta_sys.h" +#include "bta_sys_ci.h" + + +/******************************************************************************* +** +** Function bta_sys_hw_ci_enabled +** +** Description This function must be called in response to function +** bta_sys_hw_enable_co(), when HW is indeed enabled +** +** +** Returns void +** +*******************************************************************************/ + void bta_sys_hw_ci_enabled(tBTA_SYS_HW_MODULE module ) + +{ + tBTA_SYS_HW_MSG *p_msg; + + if ((p_msg = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + p_msg->hdr.event = BTA_SYS_EVT_ENABLED_EVT; + p_msg->hw_module = module; + + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_sys_hw_ci_disabled +** +** Description This function must be called in response to function +** bta_sys_hw_disable_co() when HW is really OFF +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_hw_ci_disabled( tBTA_SYS_HW_MODULE module ) +{ + tBTA_SYS_HW_MSG *p_msg; + + if ((p_msg = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + p_msg->hdr.event = BTA_SYS_EVT_DISABLED_EVT; + p_msg->hw_module = module; + + bta_sys_sendmsg(p_msg); + } +} + diff --git a/bta/sys/bta_sys_conn.c b/bta/sys/bta_sys_conn.c new file mode 100644 index 0000000..b495085 --- /dev/null +++ b/bta/sys/bta_sys_conn.c @@ -0,0 +1,577 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Routes connection status callbacks from various sub systems to DM + * + ******************************************************************************/ + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_sys_int.h" +#include "gki.h" + + +/******************************************************************************* +** +** Function bta_sys_rm_register +** +** Description Called by BTA DM to register role management callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_rm_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.prm_cb = p_cback; +} + + +/******************************************************************************* +** +** Function bta_sys_policy_register +** +** Description Called by BTA DM to register link policy change callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_policy_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.p_policy_cb = p_cback; +} + +/******************************************************************************* +** +** Function bta_sys_role_chg_register +** +** Description Called by BTA AV to register role change callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.p_role_cb = p_cback; +} +/******************************************************************************* +** +** Function bta_sys_ssr_cfg_register +** +** Description Called by BTA DM to register SSR configuration callback +** +** +** Returns void +** +*******************************************************************************/ +#if (BTM_SSR_INCLUDED == TRUE) +void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK * p_cback) +{ + bta_sys_cb.p_ssr_cb = p_cback; +} +#endif +/******************************************************************************* +** +** Function bta_sys_role_chg_register +** +** Description Called by BTA AV to register role change callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, UINT8 new_role, UINT8 hci_status) +{ + if (bta_sys_cb.p_role_cb) + { + bta_sys_cb.p_role_cb(BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda); + } +} + +/******************************************************************************* +** +** Function bta_sys_collision_register +** +** Description Called by any BTA module to register for collision event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_collision_register(UINT8 bta_id, tBTA_SYS_CONN_CBACK *p_cback) +{ + UINT8 index; + + for (index = 0; index < MAX_COLLISION_REG; index++) + { + if ((bta_sys_cb.colli_reg.id[index] == bta_id) || + (bta_sys_cb.colli_reg.id[index] == 0)) + { + bta_sys_cb.colli_reg.id[index] = bta_id; + bta_sys_cb.colli_reg.p_coll_cback[index] = p_cback; + return; + } + } +} + +/******************************************************************************* +** +** Function bta_sys_notify_collision +** +** Description Called by BTA DM to notify collision event. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_notify_collision (BD_ADDR_PTR p_bda) +{ + UINT8 index; + + for (index = 0; index < MAX_COLLISION_REG; index++) + { + if ((bta_sys_cb.colli_reg.id[index] != 0) && + (bta_sys_cb.colli_reg.p_coll_cback[index] != NULL)) + { + bta_sys_cb.colli_reg.p_coll_cback[index] (0, BTA_ID_SYS, 0, p_bda); + } + } +} + +/******************************************************************************* +** +** Function bta_sys_sco_register +** +** Description Called by BTA AV to register sco connection change callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.p_sco_cb = p_cback; +} + +/******************************************************************************* +** +** Function bta_sys_pm_register +** +** Description Called by BTA DM to register power management callbacks +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_pm_register(tBTA_SYS_CONN_CBACK * p_cback) +{ + bta_sys_cb.ppm_cb = p_cback; +} + +/******************************************************************************* +** +** Function bta_sys_conn_open +** +** Description Called by BTA subsystems when a connection is made to +** the service +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_conn_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.prm_cb) + { + + bta_sys_cb.prm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr); + + } + + if(bta_sys_cb.ppm_cb) + { + + bta_sys_cb.ppm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr); + + } +} + + + +/******************************************************************************* +** +** Function bta_sys_conn_close +** +** Description Called by BTA subsystems when a connection to the service +** is closed +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_conn_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.prm_cb) + { + + bta_sys_cb.prm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr); + + } + + if(bta_sys_cb.ppm_cb) + { + + bta_sys_cb.ppm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr); + + } +} + + +/******************************************************************************* +** +** Function bta_sys_app_open +** +** Description Called by BTA subsystems when application initiates connection +** to a peer device +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_app_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.ppm_cb) + { + bta_sys_cb.ppm_cb(BTA_SYS_APP_OPEN, id, app_id, peer_addr); + } +} + + + +/******************************************************************************* +** +** Function bta_sys_app_close +** +** Description Called by BTA subsystems when application initiates close +** of connection to peer device +** +** Returns void +** +*******************************************************************************/ +void bta_sys_app_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.ppm_cb) + { + bta_sys_cb.ppm_cb(BTA_SYS_APP_CLOSE, id, app_id, peer_addr); + } +} + + +/******************************************************************************* +** +** Function bta_sys_sco_open +** +** Description Called by BTA subsystems when sco connection for that service +** is open +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_open(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + /* AG triggers p_sco_cb by bta_sys_sco_use. */ + if((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) + { + /* without querying BTM_GetNumScoLinks() */ + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr); + } + + if(bta_sys_cb.ppm_cb) + { + bta_sys_cb.ppm_cb(BTA_SYS_SCO_OPEN, id, app_id, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_sco_close +** +** Description Called by BTA subsystems when sco connection for that service +** is closed +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_close(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + UINT8 num_sco_links; + + if((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) + { + num_sco_links = BTM_GetNumScoLinks(); + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr); + } + + if(bta_sys_cb.ppm_cb) + { + bta_sys_cb.ppm_cb(BTA_SYS_SCO_CLOSE, id, app_id, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_sco_use +** +** Description Called by BTA subsystems when that service needs to use sco. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_use(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + /* AV streaming need to be suspended before SCO is connected. */ + if(bta_sys_cb.p_sco_cb) + { + /* without querying BTM_GetNumScoLinks() */ + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_sco_unuse +** +** Description Called by BTA subsystems when sco connection for that service +** is no longer needed. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sco_unuse(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + UINT8 num_sco_links; + + if((bta_sys_cb.p_sco_cb)) + { + num_sco_links = BTM_GetNumScoLinks(); + bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr); + } +} +/******************************************************************************* +** +** Function bta_sys_chg_ssr_config +** +** Description Called by BTA subsystems to indicate that the given app SSR setting +** need to be changed. +** +** Returns void +** +*******************************************************************************/ +#if (BTM_SSR_INCLUDED == TRUE) +void bta_sys_chg_ssr_config (UINT8 id, UINT8 app_id, UINT16 max_latency, UINT16 min_tout) +{ + if(bta_sys_cb.p_ssr_cb) + { + bta_sys_cb.p_ssr_cb(id, app_id, max_latency, min_tout); + } +} +#endif +/******************************************************************************* +** +** Function bta_sys_set_policy +** +** Description Called by BTA subsystems to indicate that the given link +** policy to peer device should be set +** +** Returns void +** +*******************************************************************************/ +void bta_sys_set_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr) +{ + if(bta_sys_cb.p_policy_cb) + { + bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_SET, id, policy, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_clear_policy +** +** Description Called by BTA subsystems to indicate that the given link +** policy to peer device should be clear +** +** Returns void +** +*******************************************************************************/ +void bta_sys_clear_policy (UINT8 id, UINT8 policy, BD_ADDR peer_addr) +{ + if(bta_sys_cb.p_policy_cb) + { + bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_CLR, id, policy, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_set_default_policy +** +** Description Called by BTA subsystems to indicate that the given default +** link policy should be set +** +** Returns void +** +*******************************************************************************/ +void bta_sys_set_default_policy (UINT8 id, UINT8 policy) +{ + if(bta_sys_cb.p_policy_cb) + { + bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_SET, id, policy, NULL); + } +} + +/******************************************************************************* +** +** Function bta_sys_clear_default_policy +** +** Description Called by BTA subsystems to indicate that the given default +** link policy should be clear +** +** Returns void +** +*******************************************************************************/ +void bta_sys_clear_default_policy (UINT8 id, UINT8 policy) +{ + if(bta_sys_cb.p_policy_cb) + { + bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_CLR, id, policy, NULL); + } +} + +/******************************************************************************* +** +** Function bta_sys_idle +** +** Description Called by BTA subsystems to indicate that the connection to +** peer device is idle +** +** Returns void +** +*******************************************************************************/ +void bta_sys_idle(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + + if(bta_sys_cb.prm_cb) + { + + bta_sys_cb.prm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr); + + } + + if(bta_sys_cb.ppm_cb) + { + + bta_sys_cb.ppm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr); + } +} + +/******************************************************************************* +** +** Function bta_sys_busy +** +** Description Called by BTA subsystems to indicate that the connection to +** peer device is busy +** +** Returns void +** +*******************************************************************************/ +void bta_sys_busy(UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + if(bta_sys_cb.prm_cb) + { + + bta_sys_cb.prm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr); + + } + + if(bta_sys_cb.ppm_cb) + { + + bta_sys_cb.ppm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr); + + } +} + +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) +/******************************************************************************* +** +** Function bta_sys_eir_register +** +** Description Called by BTA DM to register EIR utility function that can be +** used by the other BTA modules to add/remove UUID. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_eir_register(tBTA_SYS_EIR_CBACK * p_cback) +{ + bta_sys_cb.eir_cb = p_cback; +} + +/******************************************************************************* +** +** Function bta_sys_add_uuid +** +** Description Called by BTA subsystems to indicate to DM that new service +** class UUID is added. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_add_uuid(UINT16 uuid16) +{ + if(bta_sys_cb.eir_cb) + { + bta_sys_cb.eir_cb(uuid16, TRUE ); + } +} + +/******************************************************************************* +** +** Function bta_sys_remove_uuid +** +** Description Called by BTA subsystems to indicate to DM that the service +** class UUID is removed. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_remove_uuid(UINT16 uuid16) +{ + if(bta_sys_cb.eir_cb) + { + bta_sys_cb.eir_cb(uuid16, FALSE); + } +} +#endif + diff --git a/bta/sys/bta_sys_int.h b/bta/sys/bta_sys_int.h new file mode 100644 index 0000000..d187b29 --- /dev/null +++ b/bta/sys/bta_sys_int.h @@ -0,0 +1,119 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 private interface file for the BTA system manager. + * + ******************************************************************************/ +#ifndef BTA_SYS_INT_H +#define BTA_SYS_INT_H + +#include "ptim.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/***************************************************************************** +** state table +*****************************************************************************/ + +/* SYS HW state */ +enum +{ + BTA_SYS_HW_OFF, + BTA_SYS_HW_STARTING, + BTA_SYS_HW_ON, + BTA_SYS_HW_STOPPING +}; +typedef UINT8 tBTA_SYS_HW_STATE; + +/* Collision callback */ +#define MAX_COLLISION_REG 5 + +typedef struct +{ + UINT8 id[MAX_COLLISION_REG]; + tBTA_SYS_CONN_CBACK *p_coll_cback[MAX_COLLISION_REG]; +} tBTA_SYS_COLLISION; + +/* system manager control block */ +typedef struct +{ + tBTA_SYS_REG *reg[BTA_ID_MAX]; /* registration structures */ + BOOLEAN is_reg[BTA_ID_MAX]; /* registration structures */ + tPTIM_CB ptim_cb; /* protocol timer list */ + BOOLEAN timers_disabled; /* TRUE if sys timers disabled */ + UINT8 task_id; /* GKI task id */ + tBTA_SYS_HW_STATE state; + tBTA_SYS_HW_CBACK *sys_hw_cback[BTA_SYS_MAX_HW_MODULES]; /* enable callback for each HW modules */ + UINT32 sys_hw_module_active; /* bitmask of all active modules */ + UINT16 sys_features; /* Bitmask of sys features */ + + tBTA_SYS_CONN_CBACK *prm_cb; /* role management callback registered by DM */ + tBTA_SYS_CONN_CBACK *ppm_cb; /* low power management callback registered by DM */ + tBTA_SYS_CONN_CBACK *p_policy_cb; /* link policy change callback registered by DM */ + tBTA_SYS_CONN_CBACK *p_sco_cb; /* SCO connection change callback registered by AV */ + tBTA_SYS_CONN_CBACK *p_role_cb; /* role change callback registered by AV */ + tBTA_SYS_COLLISION colli_reg; /* collision handling module */ +#if ( BTM_EIR_SERVER_INCLUDED == TRUE )&&(BTA_EIR_CANNED_UUID_LIST != TRUE) + tBTA_SYS_EIR_CBACK *eir_cb; /* add/remove UUID into EIR */ +#endif +#if (BTM_SSR_INCLUDED == TRUE) + tBTA_SYS_SSR_CFG_CBACK *p_ssr_cb; +#endif +} tBTA_SYS_CB; + + + + +/***************************************************************************** +** Global variables +*****************************************************************************/ + +/* system manager control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_SYS_CB bta_sys_cb; +#else +extern tBTA_SYS_CB *bta_sys_cb_ptr; +#define bta_sys_cb (*bta_sys_cb_ptr) +#endif + + +/* system manager configuration structure */ +extern tBTA_SYS_CFG *p_bta_sys_cfg; + + + +/* functions used for BTA SYS HW state machine */ +void bta_sys_hw_btm_cback( tBTM_DEV_STATUS status ); +void bta_sys_hw_error(tBTA_SYS_HW_MSG *p_sys_hw_msg); +void bta_sys_hw_api_enable( tBTA_SYS_HW_MSG *p_sys_hw_msg ); +void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG *p_sys_hw_msg); +void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg); +void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG *p_sys_hw_msg); +void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg); + +BOOLEAN bta_sys_sm_execute(BT_HDR *p_msg); + + + + + +#endif /* BTA_SYS_INT_H */ diff --git a/bta/sys/bta_sys_main.c b/bta/sys/bta_sys_main.c new file mode 100644 index 0000000..c1554bb --- /dev/null +++ b/bta/sys/bta_sys_main.c @@ -0,0 +1,722 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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 main implementation file for the BTA system manager. + * + ******************************************************************************/ + +#include "btm_api.h" +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_sys_int.h" +#include "bta_sys_ci.h" +#include "bta_sys_co.h" +#if BTA_FM_INCLUDED == TRUE +#include "bta_fm_api.h" +#endif +#if BTA_FMTX_INCLUDED == TRUE +#include "bta_fmtx_api.h" +#endif +#if GPS_INCLUDED == TRUE +#include "bta_gps_api.h" +#endif + +#include "gki.h" +#include "ptim.h" +#include <string.h> +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#include "bta_ar_api.h" +#endif + +/* protocol timer update period, in milliseconds */ +#ifndef BTA_SYS_TIMER_PERIOD +#define BTA_SYS_TIMER_PERIOD 1000 +#endif + +/* system manager control block definition */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_SYS_CB bta_sys_cb; +#endif + +/* trace level */ +/* TODO Bluedroid - Hard-coded trace levels - Needs to be configurable */ +UINT8 appl_trace_level = BT_TRACE_LEVEL_DEBUG; //APPL_INITIAL_TRACE_LEVEL; +UINT8 btif_trace_level = BT_TRACE_LEVEL_DEBUG; + +static const tBTA_SYS_REG bta_sys_hw_reg = +{ + bta_sys_sm_execute, + NULL +}; + + +/* type for action functions */ +typedef void (*tBTA_SYS_ACTION)(tBTA_SYS_HW_MSG *p_data); + +/* action function list */ +const tBTA_SYS_ACTION bta_sys_action[] = +{ + /* device manager local device API events - cf bta_sys.h for events */ + bta_sys_hw_api_enable, /* 0 BTA_SYS_HW_API_ENABLE_EVT */ + bta_sys_hw_evt_enabled, /* 1 BTA_SYS_HW_EVT_ENABLED_EVT */ + bta_sys_hw_evt_stack_enabled, /* 2 BTA_SYS_HW_EVT_STACK_ENABLED_EVT */ + bta_sys_hw_api_disable, /* 3 BTA_SYS_HW_API_DISABLE_EVT */ + bta_sys_hw_evt_disabled, /* 4 BTA_SYS_HW_EVT_DISABLED_EVT */ + bta_sys_hw_error /* 5 BTA_SYS_HW_ERROR_EVT */ +}; + +/* state machine action enumeration list */ +enum +{ + /* device manager local device API events */ + BTA_SYS_HW_API_ENABLE, + BTA_SYS_HW_EVT_ENABLED, + BTA_SYS_HW_EVT_STACK_ENABLED, + BTA_SYS_HW_API_DISABLE, + BTA_SYS_HW_EVT_DISABLED, + BTA_SYS_HW_ERROR +}; + +#define BTA_SYS_NUM_ACTIONS (BTA_SYS_MAX_EVT & 0x00ff) +#define BTA_SYS_IGNORE BTA_SYS_NUM_ACTIONS + +/* state table information */ +#define BTA_SYS_ACTIONS 2 /* number of actions */ +#define BTA_SYS_NEXT_STATE 2 /* position of next state */ +#define BTA_SYS_NUM_COLS 3 /* number of columns in state tables */ + + +/* state table for OFF state */ +const UINT8 bta_sys_hw_off[][BTA_SYS_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next State */ +/* API_ENABLE */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, +/* EVT_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, +/* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* API_DISABLE */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}, +/* EVT_DISABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}, +/* EVT_ERROR */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF} +}; + +const UINT8 bta_sys_hw_starting[][BTA_SYS_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next State */ +/* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, /* wait for completion event */ +/* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, +/* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* successive disable/enable: change state wait for completion to disable */ +/* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_HW_API_ENABLE, BTA_SYS_HW_STARTING}, /* successive enable/disable: notify, then restart HW */ +/* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON} +}; + +const UINT8 bta_sys_hw_on[][BTA_SYS_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next State */ +/* API_ENABLE */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* EVT_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* API_DISABLE */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, /* don't change the state here, as some other modules might be active */ +/* EVT_DISABLED */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}, +/* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON} +}; + +const UINT8 bta_sys_hw_stopping[][BTA_SYS_NUM_COLS] = +{ +/* Event Action 1 Action 2 Next State */ +/* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, /* change state, and wait for completion event to enable */ +/* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* successive enable/disable: finish the enable before disabling */ +/* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_HW_API_DISABLE, BTA_SYS_HW_STOPPING}, /* successive enable/disable: notify, then stop */ +/* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* wait for completion event */ +/* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}, +/* EVT_ERROR */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING} +}; + +typedef const UINT8 (*tBTA_SYS_ST_TBL)[BTA_SYS_NUM_COLS]; + +/* state table */ +const tBTA_SYS_ST_TBL bta_sys_st_tbl[] = { + bta_sys_hw_off, + bta_sys_hw_starting, + bta_sys_hw_on, + bta_sys_hw_stopping +}; + +/******************************************************************************* +** +** Function bta_sys_init +** +** Description BTA initialization; called from task initialization. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void bta_sys_init(void) +{ + memset(&bta_sys_cb, 0, sizeof(tBTA_SYS_CB)); + ptim_init(&bta_sys_cb.ptim_cb, BTA_SYS_TIMER_PERIOD, p_bta_sys_cfg->timer); + bta_sys_cb.task_id = GKI_get_taskid(); + appl_trace_level = p_bta_sys_cfg->trace_level; + + /* register BTA SYS message handler */ + bta_sys_register( BTA_ID_SYS, &bta_sys_hw_reg); + + /* register for BTM notifications */ + BTM_RegisterForDeviceStatusNotif ((tBTM_DEV_STATUS_CB*)&bta_sys_hw_btm_cback ); + +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + bta_ar_init(); +#endif + +} + +/******************************************************************************* +** +** Function bta_dm_sm_execute +** +** Description State machine event handling function for DM +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_sys_sm_execute(BT_HDR *p_msg) +{ + BOOLEAN freebuf = TRUE; + tBTA_SYS_ST_TBL state_table; + UINT8 action; + int i; + + APPL_TRACE_EVENT2("bta_sys_sm_execute state:%d, event:0x%x", bta_sys_cb.state, p_msg->event); + + /* look up the state table for the current state */ + state_table = bta_sys_st_tbl[bta_sys_cb.state]; + /* update state */ + bta_sys_cb.state = state_table[p_msg->event & 0x00ff][BTA_SYS_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_SYS_ACTIONS; i++) + { + if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_SYS_IGNORE) + { + (*bta_sys_action[action])( (tBTA_SYS_HW_MSG*) p_msg); + } + else + { + break; + } + } + return freebuf; + +} + + +void bta_sys_hw_register( tBTA_SYS_HW_MODULE module, tBTA_SYS_HW_CBACK *cback) +{ + bta_sys_cb.sys_hw_cback[module]=cback; +} + + +void bta_sys_hw_unregister( tBTA_SYS_HW_MODULE module ) +{ + bta_sys_cb.sys_hw_cback[module]=NULL; +} + +/******************************************************************************* +** +** Function bta_sys_hw_btm_cback +** +** Description This function is registered by BTA SYS to BTM in order to get status notifications +** +** +** Returns +** +*******************************************************************************/ +void bta_sys_hw_btm_cback( tBTM_DEV_STATUS status ) +{ + + tBTA_SYS_HW_MSG *sys_event; + + APPL_TRACE_DEBUG1(" bta_sys_hw_btm_cback was called with parameter: %i" , status ); + + /* send a message to BTA SYS */ + if ((sys_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) + { + if (status == BTM_DEV_STATUS_UP) + sys_event->hdr.event = BTA_SYS_EVT_STACK_ENABLED_EVT; + else if (status == BTM_DEV_STATUS_DOWN) + sys_event->hdr.event = BTA_SYS_ERROR_EVT; + else + { + /* BTM_DEV_STATUS_CMD_TOUT is ignored for now. */ + GKI_freebuf (sys_event); + sys_event = NULL; + } + + if (sys_event) + { + bta_sys_sendmsg(sys_event); + } + } + else + { + APPL_TRACE_DEBUG0("ERROR bta_sys_hw_btm_cback couldn't send msg" ); + } +} + + + +/******************************************************************************* +** +** Function bta_sys_hw_error +** +** Description In case the HW device stops answering... Try to turn it off, then re-enable all +** previously active SW modules. +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_error(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + + UINT8 module_index; + + APPL_TRACE_DEBUG1("%s", __FUNCTION__); + + for (module_index = 0; module_index < BTA_SYS_MAX_HW_MODULES; module_index++) + { + if( bta_sys_cb.sys_hw_module_active & ((UINT32)1 << module_index )) { + switch( module_index) + { + case BTA_SYS_HW_BLUETOOTH: + /* Send BTA_SYS_HW_ERROR_EVT to DM */ + if (bta_sys_cb.sys_hw_cback[module_index] != NULL) + bta_sys_cb.sys_hw_cback[module_index] (BTA_SYS_HW_ERROR_EVT); + break; + default: + /* not yet supported */ + break; + } + } + } +} + + + +/******************************************************************************* +** +** Function bta_sys_hw_enable +** +** Description this function is called after API enable and HW has been turned on +** +** +** Returns success or failure +** +*******************************************************************************/ + +void bta_sys_hw_api_enable( tBTA_SYS_HW_MSG *p_sys_hw_msg ) +{ + if ((!bta_sys_cb.sys_hw_module_active) && (bta_sys_cb.state != BTA_SYS_HW_ON)) + { + /* register which HW module was turned on */ + bta_sys_cb.sys_hw_module_active |= ((UINT32)1 << p_sys_hw_msg->hw_module ); + + /* use call-out to power-up HW */ + bta_sys_hw_co_enable(p_sys_hw_msg->hw_module); + } + else + { + /* register which HW module was turned on */ + bta_sys_cb.sys_hw_module_active |= ((UINT32)1 << p_sys_hw_msg->hw_module ); + + /* HW already in use, so directly notify the caller */ + if (bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]!= NULL ) + bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]( BTA_SYS_HW_ON_EVT ); + } + + APPL_TRACE_EVENT2 ("bta_sys_hw_api_enable for %d, active modules 0x%04X", + p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active); + +} + +/******************************************************************************* +** +** Function bta_sys_hw_disable +** +** Description if no other module is using the HW, this function will call ( if defined ) a user-macro to turn off the HW +** +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + APPL_TRACE_DEBUG2("bta_sys_hw_api_disable for %d, active modules: 0x%04X", + p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active ); + + /* make sure the related SW blocks were stopped */ + bta_sys_disable( p_sys_hw_msg->hw_module ); + + + /* register which module we turn off */ + bta_sys_cb.sys_hw_module_active &= ~((UINT32)1 << p_sys_hw_msg->hw_module ); + + + /* if there are still some SW modules using the HW, just provide an answer to the calling */ + if( bta_sys_cb.sys_hw_module_active != 0 ) + { + /* if there are still some SW modules using the HW, directly notify the caller */ + if( bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]!= NULL ) + bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]( BTA_SYS_HW_OFF_EVT ); + } + else + { + /* manually update the state of our system */ + bta_sys_cb.state = BTA_SYS_HW_STOPPING; + /* and use the call-out to disable HW */ + bta_sys_hw_co_disable(p_sys_hw_msg->hw_module); + } + +} + + +/******************************************************************************* +** +** Function bta_sys_hw_event_enabled +** +** Description +** +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + APPL_TRACE_EVENT1("bta_sys_hw_evt_enabled for %i", p_sys_hw_msg->hw_module); + +#if ( defined BTM_AUTOMATIC_HCI_RESET && BTM_AUTOMATIC_HCI_RESET == TRUE ) + /* If device is already up, send a fake "BTM DEVICE UP" using BTA SYS state machine */ + /* If we are in the middle device initialization, BTM_DEVICE_UP will be issued */ + /* by BTM once initialization is done. */ + if (BTA_DmIsDeviceUp()) + { + bta_sys_hw_btm_cback (BTM_DEV_STATUS_UP); + } +#else + + /* if HCI reset was not sent during stack start-up */ + BTM_DeviceReset( NULL ); + +#endif +} + + +/******************************************************************************* +** +** Function bta_sys_hw_event_disabled +** +** Description +** +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + UINT8 hw_module_index; + + APPL_TRACE_DEBUG1("bta_sys_hw_evt_disabled - module 0x%X", p_sys_hw_msg->hw_module); + + for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES; hw_module_index++) + { + if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL) + bta_sys_cb.sys_hw_cback[hw_module_index] (BTA_SYS_HW_OFF_EVT); + } +} + +/******************************************************************************* +** +** Function bta_sys_hw_event_stack_enabled +** +** Description we receive this event from once the SW side is ready ( stack, FW download,... ), +** i.e. we can really start using the device. So notify the app. +** +** Returns success or failure +** +*******************************************************************************/ +void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG *p_sys_hw_msg) +{ + UINT8 hw_module_index; + + APPL_TRACE_DEBUG0(" bta_sys_hw_evt_stack_enabled!notify the callers"); + + for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES; hw_module_index++ ) + { + if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL) + bta_sys_cb.sys_hw_cback[hw_module_index] (BTA_SYS_HW_ON_EVT); + } +} + + + + +/******************************************************************************* +** +** Function bta_sys_event +** +** Description BTA event handler; called from task event handler. +** +** +** Returns void +** +*******************************************************************************/ +BTA_API void bta_sys_event(BT_HDR *p_msg) +{ + UINT8 id; + BOOLEAN freebuf = TRUE; + + APPL_TRACE_EVENT1("BTA got event 0x%x", p_msg->event); + + /* get subsystem id from event */ + id = (UINT8) (p_msg->event >> 8); + + /* verify id and call subsystem event handler */ + if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) + { + freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg); + } + else + { + APPL_TRACE_WARNING1("BTA got unregistered event id %d", id); + } + + if (freebuf) + { + GKI_freebuf(p_msg); + } + +} + +/******************************************************************************* +** +** Function bta_sys_timer_update +** +** Description Update the BTA timer list and handle expired timers. +** +** Returns void +** +*******************************************************************************/ +BTA_API void bta_sys_timer_update(void) +{ + if (!bta_sys_cb.timers_disabled) + { + ptim_timer_update(&bta_sys_cb.ptim_cb); + } +} + +/******************************************************************************* +** +** Function bta_sys_register +** +** Description Called by other BTA subsystems to register their event +** handler. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_register(UINT8 id, const tBTA_SYS_REG *p_reg) +{ + bta_sys_cb.reg[id] = (tBTA_SYS_REG *) p_reg; + bta_sys_cb.is_reg[id] = TRUE; +} + +/******************************************************************************* +** +** Function bta_sys_deregister +** +** Description Called by other BTA subsystems to de-register +** handler. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_deregister(UINT8 id) +{ + bta_sys_cb.is_reg[id] = FALSE; +} + +/******************************************************************************* +** +** Function bta_sys_is_register +** +** Description Called by other BTA subsystems to get registeration +** status. +** +** +** Returns void +** +*******************************************************************************/ +BOOLEAN bta_sys_is_register(UINT8 id) +{ + return bta_sys_cb.is_reg[id]; +} + +/******************************************************************************* +** +** Function bta_sys_sendmsg +** +** Description Send a GKI message to BTA. This function is designed to +** optimize sending of messages to BTA. It is called by BTA +** API functions and call-in functions. +** +** +** Returns void +** +*******************************************************************************/ +void bta_sys_sendmsg(void *p_msg) +{ + GKI_send_msg(bta_sys_cb.task_id, p_bta_sys_cfg->mbox, p_msg); +} + +/******************************************************************************* +** +** Function bta_sys_start_timer +** +** Description Start a protocol timer for the specified amount +** of time in milliseconds. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout) +{ + ptim_start_timer(&bta_sys_cb.ptim_cb, p_tle, type, timeout); +} + +/******************************************************************************* +** +** Function bta_sys_stop_timer +** +** Description Stop a BTA timer. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_stop_timer(TIMER_LIST_ENT *p_tle) +{ + ptim_stop_timer(&bta_sys_cb.ptim_cb, p_tle); +} + +/******************************************************************************* +** +** Function bta_sys_disable +** +** Description For each registered subsystem execute its disable function. +** +** Returns void +** +*******************************************************************************/ +void bta_sys_disable(tBTA_SYS_HW_MODULE module) +{ + int bta_id = 0; + int bta_id_max = 0; + + APPL_TRACE_DEBUG1("bta_sys_disable: module %i", module); + + switch( module ) + { + case BTA_SYS_HW_BLUETOOTH: + bta_id = BTA_ID_DM; + bta_id_max = BTA_ID_BLUETOOTH_MAX; + break; + case BTA_SYS_HW_FMRX: + bta_id = BTA_ID_FM; + bta_id_max = BTA_ID_FM; + break; + case BTA_SYS_HW_FMTX: + bta_id = BTA_ID_FMTX; + bta_id_max = BTA_ID_FMTX; + break; + case BTA_SYS_HW_GPS: + bta_id = BTA_ID_GPS; + bta_id_max = BTA_ID_GPS; + break; + default: + APPL_TRACE_WARNING0("bta_sys_disable: unkown module"); + return; + } + + for ( ; bta_id <= bta_id_max; bta_id++) + { + if (bta_sys_cb.reg[bta_id] != NULL) + { + if (bta_sys_cb.is_reg[bta_id] == TRUE && bta_sys_cb.reg[bta_id]->disable != NULL) + { + (*bta_sys_cb.reg[bta_id]->disable)(); + } + } + } +} + +/******************************************************************************* +** +** Function bta_sys_disable_timers +** +** Description Disable sys timer event handling +** +** Returns void +** +*******************************************************************************/ +void bta_sys_disable_timers(void) +{ + bta_sys_cb.timers_disabled = TRUE; +} + +/******************************************************************************* +** +** Function bta_sys_set_trace_level +** +** Description Set trace level for BTA +** +** Returns void +** +*******************************************************************************/ +void bta_sys_set_trace_level(UINT8 level) +{ + appl_trace_level = level; +} + +/******************************************************************************* +** +** Function bta_sys_get_sys_features +** +** Description Returns sys_features to other BTA modules. +** +** Returns sys_features +** +*******************************************************************************/ +UINT16 bta_sys_get_sys_features (void) +{ + return bta_sys_cb.sys_features; +} + + diff --git a/bta/sys/ptim.c b/bta/sys/ptim.c new file mode 100644 index 0000000..9dffc66 --- /dev/null +++ b/bta/sys/ptim.c @@ -0,0 +1,162 @@ +/****************************************************************************** + * + * Copyright (C) 2003-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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Protocol timer services. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "gki.h" +#include "ptim.h" +#include "bta_sys.h" + +/******************************************************************************* +** +** Function ptim_init +** +** Description Initialize a protocol timer control block. Parameter +** period is the GKI timer period in milliseconds. Parameter +** timer_id is the GKI timer id. +** +** Returns void +** +*******************************************************************************/ +void ptim_init(tPTIM_CB *p_cb, UINT16 period, UINT8 timer_id) +{ + GKI_init_timer_list(&p_cb->timer_queue); + p_cb->period = period; + p_cb->timer_id = timer_id; +} + +/******************************************************************************* +** +** Function ptim_timer_update +** +** Description Update the protocol timer list and handle expired timers. +** This function is called from the task running the protocol +** timers when the periodic GKI timer expires. +** +** Returns void +** +*******************************************************************************/ +void ptim_timer_update(tPTIM_CB *p_cb) +{ + TIMER_LIST_ENT *p_tle; + BT_HDR *p_msg; + UINT32 new_ticks_count; + INT32 period_in_ticks; + + /* To handle the case when the function is called less frequently than the period + we must convert determine the number of ticks since the last update, then + convert back to milliseconds before updating timer list */ + new_ticks_count = GKI_get_tick_count(); + + /* Check for wrapped condition */ + if (new_ticks_count >= p_cb->last_gki_ticks) + { + period_in_ticks = (INT32)(new_ticks_count - p_cb->last_gki_ticks); + } + else + { + period_in_ticks = (INT32)(((UINT32)0xffffffff - p_cb->last_gki_ticks) + + new_ticks_count + 1); + } + + /* update timer list */ + GKI_update_timer_list(&p_cb->timer_queue, GKI_TICKS_TO_MS(period_in_ticks)); + + p_cb->last_gki_ticks = new_ticks_count; + + /* while there are expired timers */ + while((p_cb->timer_queue.p_first) && (p_cb->timer_queue.p_first->ticks <= 0)) + { + /* removed expired timer from list */ + p_tle = p_cb->timer_queue.p_first; + GKI_remove_from_timer_list(&p_cb->timer_queue, p_tle); + + /* call timer callback */ + if(p_tle->p_cback) + { + (*p_tle->p_cback)(p_tle); + } + else if(p_tle->event) + { + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_msg->event = p_tle->event; + p_msg->layer_specific = 0; + bta_sys_sendmsg(p_msg); + } + } + } + + /* if timer list is empty stop periodic GKI timer */ + if (p_cb->timer_queue.p_first == NULL) + { + GKI_stop_timer(p_cb->timer_id); + } +} + +/******************************************************************************* +** +** Function ptim_start_timer +** +** Description Start a protocol timer for the specified amount +** of time in seconds. +** +** Returns void +** +*******************************************************************************/ +void ptim_start_timer(tPTIM_CB *p_cb, TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout) +{ + /* if timer list is currently empty, start periodic GKI timer */ + if (p_cb->timer_queue.p_first == NULL) + { + p_cb->last_gki_ticks = GKI_get_tick_count(); + GKI_start_timer(p_cb->timer_id, GKI_MS_TO_TICKS(p_cb->period), TRUE); + } + + GKI_remove_from_timer_list(&p_cb->timer_queue, p_tle); + + p_tle->event = type; + p_tle->ticks = timeout; + + GKI_add_to_timer_list(&p_cb->timer_queue, p_tle); +} + +/******************************************************************************* +** +** Function ptim_stop_timer +** +** Description Stop a protocol timer. +** +** Returns void +** +*******************************************************************************/ +void ptim_stop_timer(tPTIM_CB *p_cb, TIMER_LIST_ENT *p_tle) +{ + GKI_remove_from_timer_list (&p_cb->timer_queue, p_tle); + + /* if timer list is empty stop periodic GKI timer */ + if (p_cb->timer_queue.p_first == NULL) + { + GKI_stop_timer(p_cb->timer_id); + } +} diff --git a/bta/sys/utl.c b/bta/sys/utl.c new file mode 100644 index 0000000..4bb1d95 --- /dev/null +++ b/bta/sys/utl.c @@ -0,0 +1,296 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains utility functions. + * + ******************************************************************************/ +#include "utl.h" +#include "gki.h" +#include "btm_api.h" + +/******************************************************************************* +** +** Function utl_str2int +** +** Description This utility function converts a character string to an +** integer. Acceptable values in string are 0-9. If invalid +** string or string value too large, -1 is returned. Leading +** spaces are skipped. +** +** +** Returns Integer value or -1 on error. +** +*******************************************************************************/ +INT16 utl_str2int(const char *p_s) +{ + INT32 val = 0; + + for (;*p_s == ' ' && *p_s != 0; p_s++); + + if (*p_s == 0) return -1; + + for (;;) + { + if ((*p_s < '0') || (*p_s > '9')) return -1; + + val += (INT32) (*p_s++ - '0'); + + if (val > 32767) return -1; + + if (*p_s == 0) + { + return (INT16) val; + } + else + { + val *= 10; + } + } +} + +/******************************************************************************* +** +** Function utl_strucmp +** +** Description This utility function compares two strings in uppercase. +** String p_s must be uppercase. String p_t is converted to +** uppercase if lowercase. If p_s ends first, the substring +** match is counted as a match. +** +** +** Returns 0 if strings match, nonzero otherwise. +** +*******************************************************************************/ +int utl_strucmp(const char *p_s, const char *p_t) +{ + char c; + + while (*p_s && *p_t) + { + c = *p_t++; + if (c >= 'a' && c <= 'z') + { + c -= 0x20; + } + if (*p_s++ != c) + { + return -1; + } + } + /* if p_t hit null first, no match */ + if (*p_t == 0 && *p_s != 0) + { + return 1; + } + /* else p_s hit null first, count as match */ + else + { + return 0; + } +} + +/******************************************************************************* +** +** Function utl_itoa +** +** Description This utility function converts a UINT16 to a string. The +** string is NULL-terminated. The length of the string is +** returned; +** +** +** Returns Length of string. +** +*******************************************************************************/ +UINT8 utl_itoa(UINT16 i, char *p_s) +{ + UINT16 j, k; + char *p = p_s; + BOOLEAN fill = FALSE; + + if (i == 0) + { + /* take care of zero case */ + *p++ = '0'; + } + else + { + for(j = 10000; j > 0; j /= 10) + { + k = i / j; + i %= j; + if (k > 0 || fill) + { + *p++ = k + '0'; + fill = TRUE; + } + } + } + *p = 0; + return (UINT8) (p - p_s); +} + +/******************************************************************************* +** +** Function utl_freebuf +** +** Description This function calls GKI_freebuf to free the buffer passed +** in, if buffer pointer is not NULL, and also initializes +** buffer pointer to NULL. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void utl_freebuf(void **p) +{ + if (*p != NULL) + { + GKI_freebuf(*p); + *p = NULL; + } +} + + +/******************************************************************************* +** +** Function utl_set_device_class +** +** Description This function updates the local Device Class. +** +** Parameters: +** p_cod - Pointer to the device class to set to +** +** cmd - the fields of the device class to update. +** BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major, minor class +** BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in the input +** BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in the input +** BTA_UTL_SET_COD_ALL - overwrite major, minor, set the bits in service class +** BTA_UTL_INIT_COD - overwrite major, minor, and service class +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +BOOLEAN utl_set_device_class(tBTA_UTL_COD *p_cod, UINT8 cmd) +{ + UINT8 *dev; + UINT16 service; + UINT8 minor, major; + DEV_CLASS dev_class; + + dev = BTM_ReadDeviceClass(); + BTM_COD_SERVICE_CLASS( service, dev ); + BTM_COD_MINOR_CLASS(minor, dev ); + BTM_COD_MAJOR_CLASS(major, dev ); + + switch(cmd) + { + case BTA_UTL_SET_COD_MAJOR_MINOR: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + break; + + case BTA_UTL_SET_COD_SERVICE_CLASS: + /* clear out the bits that is not SERVICE_CLASS bits */ + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service | p_cod->service; + break; + + case BTA_UTL_CLR_COD_SERVICE_CLASS: + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service & (~p_cod->service); + break; + + case BTA_UTL_SET_COD_ALL: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + p_cod->service &= BTM_COD_SERVICE_CLASS_MASK; + service = service | p_cod->service; + break; + + case BTA_UTL_INIT_COD: + minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK; + major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK; + service = p_cod->service & BTM_COD_SERVICE_CLASS_MASK; + break; + + default: + return FALSE; + } + + /* convert the fields into the device class type */ + FIELDS_TO_COD(dev_class, minor, major, service); + + if (BTM_SetDeviceClass(dev_class) == BTM_SUCCESS) + return TRUE; + + return FALSE; +} + +/******************************************************************************* +** +** Function utl_isintstr +** +** Description This utility function checks if the given string is an +** integer string or not +** +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +BOOLEAN utl_isintstr(const char *p_s) +{ + UINT16 i = 0; + + for(i=0; p_s[i] != 0; i++) + { + if(((p_s[i] < '0') || (p_s[i] > '9')) && (p_s[i] != ';')) + return FALSE; + } + + return TRUE; +} + +/******************************************************************************* +** +** Function utl_isdialstr +** +** Description This utility function checks if the given string contains +** only dial digits or not +** +** +** Returns TRUE if successful, Otherwise FALSE +** +*******************************************************************************/ +BOOLEAN utl_isdialstr(const char *p_s) +{ + UINT16 i = 0; + + for(i=0; p_s[i] != 0; i++) + { + if(!(((p_s[i] >= '0') && (p_s[i] <= '9')) + || (p_s[i] == '*') || (p_s[i] == '+') || (p_s[i] == '#') || (p_s[i] == ';') + || ((p_s[i] >= 'A') && (p_s[i] <= 'C')))) + return FALSE; + } + + return TRUE; +} + + |