component/bt: transport bluedroid avct, avdt, avrc and a2dp module to stack

This commit is contained in:
wangmengyang 2016-11-02 17:42:26 +08:00
parent d472ff5856
commit e3a4f23c9d
38 changed files with 13791 additions and 5 deletions

View File

@ -0,0 +1,395 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* ommon API for the Advanced Audio Distribution Profile (A2DP)
*
******************************************************************************/
#include <string.h>
#include "bt_target.h"
#include "sdpdefs.h"
#include "a2d_api.h"
#include "a2d_int.h"
#include "avdt_api.h"
/*****************************************************************************
** Global data
*****************************************************************************/
#if A2D_DYNAMIC_MEMORY == FALSE
tA2D_CB a2d_cb;
#endif
/******************************************************************************
**
** Function a2d_sdp_cback
**
** Description This is the SDP callback function used by A2D_FindService.
** 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 various parameters
** from the record. When it is finished it calls the
** application callback function.
**
** Returns Nothing.
**
******************************************************************************/
static void a2d_sdp_cback(UINT16 status)
{
tSDP_DISC_REC *p_rec = NULL;
tSDP_DISC_ATTR *p_attr;
BOOLEAN found = FALSE;
tA2D_Service a2d_svc;
tSDP_PROTOCOL_ELEM elem;
A2D_TRACE_API("a2d_sdp_cback status: %d", status);
if (status == SDP_SUCCESS)
{
/* loop through all records we found */
do
{
/* get next record; if none found, we're done */
if ((p_rec = SDP_FindServiceInDb(a2d_cb.find.p_db,
a2d_cb.find.service_uuid, p_rec)) == NULL)
{
break;
}
memset(&a2d_svc, 0, sizeof(tA2D_Service));
/* get service name */
if ((p_attr = SDP_FindAttributeInRec(p_rec,
ATTR_ID_SERVICE_NAME)) != NULL)
{
a2d_svc.p_service_name = (char *) p_attr->attr_value.v.array;
a2d_svc.service_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
}
/* get provider name */
if ((p_attr = SDP_FindAttributeInRec(p_rec,
ATTR_ID_PROVIDER_NAME)) != NULL)
{
a2d_svc.p_provider_name = (char *) p_attr->attr_value.v.array;
a2d_svc.provider_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
}
/* get supported features */
if ((p_attr = SDP_FindAttributeInRec(p_rec,
ATTR_ID_SUPPORTED_FEATURES)) != NULL)
{
a2d_svc.features = p_attr->attr_value.v.u16;
}
/* get AVDTP version */
if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem))
{
a2d_svc.avdt_version = elem.params[0];
A2D_TRACE_DEBUG("avdt_version: 0x%x", a2d_svc.avdt_version);
}
/* we've got everything, we're done */
found = TRUE;
break;
} while (TRUE);
}
a2d_cb.find.service_uuid = 0;
/* return info from sdp record in app callback function */
if (a2d_cb.find.p_cback != NULL)
{
(*a2d_cb.find.p_cback)(found, &a2d_svc);
}
return;
}
/*******************************************************************************
**
** Function a2d_set_avdt_sdp_ver
**
** Description This function allows the script wrapper to change the
** avdt version of a2dp.
**
** Returns None
**
*******************************************************************************/
void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver)
{
a2d_cb.avdt_sdp_ver = avdt_sdp_ver;
}
/******************************************************************************
**
** Function A2D_AddRecord
**
** Description This function is called by a server application to add
** SRC or SNK information to an SDP record. Prior to
** calling this function the application must call
** SDP_CreateRecord() to create an SDP record.
**
** Input Parameters:
** service_uuid: Indicates SRC or SNK.
**
** p_service_name: Pointer to a null-terminated character
** string containing the service name.
**
** p_provider_name: Pointer to a null-terminated character
** string containing the provider name.
**
** features: Profile supported features.
**
** sdp_handle: SDP handle returned by SDP_CreateRecord().
**
** Output Parameters:
** None.
**
** Returns A2D_SUCCESS if function execution succeeded,
** A2D_INVALID_PARAMS if bad parameters are given.
** A2D_FAIL if function execution failed.
**
******************************************************************************/
tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name,
UINT16 features, UINT32 sdp_handle)
{
UINT16 browse_list[1];
BOOLEAN result = TRUE;
UINT8 temp[8];
UINT8 *p;
tSDP_PROTOCOL_ELEM proto_list [A2D_NUM_PROTO_ELEMS];
A2D_TRACE_API("A2D_AddRecord uuid: %x", service_uuid);
if( (sdp_handle == 0) ||
(service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) )
return A2D_INVALID_PARAMS;
/* add service class id list */
result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid);
memset((void*) proto_list, 0 , A2D_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
/* add protocol descriptor list */
proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
proto_list[0].num_params = 1;
proto_list[0].params[0] = AVDT_PSM;
proto_list[1].protocol_uuid = UUID_PROTOCOL_AVDTP;
proto_list[1].num_params = 1;
proto_list[1].params[0] = a2d_cb.avdt_sdp_ver;
result &= SDP_AddProtocolList(sdp_handle, A2D_NUM_PROTO_ELEMS, proto_list);
/* add profile descriptor list */
result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2D_VERSION);
/* add supported feature */
if (features != 0)
{
p = temp;
UINT16_TO_BE_STREAM(p, features);
result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE,
(UINT32)2, (UINT8*)temp);
}
/* add provider name */
if (p_provider_name != NULL)
{
result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
(UINT32)(strlen(p_provider_name)+1), (UINT8 *) p_provider_name);
}
/* add service name */
if (p_service_name != NULL)
{
result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
(UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
}
/* add browse group list */
browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
return (result ? A2D_SUCCESS : A2D_FAIL);
}
/******************************************************************************
**
** Function A2D_FindService
**
** Description This function is called by a client application to
** perform service discovery and retrieve SRC or SNK SDP
** record information from a server. Information is
** returned for the first service record found on the
** server that matches the service UUID. The callback
** function will be executed when service discovery is
** complete. There can only be one outstanding call to
** A2D_FindService() at a time; the application must wait
** for the callback before it makes another call to
** the function.
**
** Input Parameters:
** service_uuid: Indicates SRC or SNK.
**
** bd_addr: BD address of the peer device.
**
** p_db: Pointer to the information to initialize
** the discovery database.
**
** p_cback: Pointer to the A2D_FindService()
** callback function.
**
** Output Parameters:
** None.
**
** Returns A2D_SUCCESS if function execution succeeded,
** A2D_INVALID_PARAMS if bad parameters are given.
** A2D_BUSY if discovery is already in progress.
** A2D_FAIL if function execution failed.
**
******************************************************************************/
tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback)
{
tSDP_UUID uuid_list;
BOOLEAN result = TRUE;
UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2D_NUM_ATTR, if changed */
ATTR_ID_BT_PROFILE_DESC_LIST,
ATTR_ID_SUPPORTED_FEATURES,
ATTR_ID_SERVICE_NAME,
ATTR_ID_PROTOCOL_DESC_LIST,
ATTR_ID_PROVIDER_NAME};
A2D_TRACE_API("A2D_FindService uuid: %x", service_uuid);
if( (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) ||
p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
return A2D_INVALID_PARAMS;
if( a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SOURCE ||
a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK)
return A2D_BUSY;
/* set up discovery database */
uuid_list.len = LEN_UUID_16;
uuid_list.uu.uuid16 = service_uuid;
if(p_db->p_attrs == NULL || p_db->num_attr == 0)
{
p_db->p_attrs = a2d_attr_list;
p_db->num_attr = A2D_NUM_ATTR;
}
result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr,
p_db->p_attrs);
if (result == TRUE)
{
/* store service_uuid and discovery db pointer */
a2d_cb.find.p_db = p_db->p_db;
a2d_cb.find.service_uuid = service_uuid;
a2d_cb.find.p_cback = p_cback;
/* perform service search */
result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, a2d_sdp_cback);
if(FALSE == result)
{
a2d_cb.find.service_uuid = 0;
}
}
return (result ? A2D_SUCCESS : A2D_FAIL);
}
/******************************************************************************
**
** Function A2D_SetTraceLevel
**
** Description Sets the trace level for A2D. If 0xff is passed, the
** current trace level is returned.
**
** Input Parameters:
** new_level: The level to set the A2D tracing to:
** 0xff-returns the current setting.
** 0-turns off tracing.
** >= 1-Errors.
** >= 2-Warnings.
** >= 3-APIs.
** >= 4-Events.
** >= 5-Debug.
**
** Returns The new trace level or current trace level if
** the input parameter is 0xff.
**
******************************************************************************/
UINT8 A2D_SetTraceLevel (UINT8 new_level)
{
if (new_level != 0xFF)
a2d_cb.trace_level = new_level;
return (a2d_cb.trace_level);
}
/******************************************************************************
** Function A2D_BitsSet
**
** Description Check the given num for the number of bits set
** Returns A2D_SET_ONE_BIT, if one and only one bit is set
** A2D_SET_ZERO_BIT, if all bits clear
** A2D_SET_MULTL_BIT, if multiple bits are set
******************************************************************************/
UINT8 A2D_BitsSet(UINT8 num)
{
UINT8 count;
BOOLEAN res;
if(num == 0)
res = A2D_SET_ZERO_BIT;
else
{
count = (num & (num - 1));
res = ((count==0)?A2D_SET_ONE_BIT:A2D_SET_MULTL_BIT);
}
return res;
}
/*******************************************************************************
**
** Function A2D_Init
**
** Description This function is called to initialize the control block
** for this layer. It must be called before accessing any
** other API functions for this layer. It is typically called
** once during the start up of the stack.
**
** Returns void
**
*******************************************************************************/
void A2D_Init(void)
{
memset(&a2d_cb, 0, sizeof(tA2D_CB));
a2d_cb.avdt_sdp_ver = AVDT_VERSION;
#if defined(A2D_INITIAL_TRACE_LEVEL)
a2d_cb.trace_level = A2D_INITIAL_TRACE_LEVEL;
#else
a2d_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
}

View File

@ -0,0 +1,399 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* Utility functions to help build and parse SBC Codec Information Element
* and Media Payload.
*
******************************************************************************/
#include "bt_target.h"
#include <string.h>
#include "a2d_api.h"
#include "a2d_int.h"
#include "a2d_sbc.h"
#include "bt_utils.h"
/*************************************************************************************************
* SBC descramble code
* Purpose: to tie the SBC code with BTE/mobile stack code,
* especially for the case when the SBC is ported into a third-party Multimedia chip
*
* Algorithm:
* init process: all counters reset to 0,
* calculate base_index: (6 + s16NumOfChannels*s16NumOfSubBands/2)
* scramble side: the init process happens every time SBC_Encoder_Init() is called.
* descramble side: it would be nice to know if he "init" process has happened.
* alter the SBC SYNC word 0x9C (1001 1100) to 0x8C (1000 1100).
*
* scramble process:
* The CRC byte:
* Every SBC frame has a frame header.
* The 1st byte is the sync word and the following 2 bytes are about the stream format.
* They are supposed to be "constant" within a "song"
* The 4th byte is the CRC byte. The CRC byte is bound to be random.
* Derive 2 items from the CRC byte; one is the "use" bit, the other is the "index".
*
* SBC keeps 2 sets of "use" & "index"; derived the current and the previous frame.
*
* The "use" bit is any bit in SBC_PRTC_USE_MASK is set.
* If set, SBC uses the "index" from the current frame.
* If not set, SBC uses the "index" from the previous frame or 0.
*
* index = (CRC & 0x3) + ((CRC & 0x30) >> 2) // 8 is the max index
*
* if(index > 0)
* {
* p = &u8frame[base_index];
* if((index&1)&&(u16PacketLength > (base_index+index*2)))
* {
* // odd index: swap 2 bytes
* tmp = p[index];
* p[index] = p[index*2];
* p[index*2] = tmp;
* }
* else
* {
* // even index: shift by 3
* tmp = (p[index] >> 3) + (p[index] << 5);
* p[index] = tmp;
* }
* }
* //else index is 0. The frame stays unaltered
*
*/
#define A2D_SBC_SYNC_WORD 0x9C
#define A2D_SBC_CRC_IDX 3
#define A2D_SBC_USE_MASK 0x64
#define A2D_SBC_SYNC_MASK 0x10
#define A2D_SBC_CIDX 0
#define A2D_SBC_LIDX 1
#define A2D_SBC_CH_M_BITS 0xC /* channel mode bits: 0: mono; 1 ch */
#define A2D_SBC_SUBBAND_BIT 0x1 /* num of subband bit: 0:4; 1: 8 */
#define A2D_SBC_GET_IDX(sc) (((sc) & 0x3) + (((sc) & 0x30) >> 2))
typedef struct
{
UINT8 use;
UINT8 idx;
} tA2D_SBC_FR_CB;
typedef struct
{
tA2D_SBC_FR_CB fr[2];
UINT8 index;
UINT8 base;
} tA2D_SBC_DS_CB;
static tA2D_SBC_DS_CB a2d_sbc_ds_cb;
/*int a2d_count = 0;*/
/******************************************************************************
**
** Function A2D_SbcChkFrInit
**
** Description check if need to init the descramble control block.
**
** Returns nothing.
******************************************************************************/
void A2D_SbcChkFrInit(UINT8 *p_pkt)
{
UINT8 fmt;
UINT8 num_chnl = 1;
UINT8 num_subband = 4;
if((p_pkt[0] & A2D_SBC_SYNC_MASK) == 0)
{
a2d_cb.use_desc = TRUE;
fmt = p_pkt[1];
p_pkt[0] |= A2D_SBC_SYNC_MASK;
memset(&a2d_sbc_ds_cb, 0, sizeof(tA2D_SBC_DS_CB));
if(fmt & A2D_SBC_CH_M_BITS)
num_chnl = 2;
if(fmt & A2D_SBC_SUBBAND_BIT)
num_subband = 8;
a2d_sbc_ds_cb.base = 6 + num_chnl*num_subband/2;
/*printf("base: %d\n", a2d_sbc_ds_cb.base);
a2d_count = 0;*/
}
}
/******************************************************************************
**
** Function A2D_SbcDescramble
**
** Description descramble the packet.
**
** Returns nothing.
******************************************************************************/
void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len)
{
tA2D_SBC_FR_CB *p_cur, *p_last;
UINT32 idx, tmp, tmp2;
if(a2d_cb.use_desc)
{
/* c2l */
p_last = &a2d_sbc_ds_cb.fr[A2D_SBC_LIDX];
p_cur = &a2d_sbc_ds_cb.fr[A2D_SBC_CIDX];
p_last->idx = p_cur->idx;
p_last->use = p_cur->use;
/* getc */
p_cur->use = p_pkt[A2D_SBC_CRC_IDX] & A2D_SBC_USE_MASK;
p_cur->idx = A2D_SBC_GET_IDX(p_pkt[A2D_SBC_CRC_IDX]);
a2d_sbc_ds_cb.index = (p_cur->use)?A2D_SBC_CIDX:A2D_SBC_LIDX;
/*
printf("%05d: ar[%02d]: x%02x, msk: x%02x, use: %s, idx: %02d, ",
a2d_count++,
A2D_SBC_CRC_IDX, p_pkt[A2D_SBC_CRC_IDX], A2D_SBC_USE_MASK,
(p_cur->use)?"cur":"lst", p_cur->idx);
*/
/* descramble */
idx = a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx;
if(idx > 0)
{
p_pkt = &p_pkt[a2d_sbc_ds_cb.base];
if((idx&1) && (len > (a2d_sbc_ds_cb.base+(idx<<1))))
{
tmp2 = (idx<<1);
tmp = p_pkt[idx];
p_pkt[idx] = p_pkt[tmp2];
p_pkt[tmp2] = tmp;
/*
printf("tmp2: %02d, len: %d, idx: %d\n",
tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx);
*/
}
else
{
tmp2 = p_pkt[idx];
tmp = (tmp2>>3)+(tmp2<<5);
p_pkt[idx] = (UINT8)tmp;
/*
printf("tmp: x%02x, len: %d, idx: %d(cmp:%d)\n",
(UINT8)tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx,
(a2d_sbc_ds_cb.base+(idx<<1)));
*/
}
}
/*
else
{
printf("!!!!\n");
}
*/
}
}
/******************************************************************************
**
** Function A2D_BldSbcInfo
**
** Description This function is called by an application to build
** the SBC Media Codec Capabilities byte sequence
** beginning from the LOSC octet.
** Input Parameters:
** media_type: Indicates Audio, or Multimedia.
**
** p_ie: The SBC Codec Information Element information.
**
** Output Parameters:
** p_result: the resulting codec info byte sequence.
**
** Returns A2D_SUCCESS if function execution succeeded.
** Error status code, otherwise.
******************************************************************************/
tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie, UINT8 *p_result)
{
tA2D_STATUS status;
if( p_ie == NULL || p_result == NULL ||
(p_ie->samp_freq & ~A2D_SBC_IE_SAMP_FREQ_MSK) ||
(p_ie->ch_mode & ~A2D_SBC_IE_CH_MD_MSK) ||
(p_ie->block_len & ~A2D_SBC_IE_BLOCKS_MSK) ||
(p_ie->num_subbands & ~A2D_SBC_IE_SUBBAND_MSK) ||
(p_ie->alloc_mthd & ~A2D_SBC_IE_ALLOC_MD_MSK) ||
(p_ie->max_bitpool < p_ie->min_bitpool) ||
(p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL) ||
(p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL) ||
(p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL) ||
(p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL) )
{
/* if any unused bit is set */
status = A2D_INVALID_PARAMS;
}
else
{
status = A2D_SUCCESS;
*p_result++ = A2D_SBC_INFO_LEN;
*p_result++ = media_type;
*p_result++ = A2D_MEDIA_CT_SBC;
/* Media Codec Specific Information Element */
*p_result++ = p_ie->samp_freq | p_ie->ch_mode;
*p_result++ = p_ie->block_len | p_ie->num_subbands | p_ie->alloc_mthd;
*p_result++ = p_ie->min_bitpool;
*p_result = p_ie->max_bitpool;
}
return status;
}
/******************************************************************************
**
** Function A2D_ParsSbcInfo
**
** Description This function is called by an application to parse
** the SBC Media Codec Capabilities byte sequence
** beginning from the LOSC octet.
** Input Parameters:
** p_info: the byte sequence to parse.
**
** for_caps: TRUE, if the byte sequence is for get capabilities response.
**
** Output Parameters:
** p_ie: The SBC Codec Information Element information.
**
** Returns A2D_SUCCESS if function execution succeeded.
** Error status code, otherwise.
******************************************************************************/
tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps)
{
tA2D_STATUS status;
UINT8 losc;
if( p_ie == NULL || p_info == NULL)
status = A2D_INVALID_PARAMS;
else
{
losc = *p_info++;
p_info++;
/* If the function is called for the wrong Media Type or Media Codec Type */
if(losc != A2D_SBC_INFO_LEN || *p_info != A2D_MEDIA_CT_SBC)
status = A2D_WRONG_CODEC;
else
{
p_info++;
p_ie->samp_freq = *p_info & A2D_SBC_IE_SAMP_FREQ_MSK;
p_ie->ch_mode = *p_info & A2D_SBC_IE_CH_MD_MSK;
p_info++;
p_ie->block_len = *p_info & A2D_SBC_IE_BLOCKS_MSK;
p_ie->num_subbands = *p_info & A2D_SBC_IE_SUBBAND_MSK;
p_ie->alloc_mthd = *p_info & A2D_SBC_IE_ALLOC_MD_MSK;
p_info++;
p_ie->min_bitpool = *p_info++;
p_ie->max_bitpool = *p_info;
status = A2D_SUCCESS;
if(p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL )
status = A2D_BAD_MIN_BITPOOL;
if(p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL ||
p_ie->max_bitpool < p_ie->min_bitpool)
status = A2D_BAD_MAX_BITPOOL;
if(for_caps == FALSE)
{
if(A2D_BitsSet(p_ie->samp_freq) != A2D_SET_ONE_BIT)
status = A2D_BAD_SAMP_FREQ;
if(A2D_BitsSet(p_ie->ch_mode) != A2D_SET_ONE_BIT)
status = A2D_BAD_CH_MODE;
if(A2D_BitsSet(p_ie->block_len) != A2D_SET_ONE_BIT)
status = A2D_BAD_BLOCK_LEN;
if(A2D_BitsSet(p_ie->num_subbands) != A2D_SET_ONE_BIT)
status = A2D_BAD_SUBBANDS;
if(A2D_BitsSet(p_ie->alloc_mthd) != A2D_SET_ONE_BIT)
status = A2D_BAD_ALLOC_MTHD;
}
}
}
return status;
}
/******************************************************************************
**
** Function A2D_BldSbcMplHdr
**
** Description This function is called by an application to parse
** the SBC Media Payload header.
** Input Parameters:
** frag: 1, if fragmented. 0, otherwise.
**
** start: 1, if the starting packet of a fragmented frame.
**
** last: 1, if the last packet of a fragmented frame.
**
** num: If frag is 1, this is the number of remaining fragments
** (including this fragment) of this frame.
** If frag is 0, this is the number of frames in this packet.
**
** Output Parameters:
** p_dst: the resulting media payload header byte sequence.
**
** Returns void.
******************************************************************************/
void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start, BOOLEAN last, UINT8 num)
{
if(p_dst)
{
*p_dst = 0;
if(frag)
*p_dst |= A2D_SBC_HDR_F_MSK;
if(start)
*p_dst |= A2D_SBC_HDR_S_MSK;
if(last)
*p_dst |= A2D_SBC_HDR_L_MSK;
*p_dst |= (A2D_SBC_HDR_NUM_MSK & num);
}
}
/******************************************************************************
**
** Function A2D_ParsSbcMplHdr
**
** Description This function is called by an application to parse
** the SBC Media Payload header.
** Input Parameters:
** p_src: the byte sequence to parse..
**
** Output Parameters:
** frag: 1, if fragmented. 0, otherwise.
**
** start: 1, if the starting packet of a fragmented frame.
**
** last: 1, if the last packet of a fragmented frame.
**
** num: If frag is 1, this is the number of remaining fragments
** (including this fragment) of this frame.
** If frag is 0, this is the number of frames in this packet.
**
** Returns void.
******************************************************************************/
void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag, BOOLEAN *p_start, BOOLEAN *p_last, UINT8 *p_num)
{
if(p_src && p_frag && p_start && p_last && p_num)
{
*p_frag = (*p_src & A2D_SBC_HDR_F_MSK) ? TRUE: FALSE;
*p_start= (*p_src & A2D_SBC_HDR_S_MSK) ? TRUE: FALSE;
*p_last = (*p_src & A2D_SBC_HDR_L_MSK) ? TRUE: FALSE;
*p_num = (*p_src & A2D_SBC_HDR_NUM_MSK);
}
}

View File

@ -0,0 +1,83 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* 2DP internal header file
*
******************************************************************************/
#ifndef A2D_INT_H
#define A2D_INT_H
#include "a2d_api.h"
/*****************************************************************************
** Constants
*****************************************************************************/
#define A2D_VERSION 0x0102
/* Number of attributes in A2D SDP record. */
#define A2D_NUM_ATTR 6
/* Number of protocol elements in protocol element list. */
#define A2D_NUM_PROTO_ELEMS 2
/*****************************************************************************
** Type definitions
*****************************************************************************/
/* Control block used by A2D_FindService(). */
typedef struct
{
tA2D_FIND_CBACK *p_cback; /* pointer to application callback */
tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */
UINT16 service_uuid; /* service UUID of search */
} tA2D_FIND_CB;
typedef struct
{
tA2D_FIND_CB find; /* find service control block */
UINT8 trace_level;
BOOLEAN use_desc;
UINT16 avdt_sdp_ver; /* AVDTP version */
} tA2D_CB;
#ifdef __cplusplus
extern "C"
{
#endif
/******************************************************************************
** Main Control Block
*******************************************************************************/
#if A2D_DYNAMIC_MEMORY == FALSE
extern tA2D_CB a2d_cb;
#else
extern tA2D_CB *a2d_cb_ptr;
#define a2d_cb (*a2d_cb_ptr)
#endif
/* Used only for conformance testing */
extern void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver);
#ifdef __cplusplus
}
#endif
#endif /* A2D_INT_H */

View File

@ -0,0 +1,473 @@
/******************************************************************************
*
* 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 module contains API of the audio/video control transport protocol.
*
******************************************************************************/
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
#include "gki.h"
#include "l2c_api.h"
#include "l2cdefs.h"
#include "btm_api.h"
#include "avct_api.h"
#include "avct_int.h"
/* Control block for AVCT */
#if AVCT_DYNAMIC_MEMORY == FALSE
tAVCT_CB avct_cb;
#endif
/*******************************************************************************
**
** Function AVCT_Register
**
** Description This is the system level registration function for the
** AVCTP protocol. This function initializes AVCTP and
** prepares the protocol stack for its use. This function
** must be called once by the system or platform using AVCTP
** before the other functions of the API an be used.
**
**
** Returns void
**
*******************************************************************************/
void AVCT_Register(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask)
{
UNUSED(mtu_br);
AVCT_TRACE_API("AVCT_Register");
/* register PSM with L2CAP */
L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_appl);
/* set security level */
BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
/* initialize AVCTP data structures */
memset(&avct_cb, 0, sizeof(tAVCT_CB));
#if (AVCT_BROWSE_INCLUDED == TRUE)
/* Include the browsing channel which uses eFCR */
L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_br_appl);
BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
if (mtu_br < AVCT_MIN_BROWSE_MTU)
mtu_br = AVCT_MIN_BROWSE_MTU;
avct_cb.mtu_br = mtu_br;
#endif
#if defined(AVCT_INITIAL_TRACE_LEVEL)
avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
#else
avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
if (mtu < AVCT_MIN_CONTROL_MTU)
mtu = AVCT_MIN_CONTROL_MTU;
/* store mtu */
avct_cb.mtu = mtu;
}
/*******************************************************************************
**
** Function AVCT_Deregister
**
** Description This function is called to deregister use AVCTP protocol.
** It is called when AVCTP is no longer being used by any
** application in the system. Before this function can be
** called, all connections must be removed with
** AVCT_RemoveConn().
**
**
** Returns void
**
*******************************************************************************/
void AVCT_Deregister(void)
{
AVCT_TRACE_API("AVCT_Deregister");
/* deregister PSM with L2CAP */
L2CA_Deregister(AVCT_PSM);
}
/*******************************************************************************
**
** Function AVCT_CreateConn
**
** Description Create an AVCTP connection. There are two types of
** connections, initiator and acceptor, as determined by
** the p_cc->role parameter. When this function is called to
** create an initiator connection, an AVCTP connection to
** the peer device is initiated if one does not already exist.
** If an acceptor connection is created, the connection waits
** passively for an incoming AVCTP connection from a peer device.
**
**
** Returns AVCT_SUCCESS if successful, otherwise error.
**
*******************************************************************************/
UINT16 AVCT_CreateConn(UINT8 *p_handle, tAVCT_CC *p_cc, BD_ADDR peer_addr)
{
UINT16 result = AVCT_SUCCESS;
tAVCT_CCB *p_ccb;
tAVCT_LCB *p_lcb;
AVCT_TRACE_API("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control);
/* Allocate ccb; if no ccbs, return failure */
if ((p_ccb = avct_ccb_alloc(p_cc)) == NULL)
{
result = AVCT_NO_RESOURCES;
}
else
{
/* get handle */
*p_handle = avct_ccb_to_idx(p_ccb);
/* if initiator connection */
if (p_cc->role == AVCT_INT)
{
/* find link; if none allocate a new one */
if ((p_lcb = avct_lcb_by_bd(peer_addr)) == NULL)
{
if ((p_lcb = avct_lcb_alloc(peer_addr)) == NULL)
{
/* no link resources; free ccb as well */
avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
result = AVCT_NO_RESOURCES;
}
}
/* check if PID already in use */
else if (avct_lcb_has_pid(p_lcb, p_cc->pid))
{
avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
result = AVCT_PID_IN_USE;
}
if (result == AVCT_SUCCESS)
{
/* bind lcb to ccb */
p_ccb->p_lcb = p_lcb;
AVCT_TRACE_DEBUG("ch_state: %d", p_lcb->ch_state);
avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
}
}
}
return result;
}
/*******************************************************************************
**
** Function AVCT_RemoveConn
**
** Description Remove an AVCTP connection. This function is called when
** the application is no longer using a connection. If this
** is the last connection to a peer the L2CAP channel for AVCTP
** will be closed.
**
**
** Returns AVCT_SUCCESS if successful, otherwise error.
**
*******************************************************************************/
UINT16 AVCT_RemoveConn(UINT8 handle)
{
UINT16 result = AVCT_SUCCESS;
tAVCT_CCB *p_ccb;
AVCT_TRACE_API("AVCT_RemoveConn");
/* map handle to ccb */
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
{
result = AVCT_BAD_HANDLE;
}
/* if connection not bound to lcb, dealloc */
else if (p_ccb->p_lcb == NULL)
{
avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
}
/* send unbind event to lcb */
else
{
avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
}
return result;
}
/*******************************************************************************
**
** Function AVCT_CreateBrowse
**
** Description Create an AVCTP Browse channel. There are two types of
** connections, initiator and acceptor, as determined by
** the role parameter. When this function is called to
** create an initiator connection, the Browse channel to
** the peer device is initiated if one does not already exist.
** If an acceptor connection is created, the connection waits
** passively for an incoming AVCTP connection from a peer device.
**
**
** Returns AVCT_SUCCESS if successful, otherwise error.
**
*******************************************************************************/
UINT16 AVCT_CreateBrowse (UINT8 handle, UINT8 role)
{
#if (AVCT_BROWSE_INCLUDED == TRUE)
UINT16 result = AVCT_SUCCESS;
tAVCT_CCB *p_ccb;
tAVCT_BCB *p_bcb;
int index;
AVCT_TRACE_API("AVCT_CreateBrowse: %d", role);
/* map handle to ccb */
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
{
return AVCT_BAD_HANDLE;
}
else
{
/* mark this CCB as supporting browsing channel */
if ((p_ccb->allocated & AVCT_ALOC_BCB) == 0)
{
p_ccb->allocated |= AVCT_ALOC_BCB;
}
}
/* if initiator connection */
if (role == AVCT_INT)
{
/* the link control block must exist before this function is called as INT. */
if ((p_ccb->p_lcb == NULL) || (p_ccb->p_lcb->allocated == 0))
{
result = AVCT_NOT_OPEN;
}
else
{
/* find link; if none allocate a new one */
index = p_ccb->p_lcb->allocated;
if (index > AVCT_NUM_LINKS)
{
result = AVCT_BAD_HANDLE;
}
else
{
p_bcb = &avct_cb.bcb[index - 1];
p_bcb->allocated = index;
}
}
if (result == AVCT_SUCCESS)
{
/* bind bcb to ccb */
p_ccb->p_bcb = p_bcb;
AVCT_TRACE_DEBUG("ch_state: %d", p_bcb->ch_state);
avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
}
}
return result;
#else
UNUSED(handle);
UNUSED(role);
return AVCT_NO_RESOURCES;
#endif
}
/*******************************************************************************
**
** Function AVCT_RemoveBrowse
**
** Description Remove an AVCTP Browse channel. This function is called when
** the application is no longer using a connection. If this
** is the last connection to a peer the L2CAP channel for AVCTP
** will be closed.
**
**
** Returns AVCT_SUCCESS if successful, otherwise error.
**
*******************************************************************************/
UINT16 AVCT_RemoveBrowse (UINT8 handle)
{
#if (AVCT_BROWSE_INCLUDED == TRUE)
UINT16 result = AVCT_SUCCESS;
tAVCT_CCB *p_ccb;
AVCT_TRACE_API("AVCT_RemoveBrowse");
/* map handle to ccb */
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
{
result = AVCT_BAD_HANDLE;
}
else if (p_ccb->p_bcb != NULL)
/* send unbind event to bcb */
{
avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
}
return result;
#else
UNUSED(handle);
return AVCT_NO_RESOURCES;
#endif
}
/*******************************************************************************
**
** Function AVCT_GetBrowseMtu
**
** Description Get the peer_mtu for the AVCTP Browse channel of the given
** connection.
**
** Returns the peer browsing channel MTU.
**
*******************************************************************************/
UINT16 AVCT_GetBrowseMtu (UINT8 handle)
{
UINT16 peer_mtu = AVCT_MIN_BROWSE_MTU;
#if (AVCT_BROWSE_INCLUDED == TRUE)
tAVCT_CCB *p_ccb;
if ((p_ccb = avct_ccb_by_idx(handle)) != NULL && p_ccb->p_bcb != NULL)
{
peer_mtu = p_ccb->p_bcb->peer_mtu;
}
#else
UNUSED(handle);
#endif
return peer_mtu;
}
/*******************************************************************************
**
** Function AVCT_GetPeerMtu
**
** Description Get the peer_mtu for the AVCTP channel of the given
** connection.
**
** Returns the peer MTU size.
**
*******************************************************************************/
UINT16 AVCT_GetPeerMtu (UINT8 handle)
{
UINT16 peer_mtu = L2CAP_DEFAULT_MTU;
tAVCT_CCB *p_ccb;
/* map handle to ccb */
if ((p_ccb = avct_ccb_by_idx(handle)) != NULL)
{
if (p_ccb->p_lcb)
{
peer_mtu = p_ccb->p_lcb->peer_mtu;
}
}
return peer_mtu;
}
/*******************************************************************************
**
** Function AVCT_MsgReq
**
** Description Send an AVCTP message to a peer device. In calling
** AVCT_MsgReq(), the application should keep track of the
** congestion state of AVCTP as communicated with events
** AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the
** application calls AVCT_MsgReq() when AVCTP is congested
** the message may be discarded. The application may make its
** first call to AVCT_MsgReq() after it receives an
** AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or
** AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel.
**
** p_msg->layer_specific must be set to
** AVCT_DATA_CTRL for control channel traffic;
** AVCT_DATA_BROWSE for for browse channel traffic.
**
** Returns AVCT_SUCCESS if successful, otherwise error.
**
*******************************************************************************/
UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg)
{
UINT16 result = AVCT_SUCCESS;
tAVCT_CCB *p_ccb;
tAVCT_UL_MSG ul_msg;
AVCT_TRACE_API("AVCT_MsgReq");
/* verify p_msg parameter */
if (p_msg == NULL)
{
return AVCT_NO_RESOURCES;
}
AVCT_TRACE_API("len: %d", p_msg->len);
/* map handle to ccb */
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL)
{
result = AVCT_BAD_HANDLE;
GKI_freebuf(p_msg);
}
/* verify channel is bound to link */
else if (p_ccb->p_lcb == NULL)
{
result = AVCT_NOT_OPEN;
GKI_freebuf(p_msg);
}
if (result == AVCT_SUCCESS)
{
ul_msg.p_buf = p_msg;
ul_msg.p_ccb = p_ccb;
ul_msg.label = label;
ul_msg.cr = cr;
#if (AVCT_BROWSE_INCLUDED == TRUE)
/* send msg event to bcb */
if (p_msg->layer_specific == AVCT_DATA_BROWSE)
{
if (p_ccb->p_bcb == NULL && (p_ccb->allocated & AVCT_ALOC_BCB) == 0)
{
/* BCB channel is not open and not allocated */
result = AVCT_BAD_HANDLE;
GKI_freebuf(p_msg);
}
else
{
p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb);
avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
}
}
/* send msg event to lcb */
else
#endif
{
avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
}
}
return result;
}

View File

@ -0,0 +1,150 @@
/******************************************************************************
*
* 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 module contains functions which operate on the AVCTP connection
* control block.
*
******************************************************************************/
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "avct_api.h"
#include "avct_int.h"
/*******************************************************************************
**
** Function avct_ccb_alloc
**
** Description Allocate a connection control block; copy parameters to ccb.
**
**
** Returns pointer to the ccb, or NULL if none could be allocated.
**
*******************************************************************************/
tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
if (!p_ccb->allocated)
{
p_ccb->allocated = AVCT_ALOC_LCB;
memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC));
AVCT_TRACE_DEBUG("avct_ccb_alloc %d", i);
break;
}
}
if (i == AVCT_NUM_CONN)
{
/* out of ccbs */
p_ccb = NULL;
AVCT_TRACE_WARNING("Out of ccbs");
}
return p_ccb;
}
/*******************************************************************************
**
** Function avct_ccb_dealloc
**
** Description Deallocate a connection control block and call application
** callback.
**
**
** Returns void.
**
*******************************************************************************/
void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr)
{
tAVCT_CTRL_CBACK *p_cback = p_ccb->cc.p_ctrl_cback;
AVCT_TRACE_DEBUG("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb));
#if (AVCT_BROWSE_INCLUDED == TRUE)
if(p_ccb->p_bcb == NULL)
memset(p_ccb, 0, sizeof(tAVCT_CCB));
else
{
/* control channel is down, but the browsing channel is still connected 0 disconnect it now */
avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
p_ccb->p_lcb = NULL;
}
#else
memset(p_ccb, 0, sizeof(tAVCT_CCB));
#endif
if (event != AVCT_NO_EVT)
{
(*p_cback)(avct_ccb_to_idx(p_ccb), event, result, bd_addr);
}
}
/*******************************************************************************
**
** Function avct_ccb_to_idx
**
** Description Given a pointer to an ccb, return its index.
**
**
** Returns Index of ccb.
**
*******************************************************************************/
UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb)
{
/* use array arithmetic to determine index */
return (UINT8) (p_ccb - avct_cb.ccb);
}
/*******************************************************************************
**
** Function avct_ccb_by_idx
**
** Description Return ccb pointer based on ccb index (or handle).
**
**
** Returns pointer to the ccb, or NULL if none found.
**
*******************************************************************************/
tAVCT_CCB *avct_ccb_by_idx(UINT8 idx)
{
tAVCT_CCB *p_ccb;
/* verify index */
if (idx < AVCT_NUM_CONN)
{
p_ccb = &avct_cb.ccb[idx];
/* verify ccb is allocated */
if (!p_ccb->allocated)
{
p_ccb = NULL;
AVCT_TRACE_WARNING("ccb %d not allocated", idx);
}
}
else
{
p_ccb = NULL;
AVCT_TRACE_WARNING("No ccb for idx %d", idx);
}
return p_ccb;
}

View File

@ -0,0 +1,436 @@
/******************************************************************************
*
* 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 AVCTP module interfaces to L2CAP
*
******************************************************************************/
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
#include "avct_api.h"
#include "avct_int.h"
#include "l2c_api.h"
#include "l2cdefs.h"
/* Configuration flags. */
#define AVCT_L2C_CFG_IND_DONE (1<<0)
#define AVCT_L2C_CFG_CFM_DONE (1<<1)
/* callback function declarations */
void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
/* L2CAP callback function structure */
const tL2CAP_APPL_INFO avct_l2c_appl = {
avct_l2c_connect_ind_cback,
avct_l2c_connect_cfm_cback,
NULL,
avct_l2c_config_ind_cback,
avct_l2c_config_cfm_cback,
avct_l2c_disconnect_ind_cback,
avct_l2c_disconnect_cfm_cback,
NULL,
avct_l2c_data_ind_cback,
avct_l2c_congestion_ind_cback,
NULL /* tL2CA_TX_COMPLETE_CB */
};
/*******************************************************************************
**
** Function avct_l2c_is_passive
**
** Description check is the CCB associated with the given LCB was created
** as passive
**
** Returns TRUE, if the given LCB is created as AVCT_PASSIVE
**
*******************************************************************************/
static BOOLEAN avct_l2c_is_passive (tAVCT_LCB *p_lcb)
{
BOOLEAN is_passive = FALSE;
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
{
AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
if (p_ccb->cc.control & AVCT_PASSIVE)
{
is_passive = TRUE;
break;
}
}
}
return is_passive;
}
/*******************************************************************************
**
** Function avct_l2c_connect_ind_cback
**
** Description This is the L2CAP connect indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
{
tAVCT_LCB *p_lcb;
UINT16 result = L2CAP_CONN_OK;
tL2CAP_CFG_INFO cfg;
UNUSED(psm);
/* do we already have a channel for this peer? */
if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL)
{
/* no, allocate lcb */
if ((p_lcb = avct_lcb_alloc(bd_addr)) == NULL)
{
/* no ccb available, reject L2CAP connection */
result = L2CAP_CONN_NO_RESOURCES;
}
}
/* else we already have a channel for this peer */
else
{
if (!avct_l2c_is_passive (p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN))
{
/* this LCB included CT role - reject */
result = L2CAP_CONN_NO_RESOURCES;
}
else
{
/* TG role only - accept the connection from CT. move the channel ID to the conflict list */
p_lcb->conflict_lcid = p_lcb->ch_lcid;
AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
}
}
if(p_lcb)
{
AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
lcid, result, p_lcb->ch_state);
}
/* Send L2CAP connect rsp */
L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
/* if result ok, proceed with connection */
if (result == L2CAP_CONN_OK)
{
/* store LCID */
p_lcb->ch_lcid = lcid;
/* transition to configuration state */
p_lcb->ch_state = AVCT_CH_CFG;
/* Send L2CAP config req */
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
cfg.mtu_present = TRUE;
cfg.mtu = avct_cb.mtu;
L2CA_ConfigReq(lcid, &cfg);
AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
}
#if (BT_USE_TRACES == TRUE)
if(p_lcb)
AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state);
#endif
}
/*******************************************************************************
**
** Function avct_l2c_connect_cfm_cback
**
** Description This is the L2CAP connect confirm callback function.
**
**
** Returns void
**
*******************************************************************************/
void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
{
tAVCT_LCB *p_lcb;
tL2CAP_CFG_INFO cfg;
/* look up lcb for this channel */
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
{
AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, conflict_lcid:0x%x",
lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
/* if in correct state */
if (p_lcb->ch_state == AVCT_CH_CONN)
{
/* if result successful */
if (result == L2CAP_CONN_OK)
{
/* set channel state */
p_lcb->ch_state = AVCT_CH_CFG;
/* Send L2CAP config req */
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
cfg.mtu_present = TRUE;
cfg.mtu = avct_cb.mtu;
L2CA_ConfigReq(lcid, &cfg);
AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
}
/* else failure */
else
{
AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
if (p_lcb->conflict_lcid == lcid)
p_lcb->conflict_lcid = 0;
else
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
}
}
else if (p_lcb->conflict_lcid == lcid)
{
/* we must be in AVCT_CH_CFG state for the ch_lcid channel */
AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", p_lcb->ch_state, p_lcb->conflict_lcid);
if (result == L2CAP_CONN_OK)
{
/* just in case the peer also accepts our connection - Send L2CAP disconnect req */
L2CA_DisconnectReq(lcid);
}
p_lcb->conflict_lcid = 0;
}
AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
}
}
/*******************************************************************************
**
** Function avct_l2c_config_cfm_cback
**
** Description This is the L2CAP config confirm callback function.
**
**
** Returns void
**
*******************************************************************************/
void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
{
tAVCT_LCB *p_lcb;
/* look up lcb for this channel */
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
{
AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
lcid, p_lcb->ch_state, p_cfg->result);
/* if in correct state */
if (p_lcb->ch_state == AVCT_CH_CFG)
{
/* if result successful */
if (p_cfg->result == L2CAP_CFG_OK)
{
/* update flags */
p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
/* if configuration complete */
if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
{
p_lcb->ch_state = AVCT_CH_OPEN;
avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
}
}
/* else failure */
else
{
AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
/* store result value */
p_lcb->ch_result = p_cfg->result;
/* Send L2CAP disconnect req */
L2CA_DisconnectReq(lcid);
}
}
AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
}
}
/*******************************************************************************
**
** Function avct_l2c_config_ind_cback
**
** Description This is the L2CAP config indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
{
tAVCT_LCB *p_lcb;
/* look up lcb for this channel */
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
{
AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
/* store the mtu in tbl */
if (p_cfg->mtu_present)
{
p_lcb->peer_mtu = p_cfg->mtu;
}
else
{
p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
}
/* send L2CAP configure response */
memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
p_cfg->result = L2CAP_CFG_OK;
L2CA_ConfigRsp(lcid, p_cfg);
/* if first config ind */
if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
{
/* update flags */
p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
/* if configuration complete */
if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
{
p_lcb->ch_state = AVCT_CH_OPEN;
avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
}
}
AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
}
}
/*******************************************************************************
**
** Function avct_l2c_disconnect_ind_cback
**
** Description This is the L2CAP disconnect indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
{
tAVCT_LCB *p_lcb;
UINT16 result = AVCT_RESULT_FAIL;
/* look up lcb for this channel */
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
{
AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
if (ack_needed)
{
/* send L2CAP disconnect response */
L2CA_DisconnectRsp(lcid);
}
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
}
}
/*******************************************************************************
**
** Function avct_l2c_disconnect_cfm_cback
**
** Description This is the L2CAP disconnect confirm callback function.
**
**
** Returns void
**
*******************************************************************************/
void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
{
tAVCT_LCB *p_lcb;
UINT16 res;
/* look up lcb for this channel */
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
{
AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
lcid, p_lcb->ch_state, result);
/* result value may be previously stored */
res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
p_lcb->ch_result = 0;
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
}
}
/*******************************************************************************
**
** Function avct_l2c_congestion_ind_cback
**
** Description This is the L2CAP congestion indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
{
tAVCT_LCB *p_lcb;
AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
/* look up lcb for this channel */
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
{
avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
}
}
/*******************************************************************************
**
** Function avct_l2c_data_ind_cback
**
** Description This is the L2CAP data indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
{
tAVCT_LCB *p_lcb;
AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
/* look up lcb for this channel */
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
{
avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
}
else /* prevent buffer leak */
{
AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
GKI_freebuf(p_buf);
}
}

View File

@ -0,0 +1,473 @@
/******************************************************************************
*
* 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 module contains the link control state machine and functions which
* operate on the link control block.
*
******************************************************************************/
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
#include "avct_api.h"
#include "avct_int.h"
#include "gki.h"
/*****************************************************************************
** state machine constants and types
*****************************************************************************/
#if BT_TRACE_VERBOSE == TRUE
/* verbose state strings for trace */
const char * const avct_lcb_st_str[] = {
"LCB_IDLE_ST",
"LCB_OPENING_ST",
"LCB_OPEN_ST",
"LCB_CLOSING_ST"
};
/* verbose event strings for trace */
const char * const avct_lcb_evt_str[] = {
"UL_BIND_EVT",
"UL_UNBIND_EVT",
"UL_MSG_EVT",
"INT_CLOSE_EVT",
"LL_OPEN_EVT",
"LL_CLOSE_EVT",
"LL_MSG_EVT",
"LL_CONG_EVT"
};
#endif
/* lcb state machine states */
enum {
AVCT_LCB_IDLE_ST,
AVCT_LCB_OPENING_ST,
AVCT_LCB_OPEN_ST,
AVCT_LCB_CLOSING_ST
};
/* state machine action enumeration list */
enum {
AVCT_LCB_CHNL_OPEN,
AVCT_LCB_CHNL_DISC,
AVCT_LCB_SEND_MSG,
AVCT_LCB_OPEN_IND,
AVCT_LCB_OPEN_FAIL,
AVCT_LCB_CLOSE_IND,
AVCT_LCB_CLOSE_CFM,
AVCT_LCB_MSG_IND,
AVCT_LCB_CONG_IND,
AVCT_LCB_BIND_CONN,
AVCT_LCB_BIND_FAIL,
AVCT_LCB_UNBIND_DISC,
AVCT_LCB_CHK_DISC,
AVCT_LCB_DISCARD_MSG,
AVCT_LCB_DEALLOC,
AVCT_LCB_FREE_MSG_IND,
AVCT_LCB_NUM_ACTIONS
};
#define AVCT_LCB_IGNORE AVCT_LCB_NUM_ACTIONS
/* type for action functions */
typedef void (*tAVCT_LCB_ACTION)(tAVCT_LCB *p_ccb, tAVCT_LCB_EVT *p_data);
/* action function list */
const tAVCT_LCB_ACTION avct_lcb_action[] = {
avct_lcb_chnl_open,
avct_lcb_chnl_disc,
avct_lcb_send_msg,
avct_lcb_open_ind,
avct_lcb_open_fail,
avct_lcb_close_ind,
avct_lcb_close_cfm,
avct_lcb_msg_ind,
avct_lcb_cong_ind,
avct_lcb_bind_conn,
avct_lcb_bind_fail,
avct_lcb_unbind_disc,
avct_lcb_chk_disc,
avct_lcb_discard_msg,
avct_lcb_dealloc,
avct_lcb_free_msg_ind
};
/* state table information */
#define AVCT_LCB_ACTIONS 2 /* number of actions */
#define AVCT_LCB_NEXT_STATE 2 /* position of next state */
#define AVCT_LCB_NUM_COLS 3 /* number of columns in state tables */
/* state table for idle state */
const UINT8 avct_lcb_st_idle[][AVCT_LCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* UL_BIND_EVT */ {AVCT_LCB_CHNL_OPEN, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
/* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
/* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
/* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
/* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}
};
/* state table for opening state */
const UINT8 avct_lcb_st_opening[][AVCT_LCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* UL_BIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
/* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
/* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
/* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
/* LL_CLOSE_EVT */ {AVCT_LCB_OPEN_FAIL, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
/* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}
};
/* state table for open state */
const UINT8 avct_lcb_st_open[][AVCT_LCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* UL_BIND_EVT */ {AVCT_LCB_BIND_CONN, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
/* UL_UNBIND_EVT */ {AVCT_LCB_CHK_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
/* UL_MSG_EVT */ {AVCT_LCB_SEND_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
/* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
/* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
/* LL_MSG_EVT */ {AVCT_LCB_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
/* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}
};
/* state table for closing state */
const UINT8 avct_lcb_st_closing[][AVCT_LCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* UL_BIND_EVT */ {AVCT_LCB_BIND_FAIL, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
/* UL_UNBIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
/* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
/* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_CFM, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
/* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}
};
/* type for state table */
typedef const UINT8 (*tAVCT_LCB_ST_TBL)[AVCT_LCB_NUM_COLS];
/* state table */
const tAVCT_LCB_ST_TBL avct_lcb_st_tbl[] = {
avct_lcb_st_idle,
avct_lcb_st_opening,
avct_lcb_st_open,
avct_lcb_st_closing
};
/*******************************************************************************
**
** Function avct_lcb_event
**
** Description State machine event handling function for lcb
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data)
{
tAVCT_LCB_ST_TBL state_table;
UINT8 action;
int i;
#if BT_TRACE_VERBOSE == TRUE
AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
#else
AVCT_TRACE_EVENT("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state);
#endif
/* look up the state table for the current state */
state_table = avct_lcb_st_tbl[p_lcb->state];
/* set next state */
p_lcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
/* execute action functions */
for (i = 0; i < AVCT_LCB_ACTIONS; i++)
{
if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
{
(*avct_lcb_action[action])(p_lcb, p_data);
}
else
{
break;
}
}
}
/*******************************************************************************
**
** Function avct_bcb_event
**
** Description State machine event handling function for lcb
**
**
** Returns Nothing.
**
*******************************************************************************/
#if (AVCT_BROWSE_INCLUDED == TRUE)
void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data)
{
tAVCT_LCB_ST_TBL state_table;
UINT8 action;
int i;
#if BT_TRACE_VERBOSE == TRUE
AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
#else
AVCT_TRACE_EVENT("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state);
#endif
/* look up the state table for the current state */
state_table = avct_lcb_st_tbl[p_bcb->state];
/* set next state */
p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
/* execute action functions */
for (i = 0; i < AVCT_LCB_ACTIONS; i++)
{
if ((action = state_table[event][i]) != AVCT_LCB_IGNORE)
{
(*avct_bcb_action[action])(p_bcb, p_data);
}
else
{
break;
}
}
}
#endif
/*******************************************************************************
**
** Function avct_lcb_by_bd
**
** Description This lookup function finds the lcb for a BD address.
**
**
** Returns pointer to the lcb, or NULL if none found.
**
*******************************************************************************/
tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr)
{
tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
int i;
for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
{
/* if allocated lcb has matching lcb */
if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN)))
{
break;
}
}
if (i == AVCT_NUM_LINKS)
{
/* if no lcb found */
p_lcb = NULL;
AVCT_TRACE_DEBUG("No lcb for 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]);
}
return p_lcb;
}
/*******************************************************************************
**
** Function avct_lcb_alloc
**
** Description Allocate a link control block.
**
**
** Returns pointer to the lcb, or NULL if none could be allocated.
**
*******************************************************************************/
tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr)
{
tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
int i;
for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
{
if (!p_lcb->allocated)
{
p_lcb->allocated = (UINT8)(i + 1);
memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated);
break;
}
}
if (i == AVCT_NUM_LINKS)
{
/* out of lcbs */
p_lcb = NULL;
AVCT_TRACE_WARNING("Out of lcbs");
}
return p_lcb;
}
/*******************************************************************************
**
** Function avct_lcb_dealloc
**
** Description Deallocate a link control block.
**
**
** Returns void.
**
*******************************************************************************/
void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
BOOLEAN found = FALSE;
int i;
UNUSED(p_data);
AVCT_TRACE_DEBUG("avct_lcb_dealloc %d", p_lcb->allocated);
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
/* if ccb allocated and */
if (p_ccb->allocated)
{
if (p_ccb->p_lcb == p_lcb)
{
AVCT_TRACE_DEBUG("avct_lcb_dealloc used by ccb: %d", i);
found = TRUE;
break;
}
}
}
if (!found)
{
AVCT_TRACE_DEBUG("avct_lcb_dealloc now");
/* clear reassembled msg buffer if in use */
if (p_lcb->p_rx_msg != NULL)
{
GKI_freebuf(p_lcb->p_rx_msg);
}
memset(p_lcb, 0, sizeof(tAVCT_LCB));
}
}
/*******************************************************************************
**
** Function avct_lcb_by_lcid
**
** Description Find the LCB associated with the L2CAP LCID
**
**
** Returns pointer to the lcb, or NULL if none found.
**
*******************************************************************************/
tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid)
{
tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
int i;
for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++)
{
if (p_lcb->allocated && ((p_lcb->ch_lcid == lcid) || (p_lcb->conflict_lcid == lcid)))
{
break;
}
}
if (i == AVCT_NUM_LINKS)
{
/* out of lcbs */
p_lcb = NULL;
AVCT_TRACE_WARNING("No lcb for lcid %x", lcid);
}
return p_lcb;
}
/*******************************************************************************
**
** Function avct_lcb_has_pid
**
** Description See if any ccbs on this lcb have a particular pid.
**
**
** Returns Pointer to CCB if PID found, NULL otherwise.
**
*******************************************************************************/
tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid))
{
return p_ccb;
}
}
return NULL;
}
/*******************************************************************************
**
** Function avct_lcb_last_ccb
**
** Description See if given ccb is only one on the lcb.
**
**
** Returns TRUE if ccb is last, FALSE otherwise.
**
*******************************************************************************/
BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
AVCT_TRACE_WARNING("avct_lcb_last_ccb");
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
AVCT_TRACE_WARNING("%x: aloc:%d, lcb:0x%x/0x%x, ccb:0x%x/0x%x",
i, p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb, p_ccb_last);
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last))
{
return FALSE;
}
}
return TRUE;
}

View File

@ -0,0 +1,734 @@
/******************************************************************************
*
* 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 module contains action functions of the link control state machine.
*
******************************************************************************/
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
#include "avct_api.h"
#include "avct_int.h"
#include "gki.h"
#include "btm_api.h"
/* packet header length lookup table */
const UINT8 avct_lcb_pkt_type_len[] = {
AVCT_HDR_LEN_SINGLE,
AVCT_HDR_LEN_START,
AVCT_HDR_LEN_CONT,
AVCT_HDR_LEN_END
};
/*******************************************************************************
**
** Function avct_lcb_msg_asmbl
**
** Description Reassemble incoming message.
**
**
** Returns Pointer to reassembled message; NULL if no message
** available.
**
*******************************************************************************/
static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf)
{
UINT8 *p;
UINT8 pkt_type;
BT_HDR *p_ret;
UINT16 buf_len;
/* parse the message header */
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
AVCT_PRS_PKT_TYPE(p, pkt_type);
/* quick sanity check on length */
if (p_buf->len < avct_lcb_pkt_type_len[pkt_type])
{
GKI_freebuf(p_buf);
AVCT_TRACE_WARNING("Bad length during reassembly");
p_ret = NULL;
}
/* single packet */
else if (pkt_type == AVCT_PKT_TYPE_SINGLE)
{
/* if reassembly in progress drop message and process new single */
if (p_lcb->p_rx_msg != NULL)
{
GKI_freebuf(p_lcb->p_rx_msg);
p_lcb->p_rx_msg = NULL;
AVCT_TRACE_WARNING("Got single during reassembly");
}
p_ret = p_buf;
}
/* start packet */
else if (pkt_type == AVCT_PKT_TYPE_START)
{
/* if reassembly in progress drop message and process new start */
if (p_lcb->p_rx_msg != NULL)
{
GKI_freebuf(p_lcb->p_rx_msg);
AVCT_TRACE_WARNING("Got start during reassembly");
}
/* Allocate bigger buffer for reassembly. As lower layers are
* not aware of possible packet size after reassembly they
* would have allocated smaller buffer.
*/
p_lcb->p_rx_msg = (BT_HDR*)GKI_getbuf(GKI_MAX_BUF_SIZE);
if (p_lcb->p_rx_msg == NULL)
{
AVCT_TRACE_ERROR ("Cannot alloc buffer for reassembly !!");
GKI_freebuf(p_buf);
}
else
{
memcpy (p_lcb->p_rx_msg, p_buf,
sizeof(BT_HDR) + p_buf->offset + p_buf->len);
/* Free original buffer */
GKI_freebuf(p_buf);
/* update p to point to new buffer */
p = (UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset;
/* copy first header byte over nosp */
*(p + 1) = *p;
/* set offset to point to where to copy next */
p_lcb->p_rx_msg->offset += p_lcb->p_rx_msg->len;
/* adjust length for packet header */
p_lcb->p_rx_msg->len -= 1;
}
p_ret = NULL;
}
/* continue or end */
else
{
/* if no reassembly in progress drop message */
if (p_lcb->p_rx_msg == NULL)
{
GKI_freebuf(p_buf);
AVCT_TRACE_WARNING("Pkt type=%d out of order", pkt_type);
p_ret = NULL;
}
else
{
/* get size of buffer holding assembled message */
buf_len = GKI_get_buf_size(p_lcb->p_rx_msg) - sizeof(BT_HDR);
/* adjust offset and len of fragment for header byte */
p_buf->offset += AVCT_HDR_LEN_CONT;
p_buf->len -= AVCT_HDR_LEN_CONT;
/* verify length */
if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len)
{
/* won't fit; free everything */
GKI_freebuf(p_lcb->p_rx_msg);
p_lcb->p_rx_msg = NULL;
GKI_freebuf(p_buf);
p_ret = NULL;
AVCT_TRACE_WARNING("Fragmented message to big!");
}
else
{
/* copy contents of p_buf to p_rx_msg */
memcpy((UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset,
(UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
if (pkt_type == AVCT_PKT_TYPE_END)
{
p_lcb->p_rx_msg->offset -= p_lcb->p_rx_msg->len;
p_lcb->p_rx_msg->len += p_buf->len;
p_ret = p_lcb->p_rx_msg;
p_lcb->p_rx_msg = NULL;
}
else
{
p_lcb->p_rx_msg->offset += p_buf->len;
p_lcb->p_rx_msg->len += p_buf->len;
p_ret = NULL;
}
GKI_freebuf(p_buf);
}
}
}
return p_ret;
}
/*******************************************************************************
**
** Function avct_lcb_chnl_open
**
** Description Open L2CAP channel to peer
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UINT16 result = AVCT_RESULT_FAIL;
UNUSED(p_data);
BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP, 0);
/* call l2cap connect req */
p_lcb->ch_state = AVCT_CH_CONN;
if ((p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr)) == 0)
{
/* if connect req failed, send ourselves close event */
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
}
}
/*******************************************************************************
**
** Function avct_lcb_unbind_disc
**
** Description Deallocate ccb and call callback with disconnect event.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UNUSED(p_lcb);
avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
}
/*******************************************************************************
**
** Function avct_lcb_open_ind
**
** Description Handle an LL_OPEN event. For each allocated ccb already
** bound to this lcb, send a connect event. For each
** unbound ccb with a new PID, bind that ccb to this lcb and
** send a connect event.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
BOOLEAN bind = FALSE;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
/* if ccb allocated and */
if (p_ccb->allocated)
{
/* if bound to this lcb send connect confirm event */
if (p_ccb->p_lcb == p_lcb)
{
bind = TRUE;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
0, p_lcb->peer_addr);
}
/* if unbound acceptor and lcb doesn't already have a ccb for this PID */
else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
(avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL))
{
/* bind ccb to lcb and send connect ind event */
bind = TRUE;
p_ccb->p_lcb = p_lcb;
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT,
0, p_lcb->peer_addr);
}
}
}
/* if no ccbs bound to this lcb, disconnect */
if (bind == FALSE)
{
avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
}
}
/*******************************************************************************
**
** Function avct_lcb_open_fail
**
** Description L2CAP channel open attempt failed. Deallocate any ccbs
** on this lcb and send connect confirm event with failure.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
{
avct_ccb_dealloc(p_ccb, AVCT_CONNECT_CFM_EVT,
p_data->result, p_lcb->peer_addr);
}
}
}
/*******************************************************************************
**
** Function avct_lcb_close_ind
**
** Description L2CAP channel closed by peer. Deallocate any initiator
** ccbs on this lcb and send disconnect ind event.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
UNUSED(p_data);
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
{
if (p_ccb->cc.role == AVCT_INT)
{
avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT,
0, p_lcb->peer_addr);
}
else
{
p_ccb->p_lcb = NULL;
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_DISCONNECT_IND_EVT,
0, p_lcb->peer_addr);
}
}
}
}
/*******************************************************************************
**
** Function avct_lcb_close_cfm
**
** Description L2CAP channel closed by us. Deallocate any initiator
** ccbs on this lcb and send disconnect ind or cfm event.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
UINT8 event;
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
{
/* if this ccb initiated close send disconnect cfm otherwise ind */
if (p_ccb->ch_close)
{
p_ccb->ch_close = FALSE;
event = AVCT_DISCONNECT_CFM_EVT;
}
else
{
event = AVCT_DISCONNECT_IND_EVT;
}
if (p_ccb->cc.role == AVCT_INT)
{
avct_ccb_dealloc(p_ccb, event, p_data->result, p_lcb->peer_addr);
}
else
{
p_ccb->p_lcb = NULL;
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event,
p_data->result, p_lcb->peer_addr);
}
}
}
}
/*******************************************************************************
**
** Function avct_lcb_bind_conn
**
** Description Bind ccb to lcb and send connect cfm event.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
p_data->p_ccb->p_lcb = p_lcb;
(*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr);
}
/*******************************************************************************
**
** Function avct_lcb_chk_disc
**
** Description A ccb wants to close; if it is the last ccb on this lcb,
** close channel. Otherwise just deallocate and call
** callback.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
AVCT_TRACE_WARNING("avct_lcb_chk_disc");
#if (AVCT_BROWSE_INCLUDED == TRUE)
avct_close_bcb(p_lcb, p_data);
#endif
if (avct_lcb_last_ccb(p_lcb, p_data->p_ccb))
{
AVCT_TRACE_WARNING("closing");
p_data->p_ccb->ch_close = TRUE;
avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
}
else
{
AVCT_TRACE_WARNING("dealloc ccb");
avct_lcb_unbind_disc(p_lcb, p_data);
}
}
/*******************************************************************************
**
** Function avct_lcb_chnl_disc
**
** Description Disconnect L2CAP channel.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UNUSED(p_data);
L2CA_DisconnectReq(p_lcb->ch_lcid);
}
/*******************************************************************************
**
** Function avct_lcb_bind_fail
**
** Description Deallocate ccb and call callback with connect event
** with failure result.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UNUSED(p_lcb);
avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
}
/*******************************************************************************
**
** Function avct_lcb_cong_ind
**
** Description Handle congestion indication from L2CAP.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
int i;
UINT8 event;
BT_HDR *p_buf;
/* set event */
event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
p_lcb->cong = p_data->cong;
if (p_lcb->cong == FALSE && GKI_getfirst(&p_lcb->tx_q))
{
while ( !p_lcb->cong && (p_buf = (BT_HDR *)GKI_dequeue(&p_lcb->tx_q)) != NULL)
{
if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
{
p_lcb->cong = TRUE;
}
}
}
/* send event to all ccbs on this lcb */
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
{
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
{
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr);
}
}
}
/*******************************************************************************
**
** Function avct_lcb_discard_msg
**
** Description Discard a message sent in from the API.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UNUSED(p_lcb);
AVCT_TRACE_WARNING("Dropping msg");
GKI_freebuf(p_data->ul_msg.p_buf);
}
/*******************************************************************************
**
** Function avct_lcb_send_msg
**
** Description Build and send an AVCTP message.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UINT16 curr_msg_len;
UINT8 pkt_type;
UINT8 hdr_len;
BT_HDR *p_buf;
UINT8 *p;
UINT8 nosp = 0; /* number of subsequent packets */
UINT16 temp;
UINT16 buf_size = p_lcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
/* store msg len */
curr_msg_len = p_data->ul_msg.p_buf->len;
/* initialize packet type and other stuff */
if (curr_msg_len <= (p_lcb->peer_mtu - AVCT_HDR_LEN_SINGLE))
{
pkt_type = AVCT_PKT_TYPE_SINGLE;
}
else
{
pkt_type = AVCT_PKT_TYPE_START;
temp = (curr_msg_len + AVCT_HDR_LEN_START - p_lcb->peer_mtu);
nosp = temp / (p_lcb->peer_mtu - 1) + 1;
if ( (temp % (p_lcb->peer_mtu - 1)) != 0)
nosp++;
}
/* while we haven't sent all packets */
while (curr_msg_len != 0)
{
/* set header len */
hdr_len = avct_lcb_pkt_type_len[pkt_type];
/* if remaining msg must be fragmented */
if (p_data->ul_msg.p_buf->len > (p_lcb->peer_mtu - hdr_len))
{
/* get a new buffer for fragment we are sending */
if ((p_buf = (BT_HDR *) GKI_getbuf(buf_size)) == NULL)
{
/* whoops; free original msg buf and bail */
AVCT_TRACE_ERROR ("avct_lcb_send_msg cannot alloc buffer!!");
GKI_freebuf(p_data->ul_msg.p_buf);
break;
}
/* copy portion of data from current message to new buffer */
p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
p_buf->len = p_lcb->peer_mtu - hdr_len;
memcpy((UINT8 *)(p_buf + 1) + p_buf->offset,
(UINT8 *)(p_data->ul_msg.p_buf + 1) + p_data->ul_msg.p_buf->offset, p_buf->len);
p_data->ul_msg.p_buf->offset += p_buf->len;
p_data->ul_msg.p_buf->len -= p_buf->len;
}
else
{
p_buf = p_data->ul_msg.p_buf;
}
curr_msg_len -= p_buf->len;
/* set up to build header */
p_buf->len += hdr_len;
p_buf->offset -= hdr_len;
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
/* build header */
AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
if (pkt_type == AVCT_PKT_TYPE_START)
{
UINT8_TO_STREAM(p, nosp);
}
if ((pkt_type == AVCT_PKT_TYPE_START) || (pkt_type == AVCT_PKT_TYPE_SINGLE))
{
UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
}
if (p_lcb->cong == TRUE)
{
GKI_enqueue (&p_lcb->tx_q, p_buf);
}
/* send message to L2CAP */
else
{
if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
{
p_lcb->cong = TRUE;
}
}
/* update pkt type for next packet */
if (curr_msg_len > (p_lcb->peer_mtu - AVCT_HDR_LEN_END))
{
pkt_type = AVCT_PKT_TYPE_CONT;
}
else
{
pkt_type = AVCT_PKT_TYPE_END;
}
}
AVCT_TRACE_DEBUG ("avct_lcb_send_msg tx_q_count:%d", GKI_queue_length(&p_lcb->tx_q));
return;
}
/*******************************************************************************
**
** Function avct_lcb_free_msg_ind
**
** Description Discard an incoming AVCTP message.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UNUSED(p_lcb);
if (p_data)
GKI_freebuf(p_data->p_buf);
return;
}
/*******************************************************************************
**
** Function avct_lcb_msg_ind
**
** Description Handle an incoming AVCTP message.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
{
UINT8 *p;
UINT8 label, type, cr_ipid;
UINT16 pid;
tAVCT_CCB *p_ccb;
BT_HDR *p_buf;
/* this p_buf is to be reported through p_msg_cback. The layer_specific
* needs to be set properly to indicate that it is received through
* control channel */
p_data->p_buf->layer_specific = AVCT_DATA_CTRL;
/* reassemble message; if no message available (we received a fragment) return */
if ((p_data->p_buf = avct_lcb_msg_asmbl(p_lcb, p_data->p_buf)) == NULL)
{
return;
}
p = (UINT8 *)(p_data->p_buf + 1) + p_data->p_buf->offset;
/* parse header byte */
AVCT_PRS_HDR(p, label, type, cr_ipid);
UNUSED(type);
/* check for invalid cr_ipid */
if (cr_ipid == AVCT_CR_IPID_INVALID)
{
AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid);
GKI_freebuf(p_data->p_buf);
return;
}
/* parse and lookup PID */
BE_STREAM_TO_UINT16(pid, p);
if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL)
{
/* PID found; send msg up, adjust bt hdr and call msg callback */
p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
(*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
}
else
{
/* PID not found; drop message */
AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
GKI_freebuf(p_data->p_buf);
/* if command send reject */
if (cr_ipid == AVCT_CMD)
{
if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVCT_CMD_POOL_ID)) != NULL)
{
p_buf->len = AVCT_HDR_LEN_SINGLE;
p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
UINT16_TO_BE_STREAM(p, pid);
L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
}
}
}
}

View File

@ -0,0 +1,62 @@
/******************************************************************************
*
* 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 contains constants definitions and other information from the AVCTP
* specification. This file is intended for use internal to AVCT only.
*
******************************************************************************/
#ifndef AVCT_DEFS_H
#define AVCT_DEFS_H
/*****************************************************************************
** constants
*****************************************************************************/
/* packet type */
#define AVCT_PKT_TYPE_SINGLE 0 /* single packet */
#define AVCT_PKT_TYPE_START 1 /* start packet */
#define AVCT_PKT_TYPE_CONT 2 /* continue packet */
#define AVCT_PKT_TYPE_END 3 /* end packet */
/* header lengths for different packet types */
#define AVCT_HDR_LEN_SINGLE 3
#define AVCT_HDR_LEN_START 4
#define AVCT_HDR_LEN_CONT 1
#define AVCT_HDR_LEN_END 1
/* invalid cr+ipid value */
#define AVCT_CR_IPID_INVALID 1
/*****************************************************************************
** message parsing and building macros
*****************************************************************************/
#define AVCT_BLD_HDR(p, label, type, cr_ipid) \
*(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid);
#define AVCT_PRS_HDR(p, label, type, cr_ipid) \
label = *(p) >> 4; \
type = (*(p) >> 2) & 3; \
cr_ipid = *(p)++ & 3;
#define AVCT_PRS_PKT_TYPE(p, type) \
type = (*(p) >> 2) & 3;
#endif /* AVCT_DEFS_H */

View File

@ -0,0 +1,237 @@
/******************************************************************************
*
* 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 interfaces which are internal to AVCTP.
*
******************************************************************************/
#ifndef AVCT_INT_H
#define AVCT_INT_H
#include "gki.h"
#include "avct_api.h"
#include "avct_defs.h"
#include "l2c_api.h"
/*****************************************************************************
** constants
*****************************************************************************/
/* lcb state machine events */
enum {
AVCT_LCB_UL_BIND_EVT,
AVCT_LCB_UL_UNBIND_EVT,
AVCT_LCB_UL_MSG_EVT,
AVCT_LCB_INT_CLOSE_EVT,
AVCT_LCB_LL_OPEN_EVT,
AVCT_LCB_LL_CLOSE_EVT,
AVCT_LCB_LL_MSG_EVT,
AVCT_LCB_LL_CONG_EVT
};
/* "states" used for L2CAP channel */
#define AVCT_CH_IDLE 0 /* No connection */
#define AVCT_CH_CONN 1 /* Waiting for connection confirm */
#define AVCT_CH_CFG 2 /* Waiting for configuration complete */
#define AVCT_CH_OPEN 3 /* Channel opened */
/* "no event" indicator used by ccb dealloc */
#define AVCT_NO_EVT 0xFF
/*****************************************************************************
** data types
*****************************************************************************/
/* sub control block type - common data members for tAVCT_LCB and tAVCT_BCB */
typedef struct {
UINT16 peer_mtu; /* peer l2c mtu */
UINT16 ch_result; /* L2CAP connection result value */
UINT16 ch_lcid; /* L2CAP channel LCID */
UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
UINT8 state; /* The state machine state */
UINT8 ch_state; /* L2CAP channel state */
UINT8 ch_flags; /* L2CAP configuration flags */
} tAVCT_SCB;
/* link control block type */
typedef struct {
UINT16 peer_mtu; /* peer l2c mtu */
UINT16 ch_result; /* L2CAP connection result value */
UINT16 ch_lcid; /* L2CAP channel LCID */
UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
UINT8 state; /* The state machine state */
UINT8 ch_state; /* L2CAP channel state */
UINT8 ch_flags; /* L2CAP configuration flags */
BT_HDR *p_rx_msg; /* Message being reassembled */
UINT16 conflict_lcid; /* L2CAP channel LCID */
BD_ADDR peer_addr; /* BD address of peer */
BUFFER_Q tx_q; /* Transmit data buffer queue */
BOOLEAN cong; /* TRUE, if congested */
} tAVCT_LCB;
/* browse control block type */
typedef struct {
UINT16 peer_mtu; /* peer l2c mtu */
UINT16 ch_result; /* L2CAP connection result value */
UINT16 ch_lcid; /* L2CAP channel LCID */
UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
UINT8 state; /* The state machine state */
UINT8 ch_state; /* L2CAP channel state */
UINT8 ch_flags; /* L2CAP configuration flags */
BT_HDR *p_tx_msg; /* Message to be sent - in case the browsing channel is not open when MsgReg is called */
UINT8 ch_close; /* CCB index+1, if CCB initiated channel close */
} tAVCT_BCB;
#define AVCT_ALOC_LCB 0x01
#define AVCT_ALOC_BCB 0x02
/* connection control block */
typedef struct {
tAVCT_CC cc; /* parameters from connection creation */
tAVCT_LCB *p_lcb; /* Associated LCB */
tAVCT_BCB *p_bcb; /* associated BCB */
BOOLEAN ch_close; /* Whether CCB initiated channel close */
UINT8 allocated; /* Whether LCB/BCB is allocated */
} tAVCT_CCB;
/* data type associated with UL_MSG_EVT */
typedef struct {
BT_HDR *p_buf;
tAVCT_CCB *p_ccb;
UINT8 label;
UINT8 cr;
} tAVCT_UL_MSG;
/* union associated with lcb state machine events */
typedef union {
tAVCT_UL_MSG ul_msg;
BT_HDR *p_buf;
tAVCT_CCB *p_ccb;
UINT16 result;
BOOLEAN cong;
UINT8 err_code;
} tAVCT_LCB_EVT;
/* Control block for AVCT */
typedef struct {
tAVCT_LCB lcb[AVCT_NUM_LINKS]; /* link control blocks */
tAVCT_BCB bcb[AVCT_NUM_LINKS]; /* browse control blocks */
tAVCT_CCB ccb[AVCT_NUM_CONN]; /* connection control blocks */
UINT16 mtu; /* our L2CAP MTU */
UINT16 mtu_br; /* our L2CAP MTU for the Browsing channel */
UINT8 trace_level; /* trace level */
} tAVCT_CB;
/*****************************************************************************
** function declarations
*****************************************************************************/
/* LCB function declarations */
extern void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data);
#if (AVCT_BROWSE_INCLUDED == TRUE)
extern void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data);
extern void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb);
extern tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb);
extern BOOLEAN avct_bcb_last_ccb(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last);
extern tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid);
#endif
extern tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr);
extern tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr);
extern void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid);
extern tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid);
extern BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last);
/* LCB action functions */
extern void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
extern void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
/* BCB action functions */
#if (AVCT_BROWSE_INCLUDED == TRUE)
typedef void (*tAVCT_BCB_ACTION)(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
extern const tAVCT_BCB_ACTION avct_bcb_action[];
extern const UINT8 avct_lcb_pkt_type_len[];
extern const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def;
#endif
/* CCB function declarations */
extern tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc);
extern void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr);
extern UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb);
extern tAVCT_CCB *avct_ccb_by_idx(UINT8 idx);
/*****************************************************************************
** global data
*****************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
/* Main control block */
#if AVCT_DYNAMIC_MEMORY == FALSE
extern tAVCT_CB avct_cb;
#else
extern tAVCT_CB *avct_cb_ptr;
#define avct_cb (*avct_cb_ptr)
#endif
/* L2CAP callback registration structure */
extern const tL2CAP_APPL_INFO avct_l2c_appl;
#if (AVCT_BROWSE_INCLUDED == TRUE)
extern const tL2CAP_APPL_INFO avct_l2c_br_appl;
#endif
#ifdef __cplusplus
}
#endif
#endif /* AVCT_INT_H */

View File

@ -0,0 +1,641 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* This module contains the AVDTP adaption layer.
*
******************************************************************************/
// #include <assert.h>
#include "bt_trace.h"
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
#include "avdt_api.h"
#include "avdtc_api.h"
#include "avdt_int.h"
#include "l2c_api.h"
#include "l2cdefs.h"
/*******************************************************************************
**
** Function avdt_ad_type_to_tcid
**
** Description Derives the TCID from the channel type and SCB.
**
**
** Returns TCID value.
**
*******************************************************************************/
UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb)
{
UINT8 scb_idx;
if (type == AVDT_CHAN_SIG)
{
return 0;
}
else
{
scb_idx = avdt_scb_to_hdl(p_scb) - 1;
/*
AVDT_TRACE_DEBUG("type: %d, tcid: %d", type, ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type));
*/
return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type);
}
}
/*******************************************************************************
**
** Function avdt_ad_tcid_to_type
**
** Description Derives the channel type from the TCID.
**
**
** Returns Channel type value.
**
*******************************************************************************/
static UINT8 avdt_ad_tcid_to_type(UINT8 tcid)
{
UINT8 type;
if (tcid == 0)
{
type = AVDT_CHAN_SIG;
}
else
{
/* tcid translates to type based on number of channels, as follows:
** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1...
** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2...
** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3...
*/
type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
}
AVDT_TRACE_DEBUG("tcid: %d, type: %d", tcid, type);
return type;
}
/*******************************************************************************
**
** Function avdt_ad_init
**
** Description Initialize adaption layer.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ad_init(void)
{
int i;
tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD));
/* make sure the peer_mtu is a valid value */
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
{
p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
}
}
/*******************************************************************************
**
** Function avdt_ad_tc_tbl_by_st
**
** Description Find adaption layer transport channel table entry matching
** the given state.
**
**
** Returns Pointer to matching entry. For control channel it returns
** the matching entry. For media or other it returns the
** first matching entry (there could be more than one).
**
*******************************************************************************/
tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state)
{
int i;
tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
UINT8 ccb_idx;
if (p_ccb == NULL)
{
/* resending security req */
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
{
/* must be AVDT_CHAN_SIG - tcid always zero */
if ((p_tbl->tcid == 0) &&
(p_tbl->state == state))
{
break;
}
}
}
else
{
ccb_idx = avdt_ccb_to_idx(p_ccb);
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
{
if (type == AVDT_CHAN_SIG)
{
/* if control channel, tcid always zero */
if ((p_tbl->tcid == 0) &&
(p_tbl->ccb_idx == ccb_idx) &&
(p_tbl->state == state))
{
break;
}
}
else
{
/* if other channel, tcid is always > zero */
if ((p_tbl->tcid > 0) &&
(p_tbl->ccb_idx == ccb_idx) &&
(p_tbl->state == state))
{
break;
}
}
}
}
/* if nothing found return null */
if (i == AVDT_NUM_TC_TBL)
{
p_tbl = NULL;
}
return p_tbl;
}
/*******************************************************************************
**
** Function avdt_ad_tc_tbl_by_lcid
**
** Description Find adaption layer transport channel table entry by LCID.
**
**
** Returns Pointer to entry.
**
*******************************************************************************/
tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid)
{
UINT8 idx;
idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
if (idx < AVDT_NUM_TC_TBL)
{
return &avdt_cb.ad.tc_tbl[idx];
}
else
{
return NULL;
}
}
/*******************************************************************************
**
** Function avdt_ad_tc_tbl_by_type
**
** Description This function retrieves the transport channel table entry
** for a particular channel.
**
**
** Returns Pointer to transport channel table entry.
**
*******************************************************************************/
tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
{
UINT8 tcid;
int i;
tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
UINT8 ccb_idx = avdt_ccb_to_idx(p_ccb);
/* get tcid from type, scb */
tcid = avdt_ad_type_to_tcid(type, p_scb);
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
{
if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx))
{
break;
}
}
assert(i != AVDT_NUM_TC_TBL);
return p_tbl;
}
/*******************************************************************************
**
** Function avdt_ad_tc_tbl_alloc
**
** Description Allocate an entry in the traffic channel table.
**
**
** Returns Pointer to entry.
**
*******************************************************************************/
tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb)
{
int i;
tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
/* find next free entry in tc table */
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
{
if (p_tbl->state == AVDT_AD_ST_UNUSED)
{
break;
}
}
/* sanity check */
assert(i != AVDT_NUM_TC_TBL);
/* initialize entry */
p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
p_tbl->cfg_flags = 0;
p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb);
p_tbl->state = AVDT_AD_ST_IDLE;
return p_tbl;
}
/*******************************************************************************
**
** Function avdt_ad_tc_tbl_to_idx
**
** Description Convert a transport channel table entry to an index.
**
**
** Returns Index value.
**
*******************************************************************************/
UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl)
{
AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdt_cb.ad.tc_tbl));
/* use array arithmetic to determine index */
return (UINT8) (p_tbl - avdt_cb.ad.tc_tbl);
}
/*******************************************************************************
**
** Function avdt_ad_tc_close_ind
**
** Description This function is called by the L2CAP interface when the
** L2CAP channel is closed. It looks up the CCB or SCB for
** the channel and sends it a close event. The reason
** parameter is the same value passed by the L2CAP
** callback function.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason)
{
tAVDT_CCB *p_ccb;
tAVDT_SCB *p_scb;
tAVDT_SCB_TC_CLOSE close;
UNUSED(reason);
close.old_tc_state = p_tbl->state;
/* clear avdt_ad_tc_tbl entry */
p_tbl->state = AVDT_AD_ST_UNUSED;
p_tbl->cfg_flags = 0;
p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
AVDT_TRACE_DEBUG("avdt_ad_tc_close_ind tcid: %d, old: %d",
p_tbl->tcid, close.old_tc_state);
/* if signaling channel, notify ccb that channel open */
if (p_tbl->tcid == 0)
{
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
}
/* if media or other channel, notify scb that channel close */
else
{
/* look up scb in stream routing table by ccb, tcid */
p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
if (p_scb != NULL)
{
close.tcid = p_tbl->tcid;
close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, (tAVDT_SCB_EVT *)&close);
}
}
}
/*******************************************************************************
**
** Function avdt_ad_tc_open_ind
**
** Description This function is called by the L2CAP interface when
** the L2CAP channel is opened. It looks up the CCB or SCB
** for the channel and sends it an open event.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl)
{
tAVDT_CCB *p_ccb;
tAVDT_SCB *p_scb;
tAVDT_OPEN open;
tAVDT_EVT_HDR evt;
p_tbl->state = AVDT_AD_ST_OPEN;
/* if signaling channel, notify ccb that channel open */
if (p_tbl->tcid == 0)
{
/* set the signal channel to use high priority within the ACL link */
L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid, L2CAP_CHNL_PRIORITY_HIGH);
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
/* use err_param to indicate the role of connection.
* AVDT_ACP, if ACP */
evt.err_param = AVDT_INT;
if(p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP)
{
evt.err_param = AVDT_ACP;
}
avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, (tAVDT_CCB_EVT *)&evt);
}
/* if media or other channel, notify scb that channel open */
else
{
/* look up scb in stream routing table by ccb, tcid */
p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
/* put lcid in event data */
if (p_scb != NULL)
{
open.peer_mtu = p_tbl->peer_mtu;
open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, (tAVDT_SCB_EVT *) &open);
}
}
}
/*******************************************************************************
**
** Function avdt_ad_tc_cong_ind
**
** Description This function is called by the L2CAP interface layer when
** L2CAP calls the congestion callback. It looks up the CCB
** or SCB for the channel and sends it a congestion event.
** The is_congested parameter is the same value passed by
** the L2CAP callback function.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested)
{
tAVDT_CCB *p_ccb;
tAVDT_SCB *p_scb;
/* if signaling channel, notify ccb of congestion */
if (p_tbl->tcid == 0)
{
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, (tAVDT_CCB_EVT *) &is_congested);
}
/* if media or other channel, notify scb that channel open */
else
{
/* look up scb in stream routing table by ccb, tcid */
p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
if (p_scb != NULL)
{
avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, (tAVDT_SCB_EVT *) &is_congested);
}
}
}
/*******************************************************************************
**
** Function avdt_ad_tc_data_ind
**
** Description This function is called by the L2CAP interface layer when
** incoming data is received from L2CAP. It looks up the CCB
** or SCB for the channel and routes the data accordingly.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf)
{
tAVDT_CCB *p_ccb;
tAVDT_SCB *p_scb;
/* store type (media, recovery, reporting) */
p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
/* if signaling channel, handle control message */
if (p_tbl->tcid == 0)
{
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
avdt_msg_ind(p_ccb, p_buf);
}
/* if media or other channel, send event to scb */
else
{
p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
if (p_scb != NULL)
{
avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT *) &p_buf);
}
else
{
GKI_freebuf(p_buf);
AVDT_TRACE_ERROR(" avdt_ad_tc_data_ind buffer freed");
}
}
}
/*******************************************************************************
**
** Function avdt_ad_write_req
**
** Description This function is called by a CCB or SCB to send data to a
** transport channel. It looks up the LCID of the channel
** based on the type, CCB, and SCB (if present). Then it
** passes the data to L2CA_DataWrite().
**
**
** Returns AVDT_AD_SUCCESS, if data accepted, else FALSE
** AVDT_AD_CONGESTED, if data accepted and the channel is congested
** AVDT_AD_FAILED, if error
**
*******************************************************************************/
UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
{
UINT8 tcid;
/* get tcid from type, scb */
tcid = avdt_ad_type_to_tcid(type, p_scb);
return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
}
/*******************************************************************************
**
** Function avdt_ad_open_req
**
** Description This function is called by a CCB or SCB to open a transport
** channel. This function allocates and initializes a
** transport channel table entry. The channel can be opened
** in two roles: as an initiator or acceptor. When opened
** as an initiator the function will start an L2CAP connection.
** When opened as an acceptor the function simply configures
** the table entry to listen for an incoming channel.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role)
{
tAVDT_TC_TBL *p_tbl;
UINT16 lcid;
if((p_tbl = avdt_ad_tc_tbl_alloc(p_ccb)) == NULL)
{
AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl");
return;
}
p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d",
type, role, p_tbl->tcid);
if (type == AVDT_CHAN_SIG)
{
/* if signaling, get mtu from registration control block */
p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
}
else
{
/* otherwise get mtu from scb */
p_tbl->my_mtu = p_scb->cs.mtu;
p_tbl->my_flush_to = p_scb->cs.flush_to;
/* also set scb_hdl in rt_tbl */
avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = avdt_scb_to_hdl(p_scb);
AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d",
avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
avdt_scb_to_hdl(p_scb));
}
/* if we're acceptor, we're done; just sit back and listen */
if (role == AVDT_ACP)
{
p_tbl->state = AVDT_AD_ST_ACP;
}
/* else we're inititator, start the L2CAP connection */
else
{
p_tbl->state = AVDT_AD_ST_CONN;
/* call l2cap connect req */
if ((lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr)) != 0)
{
/* if connect req ok, store tcid in lcid table */
avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d",
(lcid - L2CAP_BASE_APPL_CID), avdt_ad_tc_tbl_to_idx(p_tbl));
avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
lcid);
}
else
{
/* if connect req failed, call avdt_ad_tc_close_ind() */
avdt_ad_tc_close_ind(p_tbl, 0);
}
}
}
/*******************************************************************************
**
** Function avdt_ad_close_req
**
** Description This function is called by a CCB or SCB to close a
** transport channel. The function looks up the LCID for the
** channel and calls L2CA_DisconnectReq().
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
{
UINT8 tcid;
tAVDT_TC_TBL *p_tbl;
p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d", p_tbl->state);
switch(p_tbl->state)
{
case AVDT_AD_ST_UNUSED:
/* probably for reporting */
break;
case AVDT_AD_ST_ACP:
/* if we're listening on this channel, send ourselves a close ind */
avdt_ad_tc_close_ind(p_tbl, 0);
break;
default:
/* get tcid from type, scb */
tcid = avdt_ad_type_to_tcid(type, p_scb);
/* call l2cap disconnect req */
L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,465 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* This module contains the channel control block state machine and
* functions which operate on the channel control block.
*
******************************************************************************/
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
#include "avdt_api.h"
#include "avdtc_api.h"
#include "avdt_int.h"
#include "gki.h"
#include "btu.h"
/*****************************************************************************
** state machine constants and types
*****************************************************************************/
#if AVDT_DEBUG == TRUE
/* verbose state strings for trace */
const char * const avdt_ccb_st_str[] = {
"CCB_IDLE_ST",
"CCB_OPENING_ST",
"CCB_OPEN_ST",
"CCB_CLOSING_ST"
};
/* verbose event strings for trace */
const char * const avdt_ccb_evt_str[] = {
"API_DISCOVER_REQ_EVT",
"API_GETCAP_REQ_EVT",
"API_START_REQ_EVT",
"API_SUSPEND_REQ_EVT",
"API_DISCOVER_RSP_EVT",
"API_GETCAP_RSP_EVT",
"API_START_RSP_EVT",
"API_SUSPEND_RSP_EVT",
"API_CONNECT_REQ_EVT",
"API_DISCONNECT_REQ_EVT",
"MSG_DISCOVER_CMD_EVT",
"MSG_GETCAP_CMD_EVT",
"MSG_START_CMD_EVT",
"MSG_SUSPEND_CMD_EVT",
"MSG_DISCOVER_RSP_EVT",
"MSG_GETCAP_RSP_EVT",
"MSG_START_RSP_EVT",
"MSG_SUSPEND_RSP_EVT",
"RCVRSP_EVT",
"SENDMSG_EVT",
"RET_TOUT_EVT",
"RSP_TOUT_EVT",
"IDLE_TOUT_EVT",
"UL_OPEN_EVT",
"UL_CLOSE_EVT",
"LL_OPEN_EVT",
"LL_CLOSE_EVT",
"LL_CONG_EVT"
};
#endif
/* action function list */
const tAVDT_CCB_ACTION avdt_ccb_action[] = {
avdt_ccb_chan_open,
avdt_ccb_chan_close,
avdt_ccb_chk_close,
avdt_ccb_hdl_discover_cmd,
avdt_ccb_hdl_discover_rsp,
avdt_ccb_hdl_getcap_cmd,
avdt_ccb_hdl_getcap_rsp,
avdt_ccb_hdl_start_cmd,
avdt_ccb_hdl_start_rsp,
avdt_ccb_hdl_suspend_cmd,
avdt_ccb_hdl_suspend_rsp,
avdt_ccb_snd_discover_cmd,
avdt_ccb_snd_discover_rsp,
avdt_ccb_snd_getcap_cmd,
avdt_ccb_snd_getcap_rsp,
avdt_ccb_snd_start_cmd,
avdt_ccb_snd_start_rsp,
avdt_ccb_snd_suspend_cmd,
avdt_ccb_snd_suspend_rsp,
avdt_ccb_clear_cmds,
avdt_ccb_cmd_fail,
avdt_ccb_free_cmd,
avdt_ccb_cong_state,
avdt_ccb_ret_cmd,
avdt_ccb_snd_cmd,
avdt_ccb_snd_msg,
avdt_ccb_set_reconn,
avdt_ccb_clr_reconn,
avdt_ccb_chk_reconn,
avdt_ccb_chk_timer,
avdt_ccb_set_conn,
avdt_ccb_set_disconn,
avdt_ccb_do_disconn,
avdt_ccb_ll_closed,
avdt_ccb_ll_opened,
avdt_ccb_dealloc
};
/* state table information */
#define AVDT_CCB_ACTIONS 2 /* number of actions */
#define AVDT_CCB_NEXT_STATE 2 /* position of next state */
#define AVDT_CCB_NUM_COLS 3 /* number of columns in state tables */
/* state table for idle state */
const UINT8 avdt_ccb_st_idle[][AVDT_CCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* UL_OPEN_EVT */ {AVDT_CCB_CHAN_OPEN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* UL_CLOSE_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* LL_OPEN_EVT */ {AVDT_CCB_LL_OPENED, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* LL_CONG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}
};
/* state table for opening state */
const UINT8 avdt_ccb_st_opening[][AVDT_CCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST},
/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* MSG_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* UL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
/* UL_CLOSE_EVT */ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST},
/* LL_OPEN_EVT */ {AVDT_CCB_SND_CMD, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST},
/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* LL_CONG_EVT */ {AVDT_CCB_CONG_STATE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}
};
/* state table for open state */
const UINT8 avdt_ccb_st_open[][AVDT_CCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* API_START_REQ_EVT */ {AVDT_CCB_SND_START_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_SND_SUSPEND_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_SND_DISCOVER_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* API_GETCAP_RSP_EVT */ {AVDT_CCB_SND_GETCAP_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* API_START_RSP_EVT */ {AVDT_CCB_SND_START_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_SND_SUSPEND_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST},
/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST},
/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_HDL_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_HDL_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* MSG_START_CMD_EVT */ {AVDT_CCB_HDL_START_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_HDL_SUSPEND_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_OPEN_ST},
/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_OPEN_ST},
/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* RCVRSP_EVT */ {AVDT_CCB_FREE_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* SENDMSG_EVT */ {AVDT_CCB_SND_MSG, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* RET_TOUT_EVT */ {AVDT_CCB_RET_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* RSP_TOUT_EVT */ {AVDT_CCB_CMD_FAIL, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
/* IDLE_TOUT_EVT */ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST},
/* UL_OPEN_EVT */ {AVDT_CCB_CHK_TIMER, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* UL_CLOSE_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* LL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
/* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* LL_CONG_EVT */ {AVDT_CCB_CONG_STATE, AVDT_CCB_SND_MSG, AVDT_CCB_OPEN_ST}
};
/* state table for closing state */
const UINT8 avdt_ccb_st_closing[][AVDT_CCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CLOSING_ST},
/* API_GETCAP_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CLOSING_ST},
/* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SET_CONN, AVDT_CCB_CLOSING_ST},
/* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_CLR_RECONN, AVDT_CCB_SET_DISCONN, AVDT_CCB_CLOSING_ST},
/* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* UL_OPEN_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* UL_CLOSE_EVT */ {AVDT_CCB_CLR_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* LL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
/* LL_CLOSE_EVT */ {AVDT_CCB_CHK_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
/* LL_CONG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}
};
/* type for state table */
typedef const UINT8 (*tAVDT_CCB_ST_TBL)[AVDT_CCB_NUM_COLS];
/* state table */
const tAVDT_CCB_ST_TBL avdt_ccb_st_tbl[] = {
avdt_ccb_st_idle,
avdt_ccb_st_opening,
avdt_ccb_st_open,
avdt_ccb_st_closing
};
/*******************************************************************************
**
** Function avdt_ccb_init
**
** Description Initialize channel control block module.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ccb_init(void)
{
memset(&avdt_cb.ccb[0], 0, sizeof(tAVDT_CCB) * AVDT_NUM_LINKS);
avdt_cb.p_ccb_act = (tAVDT_CCB_ACTION *) avdt_ccb_action;
}
/*******************************************************************************
**
** Function avdt_ccb_event
**
** Description State machine event handling function for ccb
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data)
{
tAVDT_CCB_ST_TBL state_table;
UINT8 action;
int i;
#if AVDT_DEBUG == TRUE
AVDT_TRACE_EVENT("CCB ccb=%d event=%s state=%s", avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state]);
#endif
/* look up the state table for the current state */
state_table = avdt_ccb_st_tbl[p_ccb->state];
/* set next state */
if (p_ccb->state != state_table[event][AVDT_CCB_NEXT_STATE]) {
p_ccb->state = state_table[event][AVDT_CCB_NEXT_STATE];
}
/* execute action functions */
for (i = 0; i < AVDT_CCB_ACTIONS; i++)
{
if ((action = state_table[event][i]) != AVDT_CCB_IGNORE)
{
(*avdt_cb.p_ccb_act[action])(p_ccb, p_data);
}
else
{
break;
}
}
}
/*******************************************************************************
**
** Function avdt_ccb_by_bd
**
** Description This lookup function finds the ccb for a BD address.
**
**
** Returns pointer to the ccb, or NULL if none found.
**
*******************************************************************************/
tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr)
{
tAVDT_CCB *p_ccb = &avdt_cb.ccb[0];
int i;
for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++)
{
/* if allocated ccb has matching ccb */
if (p_ccb->allocated && (!memcmp(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN)))
{
break;
}
}
if (i == AVDT_NUM_LINKS)
{
/* if no ccb found */
p_ccb = NULL;
AVDT_TRACE_DEBUG("No ccb for 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]);
}
return p_ccb;
}
/*******************************************************************************
**
** Function avdt_ccb_alloc
**
** Description Allocate a channel control block.
**
**
** Returns pointer to the ccb, or NULL if none could be allocated.
**
*******************************************************************************/
tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr)
{
tAVDT_CCB *p_ccb = &avdt_cb.ccb[0];
int i;
for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++)
{
if (!p_ccb->allocated)
{
p_ccb->allocated = TRUE;
memcpy(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN);
GKI_init_q(&p_ccb->cmd_q);
GKI_init_q(&p_ccb->rsp_q);
p_ccb->timer_entry.param = (UINT32) p_ccb;
AVDT_TRACE_DEBUG("avdt_ccb_alloc %d", i);
break;
}
}
if (i == AVDT_NUM_LINKS)
{
/* out of ccbs */
p_ccb = NULL;
AVDT_TRACE_WARNING("Out of ccbs");
}
return p_ccb;
}
/*******************************************************************************
**
** Function avdt_ccb_dealloc
**
** Description Deallocate a stream control block.
**
**
** Returns void.
**
*******************************************************************************/
void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data)
{
UNUSED(p_data);
AVDT_TRACE_DEBUG("avdt_ccb_dealloc %d", avdt_ccb_to_idx(p_ccb));
btu_stop_timer(&p_ccb->timer_entry);
memset(p_ccb, 0, sizeof(tAVDT_CCB));
}
/*******************************************************************************
**
** Function avdt_ccb_to_idx
**
** Description Given a pointer to an ccb, return its index.
**
**
** Returns Index of ccb.
**
*******************************************************************************/
UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb)
{
/* use array arithmetic to determine index */
return (UINT8) (p_ccb - avdt_cb.ccb);
}
/*******************************************************************************
**
** Function avdt_ccb_by_idx
**
** Description Return ccb pointer based on ccb index.
**
**
** Returns pointer to the ccb, or NULL if none found.
**
*******************************************************************************/
tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx)
{
tAVDT_CCB *p_ccb;
/* verify index */
if (idx < AVDT_NUM_LINKS)
{
p_ccb = &avdt_cb.ccb[idx];
}
else
{
p_ccb = NULL;
AVDT_TRACE_WARNING("No ccb for idx %d", idx);
}
return p_ccb;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,529 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* This AVDTP adaption layer module interfaces to L2CAP
*
******************************************************************************/
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
#include "avdt_api.h"
#include "avdtc_api.h"
#include "avdt_int.h"
#include "l2c_api.h"
#include "l2cdefs.h"
#include "btm_api.h"
#include "btm_int.h"
/* callback function declarations */
void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
/* L2CAP callback function structure */
const tL2CAP_APPL_INFO avdt_l2c_appl = {
avdt_l2c_connect_ind_cback,
avdt_l2c_connect_cfm_cback,
NULL,
avdt_l2c_config_ind_cback,
avdt_l2c_config_cfm_cback,
avdt_l2c_disconnect_ind_cback,
avdt_l2c_disconnect_cfm_cback,
NULL,
avdt_l2c_data_ind_cback,
avdt_l2c_congestion_ind_cback,
NULL /* tL2CA_TX_COMPLETE_CB */
};
/*******************************************************************************
**
** Function avdt_sec_check_complete_term
**
** Description The function called when Security Manager finishes
** verification of the service side connection
**
** Returns void
**
*******************************************************************************/
static void avdt_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport,
void *p_ref_data, UINT8 res)
{
tAVDT_CCB *p_ccb = NULL;
tL2CAP_CFG_INFO cfg;
tAVDT_TC_TBL *p_tbl;
UNUSED(p_ref_data);
AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d", res);
if (!bd_addr)
{
AVDT_TRACE_WARNING("avdt_sec_check_complete_term: NULL BD_ADDR");
return;
}
p_ccb = avdt_ccb_by_bd(bd_addr);
p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP);
if (p_tbl == NULL)
return;
if (res == BTM_SUCCESS)
{
/* Send response to the L2CAP layer. */
L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK);
/* store idx in LCID table, store LCID in routing table */
avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
/* transition to configuration state */
p_tbl->state = AVDT_AD_ST_CFG;
/* Send L2CAP config req */
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
cfg.mtu_present = TRUE;
cfg.mtu = p_tbl->my_mtu;
cfg.flush_to_present = TRUE;
cfg.flush_to = p_tbl->my_flush_to;
L2CA_ConfigReq(p_tbl->lcid, &cfg);
}
else
{
L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
}
}
/*******************************************************************************
**
** Function avdt_sec_check_complete_orig
**
** Description The function called when Security Manager finishes
** verification of the service side connection
**
** Returns void
**
*******************************************************************************/
static void avdt_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
void *p_ref_data, UINT8 res)
{
tAVDT_CCB *p_ccb = NULL;
tL2CAP_CFG_INFO cfg;
tAVDT_TC_TBL *p_tbl;
UNUSED(p_ref_data);
AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d", res);
if (bd_addr)
p_ccb = avdt_ccb_by_bd(bd_addr);
p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT);
if(p_tbl == NULL)
return;
if( res == BTM_SUCCESS )
{
/* set channel state */
p_tbl->state = AVDT_AD_ST_CFG;
/* Send L2CAP config req */
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
cfg.mtu_present = TRUE;
cfg.mtu = p_tbl->my_mtu;
cfg.flush_to_present = TRUE;
cfg.flush_to = p_tbl->my_flush_to;
L2CA_ConfigReq(p_tbl->lcid, &cfg);
}
else
{
L2CA_DisconnectReq (p_tbl->lcid);
avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
}
}
/*******************************************************************************
**
** Function avdt_l2c_connect_ind_cback
**
** Description This is the L2CAP connect indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
{
tAVDT_CCB *p_ccb;
tAVDT_TC_TBL *p_tbl = NULL;
UINT16 result;
tL2CAP_CFG_INFO cfg;
tBTM_STATUS rc;
UNUSED(psm);
/* do we already have a control channel for this peer? */
if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
{
/* no, allocate ccb */
if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL)
{
/* no ccb available, reject L2CAP connection */
result = L2CAP_CONN_NO_RESOURCES;
}
else
{
/* allocate and set up entry; first channel is always signaling */
p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
p_tbl->tcid = AVDT_CHAN_SIG;
p_tbl->lcid = lcid;
p_tbl->id = id;
p_tbl->state = AVDT_AD_ST_SEC_ACP;
p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
/* Check the security */
rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
FALSE, BTM_SEC_PROTO_AVDT,
AVDT_CHAN_SIG,
&avdt_sec_check_complete_term, NULL);
if(rc == BTM_CMD_STARTED)
{
L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
}
return;
}
}
/* deal with simultaneous control channel connect case */
else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL)
{
/* reject their connection */
result = L2CAP_CONN_NO_RESOURCES;
}
/* this must be a traffic channel; are we accepting a traffic channel
** for this ccb?
*/
else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL)
{
/* yes; proceed with connection */
result = L2CAP_CONN_OK;
}
#if AVDT_REPORTING == TRUE
/* this must be a reporting channel; are we accepting a reporting channel
** for this ccb?
*/
else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL)
{
/* yes; proceed with connection */
result = L2CAP_CONN_OK;
}
#endif
/* else we're not listening for traffic channel; reject */
else
{
result = L2CAP_CONN_NO_PSM;
}
/* Send L2CAP connect rsp */
L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
/* if result ok, proceed with connection */
if (result == L2CAP_CONN_OK)
{
/* store idx in LCID table, store LCID in routing table */
avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
/* transition to configuration state */
p_tbl->state = AVDT_AD_ST_CFG;
/* Send L2CAP config req */
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
cfg.mtu_present = TRUE;
cfg.mtu = p_tbl->my_mtu;
cfg.flush_to_present = TRUE;
cfg.flush_to = p_tbl->my_flush_to;
L2CA_ConfigReq(lcid, &cfg);
}
}
/*******************************************************************************
**
** Function avdt_l2c_connect_cfm_cback
**
** Description This is the L2CAP connect confirm callback function.
**
**
** Returns void
**
*******************************************************************************/
void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
{
tAVDT_TC_TBL *p_tbl;
tL2CAP_CFG_INFO cfg;
tAVDT_CCB *p_ccb;
AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d",
lcid, result);
/* look up info for this channel */
if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
{
/* if in correct state */
if (p_tbl->state == AVDT_AD_ST_CONN)
{
/* if result successful */
if (result == L2CAP_CONN_OK)
{
if(p_tbl->tcid != AVDT_CHAN_SIG)
{
/* set channel state */
p_tbl->state = AVDT_AD_ST_CFG;
/* Send L2CAP config req */
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
cfg.mtu_present = TRUE;
cfg.mtu = p_tbl->my_mtu;
cfg.flush_to_present = TRUE;
cfg.flush_to = p_tbl->my_flush_to;
L2CA_ConfigReq(lcid, &cfg);
}
else
{
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
if(p_ccb == NULL)
{
result = L2CAP_CONN_NO_RESOURCES;
}
else
{
/* set channel state */
p_tbl->state = AVDT_AD_ST_SEC_INT;
p_tbl->lcid = lcid;
p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
/* Check the security */
btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
TRUE, BTM_SEC_PROTO_AVDT,
AVDT_CHAN_SIG,
&avdt_sec_check_complete_orig, NULL);
}
}
}
/* failure; notify adaption that channel closed */
if (result != L2CAP_CONN_OK)
{
avdt_ad_tc_close_ind(p_tbl, result);
}
}
}
}
/*******************************************************************************
**
** Function avdt_l2c_config_cfm_cback
**
** Description This is the L2CAP config confirm callback function.
**
**
** Returns void
**
*******************************************************************************/
void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
{
tAVDT_TC_TBL *p_tbl;
/* look up info for this channel */
if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
{
p_tbl->lcid = lcid;
/* if in correct state */
if (p_tbl->state == AVDT_AD_ST_CFG)
{
/* if result successful */
if (p_cfg->result == L2CAP_CONN_OK)
{
/* update cfg_flags */
p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
/* if configuration complete */
if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE)
{
avdt_ad_tc_open_ind(p_tbl);
}
}
/* else failure */
else
{
/* Send L2CAP disconnect req */
L2CA_DisconnectReq(lcid);
}
}
}
}
/*******************************************************************************
**
** Function avdt_l2c_config_ind_cback
**
** Description This is the L2CAP config indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
{
tAVDT_TC_TBL *p_tbl;
/* look up info for this channel */
if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
{
/* store the mtu in tbl */
if (p_cfg->mtu_present)
{
p_tbl->peer_mtu = p_cfg->mtu;
}
else
{
p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
}
AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x",p_tbl->peer_mtu, lcid);
/* send L2CAP configure response */
memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
p_cfg->result = L2CAP_CFG_OK;
L2CA_ConfigRsp(lcid, p_cfg);
/* if first config ind */
if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0)
{
/* update cfg_flags */
p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
/* if configuration complete */
if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE)
{
avdt_ad_tc_open_ind(p_tbl);
}
}
}
}
/*******************************************************************************
**
** Function avdt_l2c_disconnect_ind_cback
**
** Description This is the L2CAP disconnect indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
{
tAVDT_TC_TBL *p_tbl;
AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
lcid, ack_needed);
/* look up info for this channel */
if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
{
if (ack_needed)
{
/* send L2CAP disconnect response */
L2CA_DisconnectRsp(lcid);
}
avdt_ad_tc_close_ind(p_tbl, 0);
}
}
/*******************************************************************************
**
** Function avdt_l2c_disconnect_cfm_cback
**
** Description This is the L2CAP disconnect confirm callback function.
**
**
** Returns void
**
*******************************************************************************/
void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
{
tAVDT_TC_TBL *p_tbl;
AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d",
lcid, result);
/* look up info for this channel */
if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
{
avdt_ad_tc_close_ind(p_tbl, result);
}
}
/*******************************************************************************
**
** Function avdt_l2c_congestion_ind_cback
**
** Description This is the L2CAP congestion indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
{
tAVDT_TC_TBL *p_tbl;
/* look up info for this channel */
if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
{
avdt_ad_tc_cong_ind(p_tbl, is_congested);
}
}
/*******************************************************************************
**
** Function avdt_l2c_data_ind_cback
**
** Description This is the L2CAP data indication callback function.
**
**
** Returns void
**
*******************************************************************************/
void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
{
tAVDT_TC_TBL *p_tbl;
/* look up info for this channel */
if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
{
avdt_ad_tc_data_ind(p_tbl, p_buf);
}
else /* prevent buffer leak */
GKI_freebuf(p_buf);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,799 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* This module contains the stream control block and functions which
* operate on the stream control block.
*
******************************************************************************/
#include <string.h>
#include "bt_types.h"
#include "bt_target.h"
#include "bt_utils.h"
#include "avdt_api.h"
#include "avdtc_api.h"
#include "avdt_int.h"
#include "gki.h"
#include "btu.h"
/*****************************************************************************
** state machine constants and types
*****************************************************************************/
#if AVDT_DEBUG == TRUE
/* verbose state strings for trace */
const char * const avdt_scb_st_str[] = {
"SCB_IDLE_ST",
"SCB_CONF_ST",
"SCB_OPENING_ST",
"SCB_OPEN_ST",
"SCB_STREAM_ST",
"SCB_CLOSING_ST"
};
/* verbose event strings for trace */
const char * const avdt_scb_evt_str[] = {
"API_REMOVE_EVT",
"API_WRITE_REQ_EVT",
"API_GETCONFIG_REQ_EVT",
"API_DELAY_RPT_REQ",
"API_SETCONFIG_REQ_EVT",
"API_OPEN_REQ_EVT",
"API_CLOSE_REQ_EVT",
"API_RECONFIG_REQ_EVT",
"API_SECURITY_REQ_EVT",
"API_ABORT_REQ_EVT",
"API_GETCONFIG_RSP_EVT",
"API_SETCONFIG_RSP_EVT",
"API_SETCONFIG_REJ_EVT",
"API_OPEN_RSP_EVT",
"API_CLOSE_RSP_EVT",
"API_RECONFIG_RSP_EVT",
"API_SECURITY_RSP_EVT",
"API_ABORT_RSP_EVT",
"MSG_SETCONFIG_CMD_EVT",
"MSG_GETCONFIG_CMD_EVT",
"MSG_OPEN_CMD_EVT",
"MSG_START_CMD_EVT",
"MSG_SUSPEND_CMD_EVT",
"MSG_CLOSE_CMD_EVT",
"MSG_ABORT_CMD_EVT",
"MSG_RECONFIG_CMD_EVT",
"MSG_SECURITY_CMD_EVT",
"MSG_DELAY_RPT_CMD_EVT",
"MSG_DELAY_RPT_RSP_EVT",
"MSG_SETCONFIG_RSP_EVT",
"MSG_GETCONFIG_RSP_EVT",
"MSG_OPEN_RSP_EVT",
"MSG_START_RSP_EVT",
"MSG_SUSPEND_RSP_EVT",
"MSG_CLOSE_RSP_EVT",
"MSG_ABORT_RSP_EVT",
"MSG_RECONFIG_RSP_EVT",
"MSG_SECURITY_RSP_EVT",
"MSG_SETCONFIG_REJ_EVT",
"MSG_OPEN_REJ_EVT",
"MSG_START_REJ_EVT",
"MSG_SUSPEND_REJ_EVT",
"TC_TOUT_EVT",
"TC_OPEN_EVT",
"TC_CLOSE_EVT",
"TC_CONG_EVT",
"TC_DATA_EVT",
"CC_CLOSE_EVT"
};
#endif
/* action function list */
const tAVDT_SCB_ACTION avdt_scb_action[] = {
avdt_scb_hdl_abort_cmd,
avdt_scb_hdl_abort_rsp,
avdt_scb_hdl_close_cmd,
avdt_scb_hdl_close_rsp,
avdt_scb_hdl_getconfig_cmd,
avdt_scb_hdl_getconfig_rsp,
avdt_scb_hdl_open_cmd,
avdt_scb_hdl_open_rej,
avdt_scb_hdl_open_rsp,
avdt_scb_hdl_pkt,
avdt_scb_drop_pkt,
avdt_scb_hdl_reconfig_cmd,
avdt_scb_hdl_reconfig_rsp,
avdt_scb_hdl_security_cmd,
avdt_scb_hdl_security_rsp,
avdt_scb_hdl_setconfig_cmd,
avdt_scb_hdl_setconfig_rej,
avdt_scb_hdl_setconfig_rsp,
avdt_scb_hdl_start_cmd,
avdt_scb_hdl_start_rsp,
avdt_scb_hdl_suspend_cmd,
avdt_scb_hdl_suspend_rsp,
avdt_scb_hdl_tc_close,
#if AVDT_REPORTING == TRUE
avdt_scb_hdl_tc_close_sto,
#endif
avdt_scb_hdl_tc_open,
#if AVDT_REPORTING == TRUE
avdt_scb_hdl_tc_open_sto,
#endif
avdt_scb_snd_delay_rpt_req,
avdt_scb_hdl_delay_rpt_cmd,
avdt_scb_hdl_delay_rpt_rsp,
avdt_scb_hdl_write_req,
avdt_scb_snd_abort_req,
avdt_scb_snd_abort_rsp,
avdt_scb_snd_close_req,
avdt_scb_snd_stream_close,
avdt_scb_snd_close_rsp,
avdt_scb_snd_getconfig_req,
avdt_scb_snd_getconfig_rsp,
avdt_scb_snd_open_req,
avdt_scb_snd_open_rsp,
avdt_scb_snd_reconfig_req,
avdt_scb_snd_reconfig_rsp,
avdt_scb_snd_security_req,
avdt_scb_snd_security_rsp,
avdt_scb_snd_setconfig_req,
avdt_scb_snd_setconfig_rej,
avdt_scb_snd_setconfig_rsp,
avdt_scb_snd_tc_close,
avdt_scb_cb_err,
avdt_scb_cong_state,
avdt_scb_rej_state,
avdt_scb_rej_in_use,
avdt_scb_rej_not_in_use,
avdt_scb_set_remove,
avdt_scb_free_pkt,
avdt_scb_clr_pkt,
avdt_scb_chk_snd_pkt,
avdt_scb_tc_timer,
avdt_scb_clr_vars,
avdt_scb_dealloc
};
/* state table information */
#define AVDT_SCB_ACTIONS 2 /* number of actions */
#define AVDT_SCB_NEXT_STATE 2 /* position of next state */
#define AVDT_SCB_NUM_COLS 3 /* number of columns in state tables */
/* state table for idle state */
const UINT8 avdt_scb_st_idle[][AVDT_SCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_REMOVE_EVT */ {AVDT_SCB_DEALLOC, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_SND_SETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_OPEN_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_CLOSE_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_SECURITY_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_ABORT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_SND_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_SND_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_SETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_NOT_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_HDL_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* TC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* CC_CLOSE_EVT */ {AVDT_SCB_CLR_VARS, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}
};
/* state table for configured state */
const UINT8 avdt_scb_st_conf[][AVDT_SCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_REMOVE_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CONF_ST},
/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_OPEN_REQ_EVT */ {AVDT_SCB_SND_OPEN_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_OPEN_RSP_EVT */ {AVDT_SCB_SND_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST},
/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_HDL_OPEN_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_HDL_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST},
/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_HDL_OPEN_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* TC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
/* CC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}
};
/* state table for opening state */
const UINT8 avdt_scb_st_opening[][AVDT_SCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_REMOVE_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST},
/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST},
/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST},
/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* TC_TOUT_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* TC_OPEN_EVT */ {AVDT_SCB_HDL_TC_OPEN, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
};
/* state table for open state */
const UINT8 avdt_scb_st_open[][AVDT_SCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_REMOVE_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_SND_RECONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_SND_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_START_CMD_EVT */ {AVDT_SCB_HDL_START_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_HDL_RECONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_START_RSP_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
#if AVDT_REPORTING == TRUE
/* TC_OPEN_EVT */ {AVDT_SCB_HDL_TC_OPEN_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
#else
/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
#endif
/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
};
/* state table for streaming state */
const UINT8 avdt_scb_st_stream[][AVDT_SCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_REMOVE_EVT */ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
/* API_WRITE_REQ_EVT */ {AVDT_SCB_HDL_WRITE_REQ, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST},
/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_CLR_PKT, AVDT_SCB_CLOSING_ST},
/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_HDL_SUSPEND_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST},
/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_STREAM_ST},
/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST},
/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST},
/* TC_DATA_EVT */ {AVDT_SCB_HDL_PKT, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
/* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
};
/* state table for closing state */
const UINT8 avdt_scb_st_closing[][AVDT_SCB_NUM_COLS] = {
/* Event Action 1 Action 2 Next state */
/* API_REMOVE_EVT */ {AVDT_SCB_SET_REMOVE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_OPEN_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_CLOSE_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_SECURITY_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_ABORT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_CLOSE_RSP, AVDT_SCB_CLOSING_ST},
/* MSG_ABORT_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST},
/* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* TC_TOUT_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* TC_OPEN_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
/* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
/* CC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}
};
/* type for state table */
typedef const UINT8 (*tAVDT_SCB_ST_TBL)[AVDT_SCB_NUM_COLS];
/* state table */
const tAVDT_SCB_ST_TBL avdt_scb_st_tbl[] = {
avdt_scb_st_idle,
avdt_scb_st_conf,
avdt_scb_st_opening,
avdt_scb_st_open,
avdt_scb_st_stream,
avdt_scb_st_closing
};
/*******************************************************************************
**
** Function avdt_scb_event
**
** Description State machine event handling function for scb
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data)
{
tAVDT_SCB_ST_TBL state_table;
UINT8 action;
int i;
#if AVDT_DEBUG == TRUE
AVDT_TRACE_EVENT("SCB hdl=%d event=%d/%s state=%s", avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event], avdt_scb_st_str[p_scb->state]);
#endif
/* set current event */
p_scb->curr_evt = event;
/* look up the state table for the current state */
state_table = avdt_scb_st_tbl[p_scb->state];
/* set next state */
if (p_scb->state != state_table[event][AVDT_SCB_NEXT_STATE]) {
p_scb->state = state_table[event][AVDT_SCB_NEXT_STATE];
}
/* execute action functions */
for (i = 0; i < AVDT_SCB_ACTIONS; i++)
{
if ((action = state_table[event][i]) != AVDT_SCB_IGNORE)
{
(*avdt_cb.p_scb_act[action])(p_scb, p_data);
}
else
{
break;
}
}
}
/*******************************************************************************
**
** Function avdt_scb_init
**
** Description Initialize stream control block module.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_scb_init(void)
{
memset(&avdt_cb.scb[0], 0, sizeof(tAVDT_SCB) * AVDT_NUM_SEPS);
avdt_cb.p_scb_act = (tAVDT_SCB_ACTION *) avdt_scb_action;
}
/*******************************************************************************
**
** Function avdt_scb_alloc
**
** Description Allocate a stream control block.
**
**
** Returns pointer to the scb, or NULL if none could be allocated.
**
*******************************************************************************/
tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs)
{
tAVDT_SCB *p_scb = &avdt_cb.scb[0];
int i;
/* find available scb */
for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++)
{
if (!p_scb->allocated)
{
memset(p_scb,0,sizeof(tAVDT_SCB));
p_scb->allocated = TRUE;
p_scb->p_ccb = NULL;
/* initialize sink as activated */
if (p_cs->tsep == AVDT_TSEP_SNK)
{
p_scb->sink_activated = TRUE;
}
memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS));
#if AVDT_MULTIPLEXING == TRUE
/* initialize fragments gueue */
GKI_init_q(&p_scb->frag_q);
if(p_cs->cfg.psc_mask & AVDT_PSC_MUX)
{
p_scb->cs.cfg.mux_tcid_media = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
#if AVDT_REPORTING == TRUE
if(p_cs->cfg.psc_mask & AVDT_PSC_REPORT)
{
p_scb->cs.cfg.mux_tcid_report = avdt_ad_type_to_tcid(AVDT_CHAN_REPORT, p_scb);
}
#endif
}
#endif
p_scb->timer_entry.param = (UINT32) p_scb;
AVDT_TRACE_DEBUG("avdt_scb_alloc hdl=%d, psc_mask:0x%x", i+1, p_cs->cfg.psc_mask);
break;
}
}
if (i == AVDT_NUM_SEPS)
{
/* out of ccbs */
p_scb = NULL;
AVDT_TRACE_WARNING("Out of scbs");
}
return p_scb;
}
/*******************************************************************************
**
** Function avdt_scb_dealloc
**
** Description Deallocate a stream control block.
**
**
** Returns void.
**
*******************************************************************************/
void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data)
{
#if AVDT_MULTIPLEXING == TRUE
void *p_buf;
#endif
UNUSED(p_data);
AVDT_TRACE_DEBUG("avdt_scb_dealloc hdl=%d", avdt_scb_to_hdl(p_scb));
btu_stop_timer(&p_scb->timer_entry);
#if AVDT_MULTIPLEXING == TRUE
/* free fragments we're holding, if any; it shouldn't happen */
while ((p_buf = GKI_dequeue (&p_scb->frag_q)) != NULL)
GKI_freebuf(p_buf);
#endif
memset(p_scb, 0, sizeof(tAVDT_SCB));
}
/*******************************************************************************
**
** Function avdt_scb_to_hdl
**
** Description Given a pointer to an scb, return its handle (or seid).
**
**
** Returns Index of scb.
**
*******************************************************************************/
UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb)
{
return (UINT8) (p_scb - avdt_cb.scb + 1);
}
/*******************************************************************************
**
** Function avdt_scb_by_hdl
**
** Description Given an scb handle (or seid), return a pointer to the scb.
**
**
** Returns Pointer to scb or NULL if index is out of range or scb
** is not allocated.
**
*******************************************************************************/
tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl)
{
tAVDT_SCB *p_scb;
/* verify index */
if ((hdl > 0) && (hdl <= AVDT_NUM_SEPS))
{
p_scb = &avdt_cb.scb[hdl - 1];
/* verify scb is allocated */
if (!p_scb->allocated)
{
p_scb = NULL;
AVDT_TRACE_WARNING("scb hdl %d not allocated", hdl);
}
}
else
{
p_scb = NULL;
AVDT_TRACE_WARNING("scb hdl %d out of range", hdl);
}
return p_scb;
}
/*******************************************************************************
**
** Function avdt_scb_verify
**
** Description Verify the condition of a list of scbs.
**
**
** Returns SEID that failed, or 0 if success.
**
*******************************************************************************/
UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code)
{
int i;
tAVDT_SCB *p_scb;
UINT8 nsc_mask;
UINT8 ret = 0;
AVDT_TRACE_DEBUG("avdt_scb_verify state %d", state);
/* set nonsupported command mask */
/* translate public state into private state */
nsc_mask = 0;
if (state == AVDT_VERIFY_SUSPEND)
nsc_mask = AVDT_NSC_SUSPEND;
/* verify every scb */
for (i = 0, *p_err_code = 0; (i < num_seid) && (*p_err_code == 0) && (i < AVDT_NUM_SEPS); i++)
{
if ((p_scb = avdt_scb_by_hdl(p_seid[i])) == NULL)
*p_err_code = AVDT_ERR_BAD_STATE;
else if (p_scb->p_ccb != p_ccb)
*p_err_code = AVDT_ERR_BAD_STATE;
else if (p_scb->cs.nsc_mask & nsc_mask)
*p_err_code = AVDT_ERR_NSC;
switch (state) {
case AVDT_VERIFY_OPEN:
case AVDT_VERIFY_START:
if (p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST)
*p_err_code = AVDT_ERR_BAD_STATE;
break;
case AVDT_VERIFY_SUSPEND:
case AVDT_VERIFY_STREAMING:
if (p_scb->state != AVDT_SCB_STREAM_ST)
*p_err_code = AVDT_ERR_BAD_STATE;
break;
}
}
if ((i != num_seid) && (i < AVDT_NUM_SEPS))
{
ret = p_seid[i];
}
return ret;
}
/*******************************************************************************
**
** Function avdt_scb_peer_seid_list
**
** Description Given a list of SCB handles, return a list of peer SEIDs
** for the handles, copied in place into the struct passed in.
**
**
** Returns Nothing.
**
*******************************************************************************/
void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi)
{
int i;
tAVDT_SCB *p_scb;
for (i = 0; i < p_multi->num_seps; i++)
{
if ((p_scb = avdt_scb_by_hdl(p_multi->seid_list[i])) != NULL)
{
p_multi->seid_list[i] = p_scb->peer_seid;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,742 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/******************************************************************************
*
* This file contains interfaces which are internal to AVDTP.
*
******************************************************************************/
#ifndef AVDT_INT_H
#define AVDT_INT_H
#include "gki.h"
#include "avdt_api.h"
#include "avdtc_api.h"
#include "avdt_defs.h"
#include "l2c_api.h"
#include "btm_api.h"
#ifndef AVDT_DEBUG
#define AVDT_DEBUG FALSE
#endif
/*****************************************************************************
** constants
*****************************************************************************/
/* channel types */
enum {
AVDT_CHAN_SIG, /* signaling channel */
AVDT_CHAN_MEDIA, /* media channel */
#if AVDT_REPORTING == TRUE
AVDT_CHAN_REPORT, /* reporting channel */
#endif
AVDT_CHAN_NUM_TYPES
};
/* protocol service capabilities of this AVDTP implementation */
/* for now multiplexing will be used only for fragmentation */
#if ((AVDT_MULTIPLEXING == TRUE) && (AVDT_REPORTING == TRUE))
#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT)
#else /* AVDT_MULTIPLEXING && AVDT_REPORTING */
#if (AVDT_MULTIPLEXING == TRUE)
#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_DELAY_RPT)
#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX)
#else /* AVDT_MULTIPLEXING */
#if (AVDT_REPORTING == TRUE)
#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT)
#else /* AVDT_REPORTING */
#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_DELAY_RPT)
#define AVDT_LEG_PSC (AVDT_PSC_TRANS)
#endif /* AVDT_REPORTING */
#endif /* AVDT_MULTIPLEXING */
#endif /* AVDT_MULTIPLEXING && AVDT_REPORTING */
/* initiator/acceptor signaling roles */
#define AVDT_CLOSE_ACP 0
#define AVDT_CLOSE_INT 1
#define AVDT_OPEN_ACP 2
#define AVDT_OPEN_INT 3
/* states for avdt_scb_verify */
#define AVDT_VERIFY_OPEN 0
#define AVDT_VERIFY_STREAMING 1
#define AVDT_VERIFY_SUSPEND 2
#define AVDT_VERIFY_START 3
/* to distinguish CCB events from SCB events */
#define AVDT_CCB_MKR 0x80
/* offset where AVDTP signaling message header starts in message */
#define AVDT_HDR_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS)
/* offset where AVDTP signaling message content starts;
** use the size of a start header since it's the largest possible
** layout of signaling message in a buffer is:
**
** | BT_HDR | SCB handles | L2CAP + HCI header | AVDTP header | data ... |
**
** Note that we "hide" the scb handles at the top of the message buffer.
*/
#define AVDT_MSG_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS + AVDT_LEN_TYPE_START)
/* scb transport channel connect timeout value */
#define AVDT_SCB_TC_CONN_TOUT 10
/* scb transport channel disconnect timeout value */
#define AVDT_SCB_TC_DISC_TOUT 10
/* maximum number of command retransmissions */
#ifndef AVDT_RET_MAX
#define AVDT_RET_MAX 1
#endif
/* ccb state machine states */
enum {
AVDT_CCB_IDLE_ST,
AVDT_CCB_OPENING_ST,
AVDT_CCB_OPEN_ST,
AVDT_CCB_CLOSING_ST
};
/* state machine action enumeration list */
enum {
AVDT_CCB_CHAN_OPEN,
AVDT_CCB_CHAN_CLOSE,
AVDT_CCB_CHK_CLOSE,
AVDT_CCB_HDL_DISCOVER_CMD,
AVDT_CCB_HDL_DISCOVER_RSP,
AVDT_CCB_HDL_GETCAP_CMD,
AVDT_CCB_HDL_GETCAP_RSP,
AVDT_CCB_HDL_START_CMD,
AVDT_CCB_HDL_START_RSP,
AVDT_CCB_HDL_SUSPEND_CMD,
AVDT_CCB_HDL_SUSPEND_RSP,
AVDT_CCB_SND_DISCOVER_CMD,
AVDT_CCB_SND_DISCOVER_RSP,
AVDT_CCB_SND_GETCAP_CMD,
AVDT_CCB_SND_GETCAP_RSP,
AVDT_CCB_SND_START_CMD,
AVDT_CCB_SND_START_RSP,
AVDT_CCB_SND_SUSPEND_CMD,
AVDT_CCB_SND_SUSPEND_RSP,
AVDT_CCB_CLEAR_CMDS,
AVDT_CCB_CMD_FAIL,
AVDT_CCB_FREE_CMD,
AVDT_CCB_CONG_STATE,
AVDT_CCB_RET_CMD,
AVDT_CCB_SND_CMD,
AVDT_CCB_SND_MSG,
AVDT_CCB_SET_RECONN,
AVDT_CCB_CLR_RECONN,
AVDT_CCB_CHK_RECONN,
AVDT_CCB_CHK_TIMER,
AVDT_CCB_SET_CONN,
AVDT_CCB_SET_DISCONN,
AVDT_CCB_DO_DISCONN,
AVDT_CCB_LL_CLOSED,
AVDT_CCB_LL_OPENED,
AVDT_CCB_DEALLOC,
AVDT_CCB_NUM_ACTIONS
};
#define AVDT_CCB_IGNORE AVDT_CCB_NUM_ACTIONS
/* ccb state machine events */
enum {
AVDT_CCB_API_DISCOVER_REQ_EVT,
AVDT_CCB_API_GETCAP_REQ_EVT,
AVDT_CCB_API_START_REQ_EVT,
AVDT_CCB_API_SUSPEND_REQ_EVT,
AVDT_CCB_API_DISCOVER_RSP_EVT,
AVDT_CCB_API_GETCAP_RSP_EVT,
AVDT_CCB_API_START_RSP_EVT,
AVDT_CCB_API_SUSPEND_RSP_EVT,
AVDT_CCB_API_CONNECT_REQ_EVT,
AVDT_CCB_API_DISCONNECT_REQ_EVT,
AVDT_CCB_MSG_DISCOVER_CMD_EVT,
AVDT_CCB_MSG_GETCAP_CMD_EVT,
AVDT_CCB_MSG_START_CMD_EVT,
AVDT_CCB_MSG_SUSPEND_CMD_EVT,
AVDT_CCB_MSG_DISCOVER_RSP_EVT,
AVDT_CCB_MSG_GETCAP_RSP_EVT,
AVDT_CCB_MSG_START_RSP_EVT,
AVDT_CCB_MSG_SUSPEND_RSP_EVT,
AVDT_CCB_RCVRSP_EVT,
AVDT_CCB_SENDMSG_EVT,
AVDT_CCB_RET_TOUT_EVT,
AVDT_CCB_RSP_TOUT_EVT,
AVDT_CCB_IDLE_TOUT_EVT,
AVDT_CCB_UL_OPEN_EVT,
AVDT_CCB_UL_CLOSE_EVT,
AVDT_CCB_LL_OPEN_EVT,
AVDT_CCB_LL_CLOSE_EVT,
AVDT_CCB_LL_CONG_EVT
};
/* scb state machine states; these state values are private to this module so
** the scb state cannot be read or set by actions functions
*/
enum {
AVDT_SCB_IDLE_ST,
AVDT_SCB_CONF_ST,
AVDT_SCB_OPENING_ST,
AVDT_SCB_OPEN_ST,
AVDT_SCB_STREAM_ST,
AVDT_SCB_CLOSING_ST
};
/* state machine action enumeration list */
enum {
AVDT_SCB_HDL_ABORT_CMD,
AVDT_SCB_HDL_ABORT_RSP,
AVDT_SCB_HDL_CLOSE_CMD,
AVDT_SCB_HDL_CLOSE_RSP,
AVDT_SCB_HDL_GETCONFIG_CMD,
AVDT_SCB_HDL_GETCONFIG_RSP,
AVDT_SCB_HDL_OPEN_CMD,
AVDT_SCB_HDL_OPEN_REJ,
AVDT_SCB_HDL_OPEN_RSP,
AVDT_SCB_HDL_PKT,
AVDT_SCB_DROP_PKT,
AVDT_SCB_HDL_RECONFIG_CMD,
AVDT_SCB_HDL_RECONFIG_RSP,
AVDT_SCB_HDL_SECURITY_CMD,
AVDT_SCB_HDL_SECURITY_RSP,
AVDT_SCB_HDL_SETCONFIG_CMD,
AVDT_SCB_HDL_SETCONFIG_REJ,
AVDT_SCB_HDL_SETCONFIG_RSP,
AVDT_SCB_HDL_START_CMD,
AVDT_SCB_HDL_START_RSP,
AVDT_SCB_HDL_SUSPEND_CMD,
AVDT_SCB_HDL_SUSPEND_RSP,
AVDT_SCB_HDL_TC_CLOSE,
#if AVDT_REPORTING == TRUE
AVDT_SCB_HDL_TC_CLOSE_STO,
#endif
AVDT_SCB_HDL_TC_OPEN,
#if AVDT_REPORTING == TRUE
AVDT_SCB_HDL_TC_OPEN_STO,
#endif
AVDT_SCB_SND_DELAY_RPT_REQ,
AVDT_SCB_HDL_DELAY_RPT_CMD,
AVDT_SCB_HDL_DELAY_RPT_RSP,
AVDT_SCB_HDL_WRITE_REQ,
AVDT_SCB_SND_ABORT_REQ,
AVDT_SCB_SND_ABORT_RSP,
AVDT_SCB_SND_CLOSE_REQ,
AVDT_SCB_SND_STREAM_CLOSE,
AVDT_SCB_SND_CLOSE_RSP,
AVDT_SCB_SND_GETCONFIG_REQ,
AVDT_SCB_SND_GETCONFIG_RSP,
AVDT_SCB_SND_OPEN_REQ,
AVDT_SCB_SND_OPEN_RSP,
AVDT_SCB_SND_RECONFIG_REQ,
AVDT_SCB_SND_RECONFIG_RSP,
AVDT_SCB_SND_SECURITY_REQ,
AVDT_SCB_SND_SECURITY_RSP,
AVDT_SCB_SND_SETCONFIG_REQ,
AVDT_SCB_SND_SETCONFIG_REJ,
AVDT_SCB_SND_SETCONFIG_RSP,
AVDT_SCB_SND_TC_CLOSE,
AVDT_SCB_CB_ERR,
AVDT_SCB_CONG_STATE,
AVDT_SCB_REJ_STATE,
AVDT_SCB_REJ_IN_USE,
AVDT_SCB_REJ_NOT_IN_USE,
AVDT_SCB_SET_REMOVE,
AVDT_SCB_FREE_PKT,
AVDT_SCB_CLR_PKT,
AVDT_SCB_CHK_SND_PKT,
AVDT_SCB_TC_TIMER,
AVDT_SCB_CLR_VARS,
AVDT_SCB_DEALLOC,
AVDT_SCB_NUM_ACTIONS
};
#define AVDT_SCB_IGNORE AVDT_SCB_NUM_ACTIONS
/* scb state machine events */
enum {
AVDT_SCB_API_REMOVE_EVT,
AVDT_SCB_API_WRITE_REQ_EVT,
AVDT_SCB_API_GETCONFIG_REQ_EVT,
AVDT_SCB_API_DELAY_RPT_REQ_EVT,
AVDT_SCB_API_SETCONFIG_REQ_EVT,
AVDT_SCB_API_OPEN_REQ_EVT,
AVDT_SCB_API_CLOSE_REQ_EVT,
AVDT_SCB_API_RECONFIG_REQ_EVT,
AVDT_SCB_API_SECURITY_REQ_EVT,
AVDT_SCB_API_ABORT_REQ_EVT,
AVDT_SCB_API_GETCONFIG_RSP_EVT,
AVDT_SCB_API_SETCONFIG_RSP_EVT,
AVDT_SCB_API_SETCONFIG_REJ_EVT,
AVDT_SCB_API_OPEN_RSP_EVT,
AVDT_SCB_API_CLOSE_RSP_EVT,
AVDT_SCB_API_RECONFIG_RSP_EVT,
AVDT_SCB_API_SECURITY_RSP_EVT,
AVDT_SCB_API_ABORT_RSP_EVT,
AVDT_SCB_MSG_SETCONFIG_CMD_EVT,
AVDT_SCB_MSG_GETCONFIG_CMD_EVT,
AVDT_SCB_MSG_OPEN_CMD_EVT,
AVDT_SCB_MSG_START_CMD_EVT,
AVDT_SCB_MSG_SUSPEND_CMD_EVT,
AVDT_SCB_MSG_CLOSE_CMD_EVT,
AVDT_SCB_MSG_ABORT_CMD_EVT,
AVDT_SCB_MSG_RECONFIG_CMD_EVT,
AVDT_SCB_MSG_SECURITY_CMD_EVT,
AVDT_SCB_MSG_DELAY_RPT_CMD_EVT,
AVDT_SCB_MSG_DELAY_RPT_RSP_EVT,
AVDT_SCB_MSG_SETCONFIG_RSP_EVT,
AVDT_SCB_MSG_GETCONFIG_RSP_EVT,
AVDT_SCB_MSG_OPEN_RSP_EVT,
AVDT_SCB_MSG_START_RSP_EVT,
AVDT_SCB_MSG_SUSPEND_RSP_EVT,
AVDT_SCB_MSG_CLOSE_RSP_EVT,
AVDT_SCB_MSG_ABORT_RSP_EVT,
AVDT_SCB_MSG_RECONFIG_RSP_EVT,
AVDT_SCB_MSG_SECURITY_RSP_EVT,
AVDT_SCB_MSG_SETCONFIG_REJ_EVT,
AVDT_SCB_MSG_OPEN_REJ_EVT,
AVDT_SCB_MSG_START_REJ_EVT,
AVDT_SCB_MSG_SUSPEND_REJ_EVT,
AVDT_SCB_TC_TOUT_EVT,
AVDT_SCB_TC_OPEN_EVT,
AVDT_SCB_TC_CLOSE_EVT,
AVDT_SCB_TC_CONG_EVT,
AVDT_SCB_TC_DATA_EVT,
AVDT_SCB_CC_CLOSE_EVT
};
/* adaption layer number of stream routing table entries */
#if AVDT_REPORTING == TRUE
/* 2 channels(1 media, 1 report) for each SEP and one for signalling */
#define AVDT_NUM_RT_TBL ((AVDT_NUM_SEPS<<1) + 1)
#else
#define AVDT_NUM_RT_TBL (AVDT_NUM_SEPS + 1)
#endif
/* adaption layer number of transport channel table entries - moved to target.h
#define AVDT_NUM_TC_TBL (AVDT_NUM_SEPS + AVDT_NUM_LINKS) */
/* "states" used in transport channel table */
#define AVDT_AD_ST_UNUSED 0 /* Unused - unallocated */
#define AVDT_AD_ST_IDLE 1 /* No connection */
#define AVDT_AD_ST_ACP 2 /* Waiting to accept a connection */
#define AVDT_AD_ST_INT 3 /* Initiating a connection */
#define AVDT_AD_ST_CONN 4 /* Waiting for connection confirm */
#define AVDT_AD_ST_CFG 5 /* Waiting for configuration complete */
#define AVDT_AD_ST_OPEN 6 /* Channel opened */
#define AVDT_AD_ST_SEC_INT 7 /* Security process as INT */
#define AVDT_AD_ST_SEC_ACP 8 /* Security process as ACP */
/* Configuration flags. tAVDT_TC_TBL.cfg_flags */
#define AVDT_L2C_CFG_IND_DONE (1<<0)
#define AVDT_L2C_CFG_CFM_DONE (1<<1)
#define AVDT_L2C_CFG_CONN_INT (1<<2)
#define AVDT_L2C_CFG_CONN_ACP (1<<3)
/* result code for avdt_ad_write_req() (L2CA_DataWrite()) */
#define AVDT_AD_FAILED L2CAP_DW_FAILED /* FALSE */
#define AVDT_AD_SUCCESS L2CAP_DW_SUCCESS /* TRUE */
#define AVDT_AD_CONGESTED L2CAP_DW_CONGESTED /* 2 */
/*****************************************************************************
** data types
*****************************************************************************/
/* msg union of all message parameter types */
typedef union {
tAVDT_EVT_HDR hdr;
tAVDT_EVT_HDR single;
tAVDT_SETCONFIG config_cmd;
tAVDT_CONFIG reconfig_cmd;
tAVDT_MULTI multi;
tAVDT_SECURITY security_cmd;
tAVDT_DISCOVER discover_rsp;
tAVDT_CONFIG svccap;
tAVDT_SECURITY security_rsp;
tAVDT_DELAY_RPT delay_rpt_cmd;
} tAVDT_MSG;
/* data type for AVDT_CCB_API_DISCOVER_REQ_EVT */
typedef struct {
tAVDT_CTRL_CBACK *p_cback;
tAVDT_SEP_INFO *p_sep_info;
UINT8 num_seps;
} tAVDT_CCB_API_DISCOVER;
/* data type for AVDT_CCB_API_GETCAP_REQ_EVT */
typedef struct {
tAVDT_EVT_HDR single;
tAVDT_CTRL_CBACK *p_cback;
tAVDT_CFG *p_cfg;
} tAVDT_CCB_API_GETCAP;
/* data type for AVDT_CCB_API_CONNECT_REQ_EVT */
typedef struct {
tAVDT_CTRL_CBACK *p_cback;
UINT8 sec_mask;
} tAVDT_CCB_API_CONNECT;
/* data type for AVDT_CCB_API_DISCONNECT_REQ_EVT */
typedef struct {
tAVDT_CTRL_CBACK *p_cback;
} tAVDT_CCB_API_DISCONNECT;
/* union associated with ccb state machine events */
typedef union {
tAVDT_CCB_API_DISCOVER discover;
tAVDT_CCB_API_GETCAP getcap;
tAVDT_CCB_API_CONNECT connect;
tAVDT_CCB_API_DISCONNECT disconnect;
tAVDT_MSG msg;
BOOLEAN llcong;
UINT8 err_code;
} tAVDT_CCB_EVT;
/* channel control block type */
typedef struct {
BD_ADDR peer_addr; /* BD address of peer */
TIMER_LIST_ENT timer_entry; /* CCB timer list entry */
BUFFER_Q cmd_q; /* Queue for outgoing command messages */
BUFFER_Q rsp_q; /* Queue for outgoing response and reject messages */
tAVDT_CTRL_CBACK *proc_cback; /* Procedure callback function */
tAVDT_CTRL_CBACK *p_conn_cback; /* Connection/disconnection callback function */
void *p_proc_data; /* Pointer to data storage for procedure */
BT_HDR *p_curr_cmd; /* Current command being sent awaiting response */
BT_HDR *p_curr_msg; /* Current message being sent */
BT_HDR *p_rx_msg; /* Current message being received */
BOOLEAN allocated; /* Whether ccb is allocated */
UINT8 state; /* The CCB state machine state */
BOOLEAN ll_opened; /* TRUE if LL is opened */
BOOLEAN proc_busy; /* TRUE when a discover or get capabilities procedure in progress */
UINT8 proc_param; /* Procedure parameter; either SEID for get capabilities or number of SEPS for discover */
BOOLEAN cong; /* Whether signaling channel is congested */
UINT8 label; /* Message header "label" (sequence number) */
BOOLEAN reconn; /* If TRUE, reinitiate connection after transitioning from CLOSING to IDLE state */
UINT8 ret_count; /* Command retransmission count */
} tAVDT_CCB;
/* type for action functions */
typedef void (*tAVDT_CCB_ACTION)(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
/* type for AVDT_SCB_API_WRITE_REQ_EVT */
typedef struct {
BT_HDR *p_buf;
UINT32 time_stamp;
#if AVDT_MULTIPLEXING == TRUE
BUFFER_Q frag_q; /* Queue for outgoing media fragments. p_buf should be 0 */
UINT8 *p_data;
UINT32 data_len;
#endif
UINT8 m_pt;
tAVDT_DATA_OPT_MASK opt;
} tAVDT_SCB_APIWRITE;
/* type for AVDT_SCB_TC_CLOSE_EVT */
typedef struct {
UINT8 old_tc_state; /* channel state before closed */
UINT8 tcid; /* TCID */
UINT8 type; /* channel type */
} tAVDT_SCB_TC_CLOSE;
/* type for scb event data */
typedef union {
tAVDT_MSG msg;
tAVDT_SCB_APIWRITE apiwrite;
tAVDT_DELAY_RPT apidelay;
tAVDT_OPEN open;
tAVDT_SCB_TC_CLOSE close;
BOOLEAN llcong;
BT_HDR *p_pkt;
} tAVDT_SCB_EVT;
/* stream control block type */
typedef struct {
tAVDT_CS cs; /* stream creation struct */
tAVDT_CFG curr_cfg; /* current configuration */
tAVDT_CFG req_cfg; /* requested configuration */
TIMER_LIST_ENT timer_entry; /* timer entry */
BT_HDR *p_pkt; /* packet waiting to be sent */
tAVDT_CCB *p_ccb; /* ccb associated with this scb */
UINT16 media_seq; /* media packet sequence number */
BOOLEAN allocated; /* whether scb is allocated or unused */
BOOLEAN in_use; /* whether stream being used by peer */
BOOLEAN sink_activated; /* A2DP Sink activated/de-activated from Application */
UINT8 role; /* initiator/acceptor role in current procedure */
BOOLEAN remove; /* whether CB is marked for removal */
UINT8 state; /* state machine state */
UINT8 peer_seid; /* SEID of peer stream */
UINT8 curr_evt; /* current event; set only by state machine */
BOOLEAN cong; /* Whether media transport channel is congested */
UINT8 close_code; /* Error code received in close response */
#if AVDT_MULTIPLEXING == TRUE
BUFFER_Q frag_q; /* Queue for outgoing media fragments */
UINT32 frag_off; /* length of already received media fragments */
UINT32 frag_org_len; /* original length before fragmentation of receiving media packet */
UINT8 *p_next_frag; /* next fragment to send */
UINT8 *p_media_buf; /* buffer for media packet assigned by AVDT_SetMediaBuf */
UINT32 media_buf_len; /* length of buffer for media packet assigned by AVDT_SetMediaBuf */
#endif
} tAVDT_SCB;
/* type for action functions */
typedef void (*tAVDT_SCB_ACTION)(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
/* adaption layer type for transport channel table */
typedef struct {
UINT16 peer_mtu; /* L2CAP mtu of the peer device */
UINT16 my_mtu; /* Our MTU for this channel */
UINT16 my_flush_to; /* Our flush timeout for this channel */
UINT16 lcid;
UINT8 tcid; /* transport channel id */
UINT8 ccb_idx; /* channel control block associated with this tc */
UINT8 state; /* transport channel state */
UINT8 cfg_flags; /* L2CAP configuration flags */
UINT8 id;
} tAVDT_TC_TBL;
/* adaption layer type for stream routing table */
typedef struct {
UINT16 lcid; /* L2CAP LCID of the associated transport channel */
UINT8 scb_hdl; /* stream control block associated with this tc */
} tAVDT_RT_TBL;
/* adaption layer control block */
typedef struct {
tAVDT_RT_TBL rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL];
tAVDT_TC_TBL tc_tbl[AVDT_NUM_TC_TBL];
UINT8 lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */
} tAVDT_AD;
/* Control block for AVDT */
typedef struct {
tAVDT_REG rcb; /* registration control block */
tAVDT_CCB ccb[AVDT_NUM_LINKS]; /* channel control blocks */
tAVDT_SCB scb[AVDT_NUM_SEPS]; /* stream control blocks */
tAVDT_AD ad; /* adaption layer control block */
tAVDTC_CTRL_CBACK *p_conf_cback; /* conformance callback function */
tAVDT_CCB_ACTION *p_ccb_act; /* pointer to CCB action functions */
tAVDT_SCB_ACTION *p_scb_act; /* pointer to SCB action functions */
tAVDT_CTRL_CBACK *p_conn_cback; /* connection callback function */
UINT8 trace_level; /* trace level */
} tAVDT_CB;
/*****************************************************************************
** function declarations
*****************************************************************************/
/* CCB function declarations */
extern void avdt_ccb_init(void);
extern void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data);
extern tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr);
extern tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr);
extern void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb);
extern tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx);
/* CCB action functions */
extern void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
extern void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data);
/* SCB function prototypes */
extern void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_init(void);
extern tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs);
extern void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb);
extern tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl);
extern UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code);
extern void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi);
extern UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb);
/* SCB action functions */
extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_delay_rpt_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data);
extern void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq);
/* msg function declarations */
extern BOOLEAN avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg);
extern void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p_params);
extern void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
extern void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
extern void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params);
extern void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf);
/* adaption layer function declarations */
extern void avdt_ad_init(void);
extern UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb);
extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state);
extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid);
extern tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb);
extern UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl);
extern void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason);
extern void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl);
extern void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested);
extern void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf);
extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb);
extern UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf);
extern void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role);
extern void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb);
extern void avdt_process_timeout(TIMER_LIST_ENT *p_tle);
/*****************************************************************************
** macros
*****************************************************************************/
/* we store the scb and the label in the layer_specific field of the
** current cmd
*/
#define AVDT_BLD_LAYERSPEC(ls, msg, label) \
ls = (((label) << 4) | (msg))
#define AVDT_LAYERSPEC_LABEL(ls) ((UINT8)((ls) >> 4))
#define AVDT_LAYERSPEC_MSG(ls) ((UINT8)((ls) & 0x000F))
/*****************************************************************************
** global data
*****************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
/******************************************************************************
** Main Control Block
*******************************************************************************/
#if AVDT_DYNAMIC_MEMORY == FALSE
extern tAVDT_CB avdt_cb;
#else
extern tAVDT_CB *avdt_cb_ptr;
#define avdt_cb (*avdt_cb_ptr)
#endif
/* L2CAP callback registration structure */
extern const tL2CAP_APPL_INFO avdt_l2c_appl;
/* reject message event lookup table */
extern const UINT8 avdt_msg_rej_2_evt[];
#ifdef __cplusplus
}
#endif
#endif /* AVDT_INT_H */

View File

@ -21,8 +21,10 @@
* Interface to AVRCP mandatory commands * Interface to AVRCP mandatory commands
* *
******************************************************************************/ ******************************************************************************/
#include <string.h> // #include <assert.h>
#include "bt_trace.h" #include "bt_trace.h"
#include <string.h>
#include "gki.h" #include "gki.h"
#include "avrc_api.h" #include "avrc_api.h"
#include "avrc_int.h" #include "avrc_int.h"

View File

@ -21,6 +21,7 @@
#include "avrc_api.h" #include "avrc_api.h"
#include "avrc_defs.h" #include "avrc_defs.h"
#include "avrc_int.h" #include "avrc_int.h"
#include "bt_utils.h"
/***************************************************************************** /*****************************************************************************
** Global data ** Global data

View File

@ -21,8 +21,10 @@
* Interface to AVRCP optional commands * Interface to AVRCP optional commands
* *
******************************************************************************/ ******************************************************************************/
// #include <assert.h>
#include "bt_target.h"
#include <string.h> #include <string.h>
#include "bt_trace.h"
#include "gki.h" #include "gki.h"
#include "avrc_api.h" #include "avrc_api.h"
#include "avrc_int.h" #include "avrc_int.h"

View File

@ -21,6 +21,7 @@
#include "avrc_api.h" #include "avrc_api.h"
#include "avrc_defs.h" #include "avrc_defs.h"
#include "avrc_int.h" #include "avrc_int.h"
#include "bt_utils.h"
/***************************************************************************** /*****************************************************************************
** Global data ** Global data

View File

@ -26,7 +26,7 @@
#ifndef AVRC_INT_H #ifndef AVRC_INT_H
#define AVRC_INT_H #define AVRC_INT_H
//#include "avct_defs.h" #include "avct_defs.h"
#include "avrc_api.h" #include "avrc_api.h"
/* DEBUG FLAGS /* DEBUG FLAGS

View File

@ -0,0 +1,257 @@
/******************************************************************************
*
* Copyright (C) 2000-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.
*
******************************************************************************/
/******************************************************************************
*
* nterface to A2DP Application Programming Interface
*
******************************************************************************/
#ifndef A2D_API_H
#define A2D_API_H
#include "sdp_api.h"
/*****************************************************************************
** constants
*****************************************************************************/
/* Profile supported features */
#define A2D_SUPF_PLAYER 0x0001
#define A2D_SUPF_MIC 0x0002
#define A2D_SUPF_TUNER 0x0004
#define A2D_SUPF_MIXER 0x0008
#define A2D_SUPF_HEADPHONE 0x0001
#define A2D_SUPF_SPEAKER 0x0002
#define A2D_SUPF_RECORDER 0x0004
#define A2D_SUPF_AMP 0x0008
/* AV Media Types */
#define A2D_MEDIA_TYPE_AUDIO 0x00 /* audio media type + RFA */
#define A2D_MEDIA_TYPE_VIDEO 0x10 /* video media type + RFA */
#define A2D_MEDIA_TYPE_MULTI 0x20 /* multimedia media type + RFA */
/* AV Media Codec Type (Audio Codec ID) */
#define A2D_MEDIA_CT_SBC 0x00 /* SBC media codec type */
#define A2D_MEDIA_CT_M12 0x01 /* MPEG-1, 2 Audio media codec type */
#define A2D_MEDIA_CT_M24 0x02 /* MPEG-2, 4 AAC media codec type */
#define A2D_MEDIA_CT_ATRAC 0x04 /* ATRAC family media codec type */
#define A2D_SUCCESS 0 /* Success */
#define A2D_FAIL 0x0A /* Failed */
#define A2D_BUSY 0x0B /* A2D_FindService is already in progress */
#define A2D_INVALID_PARAMS 0x0C /* bad parameters */
#define A2D_WRONG_CODEC 0x0D /* wrong codec info */
#define A2D_BAD_CODEC_TYPE 0xC1 /* Media Codec Type is not valid */
#define A2D_NS_CODEC_TYPE 0xC2 /* Media Codec Type is not supported */
#define A2D_BAD_SAMP_FREQ 0xC3 /* Sampling Frequency is not valid or multiple values have been selected */
#define A2D_NS_SAMP_FREQ 0xC4 /* Sampling Frequency is not supported */
#define A2D_BAD_CH_MODE 0xC5 /* Channel Mode is not valid or multiple values have been selected */
#define A2D_NS_CH_MODE 0xC6 /* Channel Mode is not supported */
#define A2D_BAD_SUBBANDS 0xC7 /* None or multiple values have been selected for Number of Subbands */
#define A2D_NS_SUBBANDS 0xC8 /* Number of Subbands is not supported */
#define A2D_BAD_ALLOC_MTHD 0xC9 /* None or multiple values have been selected for Allocation Method */
#define A2D_NS_ALLOC_MTHD 0xCA /* Allocation Method is not supported */
#define A2D_BAD_MIN_BITPOOL 0xCB /* Minimum Bitpool Value is not valid */
#define A2D_NS_MIN_BITPOOL 0xCC /* Minimum Bitpool Value is not supported */
#define A2D_BAD_MAX_BITPOOL 0xCD /* Maximum Bitpool Value is not valid */
#define A2D_NS_MAX_BITPOOL 0xCE /* Maximum Bitpool Value is not supported */
#define A2D_BAD_LAYER 0xCF /* None or multiple values have been selected for Layer */
#define A2D_NS_LAYER 0xD0 /* Layer is not supported */
#define A2D_NS_CRC 0xD1 /* CRC is not supported */
#define A2D_NS_MPF 0xD2 /* MPF-2 is not supported */
#define A2D_NS_VBR 0xD3 /* VBR is not supported */
#define A2D_BAD_BIT_RATE 0xD4 /* None or multiple values have been selected for Bit Rate */
#define A2D_NS_BIT_RATE 0xD5 /* Bit Rate is not supported */
#define A2D_BAD_OBJ_TYPE 0xD6 /* Either 1) Object type is not valid (b3-b0) or 2) None or multiple values have been selected for Object Type */
#define A2D_NS_OBJ_TYPE 0xD7 /* Object type is not supported */
#define A2D_BAD_CHANNEL 0xD8 /* None or multiple values have been selected for Channels */
#define A2D_NS_CHANNEL 0xD9 /* Channels is not supported */
#define A2D_BAD_BLOCK_LEN 0xDD /* None or multiple values have been selected for Block Length */
#define A2D_BAD_CP_TYPE 0xE0 /* The requested CP Type is not supported. */
#define A2D_BAD_CP_FORMAT 0xE1 /* The format of Content Protection Service Capability/Content Protection Scheme Dependent Data is not correct. */
typedef UINT8 tA2D_STATUS;
/* the return values from A2D_BitsSet() */
#define A2D_SET_ONE_BIT 1 /* one and only one bit is set */
#define A2D_SET_ZERO_BIT 0 /* all bits clear */
#define A2D_SET_MULTL_BIT 2 /* multiple bits are set */
/*****************************************************************************
** type definitions
*****************************************************************************/
/* This data type is used in A2D_FindService() to initialize the SDP database
* to hold the result service search. */
typedef struct
{
UINT32 db_len; /* Length, in bytes, of the discovery database */
UINT16 num_attr;/* The number of attributes in p_attrs */
tSDP_DISCOVERY_DB *p_db; /* Pointer to the discovery database */
UINT16 *p_attrs; /* The attributes filter. If NULL, A2DP API sets the attribute filter
* to be ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_BT_PROFILE_DESC_LIST,
* ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and ATTR_ID_PROVIDER_NAME.
* If not NULL, the input is taken as the filter. */
} tA2D_SDP_DB_PARAMS;
/* This data type is used in tA2D_FIND_CBACK to report the result of the SDP discovery process. */
typedef struct
{
UINT16 service_len; /* Length, in bytes, of the service name */
UINT16 provider_len; /* Length, in bytes, of the provider name */
char * p_service_name; /* Pointer the service name. This character string may not be null terminated.
* Use the service_len parameter to safely copy this string */
char * p_provider_name;/* Pointer the provider name. This character string may not be null terminated.
* Use the provider_len parameter to safely copy this string */
UINT16 features; /* Profile supported features */
UINT16 avdt_version; /* AVDTP protocol version */
} tA2D_Service;
/* This is the callback to notify the result of the SDP discovery process. */
typedef void (tA2D_FIND_CBACK)(BOOLEAN found, tA2D_Service * p_service);
/*****************************************************************************
** external function declarations
*****************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
/******************************************************************************
**
** Function A2D_AddRecord
**
** Description This function is called by a server application to add
** SRC or SNK information to an SDP record. Prior to
** calling this function the application must call
** SDP_CreateRecord() to create an SDP record.
**
** Input Parameters:
** service_uuid: Indicates SRC or SNK.
**
** p_service_name: Pointer to a null-terminated character
** string containing the service name.
**
** p_provider_name: Pointer to a null-terminated character
** string containing the provider name.
**
** features: Profile supported features.
**
** sdp_handle: SDP handle returned by SDP_CreateRecord().
**
** Output Parameters:
** None.
**
** Returns A2D_SUCCESS if function execution succeeded,
** A2D_INVALID_PARAMS if bad parameters are given.
** A2D_FAIL if function execution failed.
**
******************************************************************************/
extern tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name,
UINT16 features, UINT32 sdp_handle);
/******************************************************************************
**
** Function A2D_FindService
**
** Description This function is called by a client application to
** perform service discovery and retrieve SRC or SNK SDP
** record information from a server. Information is
** returned for the first service record found on the
** server that matches the service UUID. The callback
** function will be executed when service discovery is
** complete. There can only be one outstanding call to
** A2D_FindService() at a time; the application must wait
** for the callback before it makes another call to
** the function.
**
** Input Parameters:
** service_uuid: Indicates SRC or SNK.
**
** bd_addr: BD address of the peer device.
**
** p_db: Pointer to the information to initialize
** the discovery database.
**
** p_cback: Pointer to the A2D_FindService()
** callback function.
**
** Output Parameters:
** None.
**
** Returns A2D_SUCCESS if function execution succeeded,
** A2D_INVALID_PARAMS if bad parameters are given.
** A2D_BUSY if discovery is already in progress.
** A2D_FAIL if function execution failed.
**
******************************************************************************/
extern tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr,
tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback);
/******************************************************************************
**
** Function A2D_SetTraceLevel
**
** Description Sets the trace level for A2D. If 0xff is passed, the
** current trace level is returned.
**
** Input Parameters:
** new_level: The level to set the A2D tracing to:
** 0xff-returns the current setting.
** 0-turns off tracing.
** >= 1-Errors.
** >= 2-Warnings.
** >= 3-APIs.
** >= 4-Events.
** >= 5-Debug.
**
** Returns The new trace level or current trace level if
** the input parameter is 0xff.
**
******************************************************************************/
extern UINT8 A2D_SetTraceLevel (UINT8 new_level);
/******************************************************************************
** Function A2D_BitsSet
**
** Description Check the given num for the number of bits set
** Returns A2D_SET_ONE_BIT, if one and only one bit is set
** A2D_SET_ZERO_BIT, if all bits clear
** A2D_SET_MULTL_BIT, if multiple bits are set
******************************************************************************/
extern UINT8 A2D_BitsSet(UINT8 num);
#ifdef __cplusplus
}
#endif
/*******************************************************************************
**
** Function A2D_Init
**
** Description This function is called at stack startup to allocate the
** control block (if using dynamic memory), and initializes the
** control block and tracing level.
**
** Returns void
**
*******************************************************************************/
extern void A2D_Init(void);
#endif /* A2D_API_H */

View File

@ -0,0 +1,212 @@
/******************************************************************************
*
* Copyright (C) 2000-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.
*
******************************************************************************/
/******************************************************************************
*
* nterface to low complexity subband codec (SBC)
*
******************************************************************************/
#ifndef A2D_SBC_H
#define A2D_SBC_H
/*****************************************************************************
** Constants
*****************************************************************************/
/* the length of the SBC Media Payload header. */
#define A2D_SBC_MPL_HDR_LEN 1
/* the LOSC of SBC media codec capabilitiy */
#define A2D_SBC_INFO_LEN 6
/* for Codec Specific Information Element */
#define A2D_SBC_IE_SAMP_FREQ_MSK 0xF0 /* b7-b4 sampling frequency */
#define A2D_SBC_IE_SAMP_FREQ_16 0x80 /* b7:16 kHz */
#define A2D_SBC_IE_SAMP_FREQ_32 0x40 /* b6:32 kHz */
#define A2D_SBC_IE_SAMP_FREQ_44 0x20 /* b5:44.1kHz */
#define A2D_SBC_IE_SAMP_FREQ_48 0x10 /* b4:48 kHz */
#define A2D_SBC_IE_CH_MD_MSK 0x0F /* b3-b0 channel mode */
#define A2D_SBC_IE_CH_MD_MONO 0x08 /* b3: mono */
#define A2D_SBC_IE_CH_MD_DUAL 0x04 /* b2: dual */
#define A2D_SBC_IE_CH_MD_STEREO 0x02 /* b1: stereo */
#define A2D_SBC_IE_CH_MD_JOINT 0x01 /* b0: joint stereo */
#define A2D_SBC_IE_BLOCKS_MSK 0xF0 /* b7-b4 number of blocks */
#define A2D_SBC_IE_BLOCKS_4 0x80 /* 4 blocks */
#define A2D_SBC_IE_BLOCKS_8 0x40 /* 8 blocks */
#define A2D_SBC_IE_BLOCKS_12 0x20 /* 12blocks */
#define A2D_SBC_IE_BLOCKS_16 0x10 /* 16blocks */
#define A2D_SBC_IE_SUBBAND_MSK 0x0C /* b3-b2 number of subbands */
#define A2D_SBC_IE_SUBBAND_4 0x08 /* b3: 4 */
#define A2D_SBC_IE_SUBBAND_8 0x04 /* b2: 8 */
#define A2D_SBC_IE_ALLOC_MD_MSK 0x03 /* b1-b0 allocation mode */
#define A2D_SBC_IE_ALLOC_MD_S 0x02 /* b1: SNR */
#define A2D_SBC_IE_ALLOC_MD_L 0x01 /* b0: loundess */
#define A2D_SBC_IE_MIN_BITPOOL 2
#define A2D_SBC_IE_MAX_BITPOOL 250
/* for media payload header */
#define A2D_SBC_HDR_F_MSK 0x80
#define A2D_SBC_HDR_S_MSK 0x40
#define A2D_SBC_HDR_L_MSK 0x20
#define A2D_SBC_HDR_NUM_MSK 0x0F
/*****************************************************************************
** Type Definitions
*****************************************************************************/
/* data type for the SBC Codec Information Element*/
typedef struct
{
UINT8 samp_freq; /* Sampling frequency */
UINT8 ch_mode; /* Channel mode */
UINT8 block_len; /* Block length */
UINT8 num_subbands; /* Number of subbands */
UINT8 alloc_mthd; /* Allocation method */
UINT8 max_bitpool; /* Maximum bitpool */
UINT8 min_bitpool; /* Minimum bitpool */
} tA2D_SBC_CIE;
/*****************************************************************************
** External Function Declarations
*****************************************************************************/
#ifdef __cplusplus
extern "C"
{
#endif
/******************************************************************************
**
** Function A2D_SbcChkFrInit
**
** Description check if need to init the descramble control block.
**
** Returns nothing.
******************************************************************************/
extern void A2D_SbcChkFrInit(UINT8 *p_pkt);
/******************************************************************************
**
** Function A2D_SbcDescramble
**
** Description descramble the packet.
**
** Returns nothing.
******************************************************************************/
extern void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len);
/******************************************************************************
**
** Function A2D_BldSbcInfo
**
** Description This function is called by an application to build
** the SBC Media Codec Capabilities byte sequence
** beginning from the LOSC octet.
** Input Parameters:
** media_type: Indicates Audio, or Multimedia.
**
** p_ie: The SBC Codec Information Element information.
**
** Output Parameters:
** p_result: the resulting codec info byte sequence.
**
** Returns A2D_SUCCESS if function execution succeeded.
** Error status code, otherwise.
******************************************************************************/
extern tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie,
UINT8 *p_result);
/******************************************************************************
**
** Function A2D_ParsSbcInfo
**
** Description This function is called by an application to parse
** the SBC Media Codec Capabilities byte sequence
** beginning from the LOSC octet.
** Input Parameters:
** p_info: the byte sequence to parse.
**
** for_caps: TRUE, if the byte sequence is for get capabilities response.
**
** Output Parameters:
** p_ie: The SBC Codec Information Element information.
**
** Returns A2D_SUCCESS if function execution succeeded.
** Error status code, otherwise.
******************************************************************************/
extern tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info,
BOOLEAN for_caps);
/******************************************************************************
**
** Function A2D_BldSbcMplHdr
**
** Description This function is called by an application to parse
** the SBC Media Payload header.
** Input Parameters:
** frag: 1, if fragmented. 0, otherwise.
**
** start: 1, if the starting packet of a fragmented frame.
**
** last: 1, if the last packet of a fragmented frame.
**
** num: If frag is 1, this is the number of remaining fragments
** (including this fragment) of this frame.
** If frag is 0, this is the number of frames in this packet.
**
** Output Parameters:
** p_dst: the resulting media payload header byte sequence.
**
** Returns void.
******************************************************************************/
extern void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start,
BOOLEAN last, UINT8 num);
/******************************************************************************
**
** Function A2D_ParsSbcMplHdr
**
** Description This function is called by an application to parse
** the SBC Media Payload header.
** Input Parameters:
** p_src: the byte sequence to parse..
**
** Output Parameters:
** frag: 1, if fragmented. 0, otherwise.
**
** start: 1, if the starting packet of a fragmented frame.
**
** last: 1, if the last packet of a fragmented frame.
**
** num: If frag is 1, this is the number of remaining fragments
** (including this fragment) of this frame.
** If frag is 0, this is the number of frames in this packet.
**
** Returns void.
******************************************************************************/
extern void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag,
BOOLEAN *p_start, BOOLEAN *p_last,
UINT8 *p_num);
#ifdef __cplusplus
}
#endif
#endif /* A2D_SBC_H */

View File

@ -0,0 +1,46 @@
/******************************************************************************
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef BT_UTILS_H
#define BT_UTILS_H
// static const char BT_UTILS_MODULE[] = "bt_utils_module";
/*******************************************************************************
** Type definitions
********************************************************************************/
typedef enum {
TASK_HIGH_MEDIA = 0,
TASK_HIGH_GKI_TIMER,
TASK_HIGH_BTU,
TASK_HIGH_HCI_WORKER,
TASK_HIGH_USERIAL_READ,
TASK_UIPC_READ,
TASK_JAVA_ALARM,
TASK_HIGH_MAX
} tHIGH_PRIORITY_TASK;
/*******************************************************************************
** Functions
********************************************************************************/
// void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task);
// void adjust_priority_a2dp(int start);
#define UNUSED(x) (void)(x)
#endif /* BT_UTILS_H */

View File

@ -9,10 +9,10 @@ COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \
bluedroid/gki/include \ bluedroid/gki/include \
bluedroid/hci/include \ bluedroid/hci/include \
bluedroid/osi/include \ bluedroid/osi/include \
bluedroid/utils/include \
bluedroid/profiles/core/include \ bluedroid/profiles/core/include \
bluedroid/profiles/esp/blufi/include \ bluedroid/profiles/esp/blufi/include \
bluedroid/profiles/esp/include \ bluedroid/profiles/esp/include \
bluedroid/profiles/std/avrc/include \
bluedroid/profiles/std/battery/include \ bluedroid/profiles/std/battery/include \
bluedroid/profiles/std/dis/include \ bluedroid/profiles/std/dis/include \
bluedroid/profiles/std/hid/include \ bluedroid/profiles/std/hid/include \
@ -26,6 +26,10 @@ COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \
bluedroid/stack/l2cap/include \ bluedroid/stack/l2cap/include \
bluedroid/stack/sdp/include \ bluedroid/stack/sdp/include \
bluedroid/stack/smp/include \ bluedroid/stack/smp/include \
bluedroid/stack/avct/include \
bluedroid/stack/avrc/include \
bluedroid/stack/avdt/include \
bluedroid/stack/a2dp/include \
bluedroid/stack/include \ bluedroid/stack/include \
bluedroid/stack_api/include \ bluedroid/stack_api/include \
bluedroid/include \ bluedroid/include \
@ -57,7 +61,6 @@ COMPONENT_SRCDIRS := bluedroid/bta/dm \
bluedroid/profiles/esp/ble_button \ bluedroid/profiles/esp/ble_button \
bluedroid/profiles/esp/wechat_AirSync \ bluedroid/profiles/esp/wechat_AirSync \
bluedroid/profiles/esp \ bluedroid/profiles/esp \
bluedroid/profiles/std/avrc \
bluedroid/profiles/std/battery \ bluedroid/profiles/std/battery \
bluedroid/profiles/std/dis \ bluedroid/profiles/std/dis \
bluedroid/profiles/std/hid \ bluedroid/profiles/std/hid \
@ -76,6 +79,10 @@ COMPONENT_SRCDIRS := bluedroid/bta/dm \
bluedroid/stack/l2cap \ bluedroid/stack/l2cap \
bluedroid/stack/sdp \ bluedroid/stack/sdp \
bluedroid/stack/smp \ bluedroid/stack/smp \
bluedroid/stack/avct \
bluedroid/stack/avrc \
bluedroid/stack/avdt \
bluedroid/stack/a2dp \
bluedroid/stack \ bluedroid/stack \
bluedroid/stack_api \ bluedroid/stack_api \
bluedroid \ bluedroid \