/******************************************************************************* ** ** 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_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\n", 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\n", 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\n", (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\n", 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_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_GetL2CapChannel ** ** Description Get the L2CAP CID used by the handle. ** ** Returns CID if successful, otherwise 0. ** *******************************************************************************/ UINT16 AVDT_GetL2CapChannel(UINT8 handle) { tAVDT_SCB *p_scb; tAVDT_CCB *p_ccb; UINT8 tcid; UINT16 lcid = 0; /* map handle to scb */ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) && ((p_ccb = p_scb->p_ccb) != NULL)) { /* get tcid from type, scb */ tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb); lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; } return (lcid); }
/******************************************************************************* ** ** 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_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\n", 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); } }