• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *******************************************************************************/
avdt_ad_type_to_tcid(UINT8 type,tAVDT_SCB * p_scb)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 *******************************************************************************/
avdt_ad_tcid_to_type(UINT8 tcid)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 *******************************************************************************/
avdt_ad_init(void)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 *******************************************************************************/
avdt_ad_tc_tbl_by_st(UINT8 type,tAVDT_CCB * p_ccb,UINT8 state)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 *******************************************************************************/
avdt_ad_tc_tbl_by_lcid(UINT16 lcid)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 *******************************************************************************/
avdt_ad_tc_tbl_by_type(UINT8 type,tAVDT_CCB * p_ccb,tAVDT_SCB * p_scb)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 *******************************************************************************/
avdt_ad_tc_tbl_alloc(tAVDT_CCB * p_ccb)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 *******************************************************************************/
avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL * p_tbl)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 *******************************************************************************/
avdt_ad_tc_close_ind(tAVDT_TC_TBL * p_tbl,UINT16 reason)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 *******************************************************************************/
avdt_ad_tc_open_ind(tAVDT_TC_TBL * p_tbl)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 *******************************************************************************/
avdt_ad_tc_cong_ind(tAVDT_TC_TBL * p_tbl,BOOLEAN is_congested)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 *******************************************************************************/
avdt_ad_tc_data_ind(tAVDT_TC_TBL * p_tbl,BT_HDR * p_buf)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 *******************************************************************************/
avdt_ad_write_req(UINT8 type,tAVDT_CCB * p_ccb,tAVDT_SCB * p_scb,BT_HDR * p_buf)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 *******************************************************************************/
avdt_ad_open_req(UINT8 type,tAVDT_CCB * p_ccb,tAVDT_SCB * p_scb,UINT8 role)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 *******************************************************************************/
avdt_ad_close_req(UINT8 type,tAVDT_CCB * p_ccb,tAVDT_SCB * p_scb)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