static void hci_host_thread_handler(void *arg) { /* * Previous task handles RX queue and two TX Queues, Since there is * a RX Thread Task in H4 layer which receives packet from driver layer. * Now HCI Host Task has been optimized to only process TX Queue * including command and data queue. And command queue has high priority, * All packets will be directly copied to single queue in driver layer with * H4 type header added (1 byte). */ BtTaskEvt_t e; for (;;) { if (pdTRUE == xQueueReceive(xHciHostQueue, &e, (portTickType)portMAX_DELAY)) { if (e.sig == 0xff) { if (esp_vhci_host_check_send_available()) { /*Now Target only allowed one packet per TX*/ BT_HDR *pkt = packet_fragmenter->fragment_current_packet(); if (pkt != NULL) { packet_fragmenter->fragment_and_dispatch(pkt); } else { if (!fixed_queue_is_empty(hci_host_env.command_queue) && hci_host_env.command_credits > 0) { fixed_queue_process(hci_host_env.command_queue); } else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) { fixed_queue_process(hci_host_env.packet_queue); } } } } } } }
/******************************************************************************* ** ** Function avdt_ccb_snd_msg ** ** Description ** ** ** Returns void. ** *******************************************************************************/ void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) { BT_HDR *p_msg; UNUSED(p_data); /* if not congested */ if (!p_ccb->cong) { /* are we sending a fragmented message? continue sending fragment */ if (p_ccb->p_curr_msg != NULL) { avdt_msg_send(p_ccb, NULL); } /* do we have responses to send? send them */ else if (!fixed_queue_is_empty(p_ccb->rsp_q)) { while ((p_msg = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL) { if (avdt_msg_send(p_ccb, p_msg) == TRUE) { /* break out if congested */ break; } } } /* do we have commands to send? send next command */ avdt_ccb_snd_cmd(p_ccb, NULL); } }
/******************************************************************************* ** ** Function btc_a2dp_sink_rx_flush_req ** ** Description ** ** Returns TRUE is success ** *******************************************************************************/ BOOLEAN btc_a2dp_sink_rx_flush_req(void) { if (fixed_queue_is_empty(btc_aa_snk_cb.RxSbcQ) == TRUE) { /* Que is already empty */ return TRUE; } btc_a2dp_sink_ctrl_post(BTC_MEDIA_FLUSH_AA_RX, NULL); return TRUE; }
/******************************************************************************* ** ** Function l2c_ucd_delete_sec_pending_q ** ** Description discard all of UCD packets in security pending queue ** ** Returns None ** *******************************************************************************/ void l2c_ucd_delete_sec_pending_q(tL2C_LCB *p_lcb) { /* clean up any security pending UCD */ while (p_lcb->ucd_out_sec_pending_q.p_first) { osi_free(fixed_queue_try_dequeue(p_lcb->ucd_out_sec_pending_q)); } fixed_queue_free(p_lcb->ucd_out_sec_pending_q, NULL); p_lcb->ucd_out_sec_pending_q = NULL; while (! fixed_queue_is_empty(p_lcb->ucd_in_sec_pending_q)) { osi_free(fixed_queue_try_dequeue(p_lcb->ucd_in_sec_pending_q)); } fixed_queue_free(p_lcb->ucd_in_sec_pending_q); p_lcb->ucd_in_sec_pending_q = NULL; }
static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context) { tBT_SBC_HDR *p_msg; if (fixed_queue_is_empty(btc_aa_snk_cb.RxSbcQ)) { APPL_TRACE_DEBUG(" QUE EMPTY "); } else { if (btc_aa_snk_cb.rx_flush == TRUE) { btc_a2dp_sink_flush_q(btc_aa_snk_cb.RxSbcQ); return; } while ((p_msg = (tBT_SBC_HDR *)fixed_queue_try_peek_first(btc_aa_snk_cb.RxSbcQ)) != NULL ) { btc_a2dp_sink_handle_inc_media(p_msg); p_msg = (tBT_SBC_HDR *)fixed_queue_try_dequeue(btc_aa_snk_cb.RxSbcQ); if ( p_msg == NULL ) { APPL_TRACE_ERROR("Insufficient data in que "); break; } osi_free(p_msg); } APPL_TRACE_DEBUG(" Process Frames - "); } }
// Returns true if the event was intercepted and should not proceed to // higher layers. Also inspects an incoming event for interesting // information, like how many commands are now able to be sent. static bool filter_incoming_event(BT_HDR *packet) { waiting_command_t *wait_entry = NULL; uint8_t *stream = packet->data + packet->offset; uint8_t event_code; command_opcode_t opcode; STREAM_TO_UINT8(event_code, stream); STREAM_SKIP_UINT8(stream); // Skip the parameter total length field LOG_DEBUG("Receive packet event_code=0x%x\n", event_code); if (event_code == HCI_COMMAND_COMPLETE_EVT) { STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); wait_entry = get_waiting_command(opcode); if (!wait_entry) { LOG_WARN("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode); } else if (wait_entry->complete_callback) { wait_entry->complete_callback(packet, wait_entry->context); } else if (wait_entry->complete_future) { future_ready(wait_entry->complete_future, packet); } goto intercepted; } else if (event_code == HCI_COMMAND_STATUS_EVT) { uint8_t status; STREAM_TO_UINT8(status, stream); STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); // If a command generates a command status event, it won't be getting a command complete event wait_entry = get_waiting_command(opcode); if (!wait_entry) { LOG_WARN("%s command status event with no matching command. opcode: 0x%x", __func__, opcode); } else if (wait_entry->status_callback) { wait_entry->status_callback(status, wait_entry->command, wait_entry->context); } goto intercepted; } return false; intercepted: restart_comamnd_waiting_response_timer(&hci_host_env.cmd_waiting_q, false); /*Tell HCI Host Task to continue TX Pending commands*/ if (hci_host_env.command_credits && !fixed_queue_is_empty(hci_host_env.command_queue)) { hci_host_task_post(); } //ke_event_set(KE_EVENT_HCI_HOST_THREAD); if (wait_entry) { // If it has a callback, it's responsible for freeing the packet if (event_code == HCI_COMMAND_STATUS_EVT || (!wait_entry->complete_callback && !wait_entry->complete_future)) { buffer_allocator->free(packet); } // If it has a callback, it's responsible for freeing the command if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback) { buffer_allocator->free(wait_entry->command); } osi_free(wait_entry); } else { buffer_allocator->free(packet); } return true; }
/******************************************************************************* ** ** Function rfc_port_sm_opened ** ** Description This function handles events for the port in the OPENED ** state ** ** Returns void ** *******************************************************************************/ void rfc_port_sm_opened (tPORT *p_port, UINT16 event, void *p_data) { switch (event) { case RFC_EVENT_OPEN: RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); return; case RFC_EVENT_CLOSE: rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT); rfc_send_disc (p_port->rfc.p_mcb, p_port->dlci); p_port->rfc.expected_rsp = 0; p_port->rfc.state = RFC_STATE_DISC_WAIT_UA; return; case RFC_EVENT_CLEAR: rfc_port_closed (p_port); return; case RFC_EVENT_DATA: /* Send credits in the frame. Pass them in the layer specific member of the hdr. */ /* There might be an initial case when we reduced rx_max and credit_rx is still */ /* bigger. Make sure that we do not send 255 */ if ((p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) && (((BT_HDR *)p_data)->len < p_port->peer_mtu) && (!p_port->rx.user_fc) && (p_port->credit_rx_max > p_port->credit_rx)) { ((BT_HDR *)p_data)->layer_specific = (UINT8) (p_port->credit_rx_max - p_port->credit_rx); p_port->credit_rx = p_port->credit_rx_max; } else { ((BT_HDR *)p_data)->layer_specific = 0; } rfc_send_buf_uih (p_port->rfc.p_mcb, p_port->dlci, (BT_HDR *)p_data); rfc_dec_credit (p_port); return; case RFC_EVENT_UA: return; case RFC_EVENT_SABME: rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci); return; case RFC_EVENT_DM: PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci); rfc_port_closed (p_port); return; case RFC_EVENT_DISC: p_port->rfc.state = RFC_STATE_CLOSED; rfc_send_ua (p_port->rfc.p_mcb, p_port->dlci); if (! fixed_queue_is_empty(p_port->rx.queue)) { /* give a chance to upper stack to close port properly */ RFCOMM_TRACE_DEBUG("port queue is not empty"); rfc_port_timer_start (p_port, RFC_DISC_TIMEOUT); } else { PORT_DlcReleaseInd (p_port->rfc.p_mcb, p_port->dlci); } return; case RFC_EVENT_UIH: rfc_port_uplink_data (p_port, (BT_HDR *)p_data); return; case RFC_EVENT_TIMEOUT: Port_TimeOutCloseMux( p_port->rfc.p_mcb ) ; RFCOMM_TRACE_ERROR ("Port error state %d event %d", p_port->rfc.state, event); return; } RFCOMM_TRACE_WARNING ("Port state opened Event ignored %d", event); }
/******************************************************************************* ** ** Function btc_a2dp_sink_flush_q ** ** Description ** ** Returns void ** *******************************************************************************/ static void btc_a2dp_sink_flush_q(fixed_queue_t *p_q) { while (! fixed_queue_is_empty(p_q)) { osi_free(fixed_queue_try_dequeue(p_q)); } }