Home | History | Annotate | Download | only in avdt
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2002-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 /******************************************************************************
     20  *
     21  *  This module contains the AVDTP adaption layer.
     22  *
     23  ******************************************************************************/
     24 
     25 #include <assert.h>
     26 #include <string.h>
     27 
     28 #include "bt_types.h"
     29 #include "bt_target.h"
     30 #include "bt_utils.h"
     31 #include "avdt_api.h"
     32 #include "avdtc_api.h"
     33 #include "avdt_int.h"
     34 #include "l2c_api.h"
     35 #include "l2cdefs.h"
     36 
     37 
     38 /*******************************************************************************
     39 **
     40 ** Function         avdt_ad_type_to_tcid
     41 **
     42 ** Description      Derives the TCID from the channel type and SCB.
     43 **
     44 **
     45 ** Returns          TCID value.
     46 **
     47 *******************************************************************************/
     48 UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb)
     49 {
     50     UINT8 scb_idx;
     51 
     52     if (type == AVDT_CHAN_SIG)
     53     {
     54         return 0;
     55     }
     56     else
     57     {
     58         scb_idx = avdt_scb_to_hdl(p_scb) - 1;
     59         /*
     60         AVDT_TRACE_DEBUG("type: %d, tcid: %d", type, ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type));
     61         */
     62         return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type);
     63     }
     64 }
     65 
     66 /*******************************************************************************
     67 **
     68 ** Function         avdt_ad_tcid_to_type
     69 **
     70 ** Description      Derives the channel type from the TCID.
     71 **
     72 **
     73 ** Returns          Channel type value.
     74 **
     75 *******************************************************************************/
     76 static UINT8 avdt_ad_tcid_to_type(UINT8 tcid)
     77 {
     78     UINT8 type;
     79 
     80     if (tcid == 0)
     81     {
     82         type = AVDT_CHAN_SIG;
     83     }
     84     else
     85     {
     86         /* tcid translates to type based on number of channels, as follows:
     87         ** only media channel   :  tcid=1,2,3,4,5,6...  type=1,1,1,1,1,1...
     88         ** media and report     :  tcid=1,2,3,4,5,6...  type=1,2,1,2,1,2...
     89         ** media, report, recov :  tcid=1,2,3,4,5,6...  type=1,2,3,1,2,3...
     90         */
     91         type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
     92     }
     93     AVDT_TRACE_DEBUG("tcid: %d, type: %d", tcid, type);
     94     return type;
     95 }
     96 
     97 
     98 /*******************************************************************************
     99 **
    100 ** Function         avdt_ad_init
    101 **
    102 ** Description      Initialize adaption layer.
    103 **
    104 **
    105 ** Returns          Nothing.
    106 **
    107 *******************************************************************************/
    108 void avdt_ad_init(void)
    109 {
    110     int             i;
    111     tAVDT_TC_TBL    *p_tbl = avdt_cb.ad.tc_tbl;
    112     memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD));
    113 
    114     /* make sure the peer_mtu is a valid value */
    115     for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
    116     {
    117         p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    118     }
    119 }
    120 
    121 
    122 /*******************************************************************************
    123 **
    124 ** Function         avdt_ad_tc_tbl_by_st
    125 **
    126 ** Description      Find adaption layer transport channel table entry matching
    127 **                  the given state.
    128 **
    129 **
    130 ** Returns          Pointer to matching entry.  For control channel it returns
    131 **                  the matching entry.  For media or other it returns the
    132 **                  first matching entry (there could be more than one).
    133 **
    134 *******************************************************************************/
    135 tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state)
    136 {
    137     int             i;
    138     tAVDT_TC_TBL    *p_tbl = avdt_cb.ad.tc_tbl;
    139     UINT8           ccb_idx;
    140 
    141     if (p_ccb == NULL)
    142     {
    143         /* resending security req */
    144         for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
    145         {
    146             /* must be AVDT_CHAN_SIG - tcid always zero */
    147             if ((p_tbl->tcid == 0) &&
    148                 (p_tbl->state == state))
    149             {
    150                 break;
    151             }
    152         }
    153     }
    154     else
    155     {
    156         ccb_idx = avdt_ccb_to_idx(p_ccb);
    157 
    158         for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
    159         {
    160             if (type == AVDT_CHAN_SIG)
    161             {
    162                 /* if control channel, tcid always zero */
    163                 if ((p_tbl->tcid == 0) &&
    164                     (p_tbl->ccb_idx == ccb_idx) &&
    165                     (p_tbl->state == state))
    166                 {
    167                     break;
    168                 }
    169             }
    170             else
    171             {
    172                 /* if other channel, tcid is always > zero */
    173                 if ((p_tbl->tcid > 0) &&
    174                     (p_tbl->ccb_idx == ccb_idx) &&
    175                     (p_tbl->state == state))
    176                 {
    177                     break;
    178                 }
    179             }
    180         }
    181     }
    182 
    183     /* if nothing found return null */
    184     if (i == AVDT_NUM_TC_TBL)
    185     {
    186         p_tbl = NULL;
    187     }
    188 
    189     return p_tbl;
    190 }
    191 
    192 
    193 /*******************************************************************************
    194 **
    195 ** Function         avdt_ad_tc_tbl_by_lcid
    196 **
    197 ** Description      Find adaption layer transport channel table entry by LCID.
    198 **
    199 **
    200 ** Returns          Pointer to entry.
    201 **
    202 *******************************************************************************/
    203 tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid)
    204 {
    205     UINT8 idx;
    206 
    207     idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
    208 
    209     if (idx < AVDT_NUM_TC_TBL)
    210     {
    211         return &avdt_cb.ad.tc_tbl[idx];
    212     }
    213     else
    214     {
    215         return NULL;
    216     }
    217 }
    218 
    219 
    220 /*******************************************************************************
    221 **
    222 ** Function         avdt_ad_tc_tbl_by_type
    223 **
    224 ** Description      This function retrieves the transport channel table entry
    225 **                  for a particular channel.
    226 **
    227 **
    228 ** Returns          Pointer to transport channel table entry.
    229 **
    230 *******************************************************************************/
    231 tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
    232 {
    233     UINT8           tcid;
    234     int             i;
    235     tAVDT_TC_TBL    *p_tbl = avdt_cb.ad.tc_tbl;
    236     UINT8           ccb_idx = avdt_ccb_to_idx(p_ccb);
    237 
    238     /* get tcid from type, scb */
    239     tcid = avdt_ad_type_to_tcid(type, p_scb);
    240 
    241     for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
    242     {
    243         if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx))
    244         {
    245             break;
    246         }
    247     }
    248 
    249     assert(i != AVDT_NUM_TC_TBL);
    250 
    251     return p_tbl;
    252 }
    253 
    254 
    255 /*******************************************************************************
    256 **
    257 ** Function         avdt_ad_tc_tbl_alloc
    258 **
    259 ** Description      Allocate an entry in the traffic channel table.
    260 **
    261 **
    262 ** Returns          Pointer to entry.
    263 **
    264 *******************************************************************************/
    265 tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb)
    266 {
    267     int             i;
    268     tAVDT_TC_TBL    *p_tbl = avdt_cb.ad.tc_tbl;
    269 
    270     /* find next free entry in tc table */
    271     for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++)
    272     {
    273         if (p_tbl->state == AVDT_AD_ST_UNUSED)
    274         {
    275             break;
    276         }
    277     }
    278 
    279     /* sanity check */
    280     assert(i != AVDT_NUM_TC_TBL);
    281 
    282 
    283     /* initialize entry */
    284     p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    285     p_tbl->cfg_flags = 0;
    286     p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb);
    287     p_tbl->state = AVDT_AD_ST_IDLE;
    288     return p_tbl;
    289 
    290 }
    291 
    292 /*******************************************************************************
    293 **
    294 ** Function         avdt_ad_tc_tbl_to_idx
    295 **
    296 ** Description      Convert a transport channel table entry to an index.
    297 **
    298 **
    299 ** Returns          Index value.
    300 **
    301 *******************************************************************************/
    302 UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl)
    303 {
    304     AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdt_cb.ad.tc_tbl));
    305     /* use array arithmetic to determine index */
    306     return (UINT8) (p_tbl - avdt_cb.ad.tc_tbl);
    307 }
    308 
    309 /*******************************************************************************
    310 **
    311 ** Function         avdt_ad_tc_close_ind
    312 **
    313 ** Description      This function is called by the L2CAP interface when the
    314 **                  L2CAP channel is closed.  It looks up the CCB or SCB for
    315 **                  the channel and sends it a close event.  The reason
    316 **                  parameter is the same value passed by the L2CAP
    317 **                  callback function.
    318 **
    319 **
    320 ** Returns          Nothing.
    321 **
    322 *******************************************************************************/
    323 void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason)
    324 {
    325     tAVDT_CCB   *p_ccb;
    326     tAVDT_SCB   *p_scb;
    327     tAVDT_SCB_TC_CLOSE  close;
    328     UNUSED(reason);
    329 
    330     close.old_tc_state = p_tbl->state;
    331     /* clear avdt_ad_tc_tbl entry */
    332     p_tbl->state = AVDT_AD_ST_UNUSED;
    333     p_tbl->cfg_flags = 0;
    334     p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    335 
    336     AVDT_TRACE_DEBUG("avdt_ad_tc_close_ind tcid: %d, old: %d",
    337         p_tbl->tcid, close.old_tc_state);
    338     /* if signaling channel, notify ccb that channel open */
    339     if (p_tbl->tcid == 0)
    340     {
    341         p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
    342         avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
    343     }
    344     /* if media or other channel, notify scb that channel close */
    345     else
    346     {
    347         /* look up scb in stream routing table by ccb, tcid */
    348         p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
    349         if (p_scb != NULL)
    350         {
    351             close.tcid = p_tbl->tcid;
    352             close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
    353             avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, (tAVDT_SCB_EVT *)&close);
    354         }
    355     }
    356 }
    357 
    358 /*******************************************************************************
    359 **
    360 ** Function         avdt_ad_tc_open_ind
    361 **
    362 ** Description      This function is called by the L2CAP interface when
    363 **                  the L2CAP channel is opened.  It looks up the CCB or SCB
    364 **                  for the channel and sends it an open event.
    365 **
    366 **
    367 ** Returns          Nothing.
    368 **
    369 *******************************************************************************/
    370 void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl)
    371 {
    372     tAVDT_CCB   *p_ccb;
    373     tAVDT_SCB   *p_scb;
    374     tAVDT_OPEN  open;
    375     tAVDT_EVT_HDR evt;
    376 
    377     p_tbl->state = AVDT_AD_ST_OPEN;
    378 
    379     /* if signaling channel, notify ccb that channel open */
    380     if (p_tbl->tcid == 0)
    381     {
    382         /* set the signal channel to use high priority within the ACL link */
    383         L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid, L2CAP_CHNL_PRIORITY_HIGH);
    384 
    385         p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
    386         /* use err_param to indicate the role of connection.
    387          * AVDT_ACP, if ACP */
    388         evt.err_param = AVDT_INT;
    389         if(p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP)
    390         {
    391             evt.err_param = AVDT_ACP;
    392         }
    393         avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, (tAVDT_CCB_EVT *)&evt);
    394     }
    395     /* if media or other channel, notify scb that channel open */
    396     else
    397     {
    398         /* look up scb in stream routing table by ccb, tcid */
    399         p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
    400 
    401         /* put lcid in event data */
    402         if (p_scb != NULL)
    403         {
    404             open.peer_mtu = p_tbl->peer_mtu;
    405             open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
    406             open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
    407             avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, (tAVDT_SCB_EVT *) &open);
    408         }
    409     }
    410 }
    411 
    412 
    413 /*******************************************************************************
    414 **
    415 ** Function         avdt_ad_tc_cong_ind
    416 **
    417 ** Description      This function is called by the L2CAP interface layer when
    418 **                  L2CAP calls the congestion callback.  It looks up the CCB
    419 **                  or SCB for the channel and sends it a congestion event.
    420 **                  The is_congested parameter is the same value passed by
    421 **                  the L2CAP callback function.
    422 **
    423 **
    424 ** Returns          Nothing.
    425 **
    426 *******************************************************************************/
    427 void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested)
    428 {
    429     tAVDT_CCB   *p_ccb;
    430     tAVDT_SCB   *p_scb;
    431 
    432     /* if signaling channel, notify ccb of congestion */
    433     if (p_tbl->tcid == 0)
    434     {
    435         p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
    436         avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, (tAVDT_CCB_EVT *) &is_congested);
    437     }
    438     /* if media or other channel, notify scb that channel open */
    439     else
    440     {
    441         /* look up scb in stream routing table by ccb, tcid */
    442         p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
    443         if (p_scb != NULL)
    444         {
    445             avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, (tAVDT_SCB_EVT *) &is_congested);
    446         }
    447     }
    448 }
    449 
    450 
    451 /*******************************************************************************
    452 **
    453 ** Function         avdt_ad_tc_data_ind
    454 **
    455 ** Description      This function is called by the L2CAP interface layer when
    456 **                  incoming data is received from L2CAP.  It looks up the CCB
    457 **                  or SCB for the channel and routes the data accordingly.
    458 **
    459 **
    460 ** Returns          Nothing.
    461 **
    462 *******************************************************************************/
    463 void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf)
    464 {
    465     tAVDT_CCB   *p_ccb;
    466     tAVDT_SCB   *p_scb;
    467 
    468     /* store type (media, recovery, reporting) */
    469     p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
    470 
    471 
    472     /* if signaling channel, handle control message */
    473     if (p_tbl->tcid == 0)
    474     {
    475         p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
    476         avdt_msg_ind(p_ccb, p_buf);
    477     }
    478     /* if media or other channel, send event to scb */
    479     else
    480     {
    481         p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
    482         if (p_scb != NULL)
    483         {
    484             avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT *) &p_buf);
    485         }
    486         else
    487         {
    488             GKI_freebuf(p_buf);
    489             AVDT_TRACE_ERROR(" avdt_ad_tc_data_ind buffer freed");
    490         }
    491     }
    492 }
    493 
    494 /*******************************************************************************
    495 **
    496 ** Function         avdt_ad_write_req
    497 **
    498 ** Description      This function is called by a CCB or SCB to send data to a
    499 **                  transport channel.  It looks up the LCID of the channel
    500 **                  based on the type, CCB, and SCB (if present).  Then it
    501 **                  passes the data to L2CA_DataWrite().
    502 **
    503 **
    504 ** Returns          AVDT_AD_SUCCESS, if data accepted, else FALSE
    505 **                  AVDT_AD_CONGESTED, if data accepted and the channel is congested
    506 **                  AVDT_AD_FAILED, if error
    507 **
    508 *******************************************************************************/
    509 UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
    510 {
    511     UINT8   tcid;
    512 
    513     /* get tcid from type, scb */
    514     tcid = avdt_ad_type_to_tcid(type, p_scb);
    515 
    516 
    517     return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
    518 }
    519 
    520 
    521 /*******************************************************************************
    522 **
    523 ** Function         avdt_ad_open_req
    524 **
    525 ** Description      This function is called by a CCB or SCB to open a transport
    526 **                  channel.  This function allocates and initializes a
    527 **                  transport channel table entry.  The channel can be opened
    528 **                  in two roles:  as an initiator or acceptor.  When opened
    529 **                  as an initiator the function will start an L2CAP connection.
    530 **                  When opened as an acceptor the function simply configures
    531 **                  the table entry to listen for an incoming channel.
    532 **
    533 **
    534 ** Returns          Nothing.
    535 **
    536 *******************************************************************************/
    537 void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role)
    538 {
    539     tAVDT_TC_TBL    *p_tbl;
    540     UINT16          lcid;
    541 
    542     if((p_tbl = avdt_ad_tc_tbl_alloc(p_ccb)) == NULL)
    543     {
    544         AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl");
    545         return;
    546     }
    547 
    548 
    549     p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
    550     AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d",
    551         type, role, p_tbl->tcid);
    552 
    553     if (type == AVDT_CHAN_SIG)
    554     {
    555         /* if signaling, get mtu from registration control block */
    556         p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
    557         p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
    558     }
    559     else
    560     {
    561         /* otherwise get mtu from scb */
    562         p_tbl->my_mtu = p_scb->cs.mtu;
    563         p_tbl->my_flush_to = p_scb->cs.flush_to;
    564 
    565         /* also set scb_hdl in rt_tbl */
    566         avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = avdt_scb_to_hdl(p_scb);
    567         AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d",
    568             avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
    569             avdt_scb_to_hdl(p_scb));
    570     }
    571 
    572     /* if we're acceptor, we're done; just sit back and listen */
    573     if (role == AVDT_ACP)
    574     {
    575         p_tbl->state = AVDT_AD_ST_ACP;
    576     }
    577     /* else we're inititator, start the L2CAP connection */
    578     else
    579     {
    580         p_tbl->state = AVDT_AD_ST_CONN;
    581 
    582         /* call l2cap connect req */
    583         if ((lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr)) != 0)
    584         {
    585             /* if connect req ok, store tcid in lcid table  */
    586             avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
    587             AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d",
    588                 (lcid - L2CAP_BASE_APPL_CID), avdt_ad_tc_tbl_to_idx(p_tbl));
    589 
    590             avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
    591             AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
    592                 avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
    593                 lcid);
    594         }
    595         else
    596         {
    597             /* if connect req failed, call avdt_ad_tc_close_ind() */
    598             avdt_ad_tc_close_ind(p_tbl, 0);
    599         }
    600     }
    601 }
    602 
    603 /*******************************************************************************
    604 **
    605 ** Function         avdt_ad_close_req
    606 **
    607 ** Description      This function is called by a CCB or SCB to close a
    608 **                  transport channel.  The function looks up the LCID for the
    609 **                  channel and calls L2CA_DisconnectReq().
    610 **
    611 **
    612 ** Returns          Nothing.
    613 **
    614 *******************************************************************************/
    615 void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
    616 {
    617     UINT8           tcid;
    618     tAVDT_TC_TBL    *p_tbl;
    619 
    620     p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
    621     AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d", p_tbl->state);
    622 
    623     switch(p_tbl->state)
    624     {
    625     case AVDT_AD_ST_UNUSED:
    626         /* probably for reporting */
    627         break;
    628     case AVDT_AD_ST_ACP:
    629         /* if we're listening on this channel, send ourselves a close ind */
    630         avdt_ad_tc_close_ind(p_tbl, 0);
    631         break;
    632     default:
    633         /* get tcid from type, scb */
    634         tcid = avdt_ad_type_to_tcid(type, p_scb);
    635 
    636         /* call l2cap disconnect req */
    637         L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
    638     }
    639 }
    640 
    641