/******************************************************************************* ** ** 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_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\n", 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_dealloc ** ** Description Deallocate a stream control block. ** ** ** Returns void. ** *******************************************************************************/ void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) { UNUSED(p_data); AVDT_TRACE_DEBUG("avdt_scb_dealloc hdl=%d\n", 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 */ fixed_queue_free(p_scb->frag_q, osi_free_func); #endif memset(p_scb, 0, sizeof(tAVDT_SCB)); }
/******************************************************************************* ** ** 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_CreateStream ** ** Description Create a stream endpoint. After a stream endpoint is ** created an application can initiate a connection between ** this endpoint and an endpoint on a peer device. In ** addition, a peer device can discover, get the capabilities, ** and connect to this endpoint. ** ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs) { UINT16 result = AVDT_SUCCESS; tAVDT_SCB *p_scb; /* Verify parameters; if invalid, return failure */ if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL)) { result = AVDT_BAD_PARAMS; } /* Allocate scb; if no scbs, return failure */ else if ((p_scb = avdt_scb_alloc(p_cs)) == NULL) { result = AVDT_NO_RESOURCES; } else { *p_handle = avdt_scb_to_hdl(p_scb); } return result; }
/******************************************************************************* ** ** 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)); }