Example #1
0
/*******************************************************************************
 **
 ** Function         btc_a2dp_sink_enque_buf
 **
 ** Description      This function is called by the av_co to fill A2DP Sink Queue
 **
 **
 ** Returns          size of the queue
 *******************************************************************************/
UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt)
{
    tBT_SBC_HDR *p_msg;

    if (btc_aa_snk_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/
        return fixed_queue_length(btc_aa_snk_cb.RxSbcQ);
    }

    if (fixed_queue_length(btc_aa_snk_cb.RxSbcQ) >= MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ) {
        APPL_TRACE_WARNING("Pkt dropped\n");
        return fixed_queue_length(btc_aa_snk_cb.RxSbcQ);
    }

    APPL_TRACE_DEBUG("btc_a2dp_sink_enque_buf + ");

    /* allocate and Queue this buffer */
    if ((p_msg = (tBT_SBC_HDR *) osi_malloc(sizeof(tBT_SBC_HDR) +
                                            p_pkt->offset + p_pkt->len)) != NULL) {
        memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len));
        p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
        APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed);
        fixed_queue_enqueue(btc_aa_snk_cb.RxSbcQ, p_msg);
        btc_a2dp_sink_data_post(BTC_A2DP_SINK_DATA_EVT);
    } else {
        /* let caller deal with a failed allocation */
        APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - ");
    }
    return fixed_queue_length(btc_aa_snk_cb.RxSbcQ);
}
Example #2
0
/*******************************************************************************
**
** Function         port_flow_control_user
**
** Description      Check the current user flow control and if necessary return
**                  events to be send to the user based on the user's specified
**                  flow control type.
**
** Returns          event mask to be returned to the application
**
*******************************************************************************/
UINT32 port_flow_control_user (tPORT *p_port)
{
    UINT32 event = 0;

    /* Flow control to the user can be caused by flow controlling by the peer */
    /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
    /* tx_queue is full */
    BOOLEAN fc = p_port->tx.peer_fc
                 || !p_port->rfc.p_mcb
                 || !p_port->rfc.p_mcb->peer_ready
                 || (p_port->tx.queue_size > PORT_TX_HIGH_WM)
                 || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);

    if (p_port->tx.user_fc == fc) {
        return (0);
    }

    p_port->tx.user_fc = fc;

    if (fc) {
        event = PORT_EV_FC;
    } else {
        event = PORT_EV_FC | PORT_EV_FCS;
    }

    return (event);
}
Example #3
0
/*******************************************************************************
**
**  Function        L2CA_UcdDataWrite
**
**  Description     Send UCD to remote device
**
**  Parameters:     PSM
**                  BD Address of remote
**                  Pointer to buffer of type BT_HDR
**                  flags : L2CAP_FLUSHABLE_CH_BASED
**                          L2CAP_FLUSHABLE_PKT
**                          L2CAP_NON_FLUSHABLE_PKT
**
** Return value     L2CAP_DW_SUCCESS, if data accepted
**                  L2CAP_DW_FAILED,  if error
**
*******************************************************************************/
UINT16 L2CA_UcdDataWrite (UINT16 psm, BD_ADDR rem_bda, BT_HDR *p_buf, UINT16 flags)
{
    tL2C_LCB        *p_lcb;
    tL2C_CCB        *p_ccb;
    tL2C_RCB        *p_rcb;
    UINT8           *p;

    L2CAP_TRACE_API ("L2CA_UcdDataWrite()  PSM: 0x%04x  BDA: %08x%04x", psm,
                     (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
                     (rem_bda[4] << 8) + rem_bda[5]);

    /* Fail if the PSM is not registered */
    if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
            || ( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED )) {
        L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_UcdDataWrite, PSM: 0x%04x", psm);
        osi_free (p_buf);
        return (L2CAP_DW_FAILED);
    }

    /* First, see if we already have a link to the remote */
    /*  then find the channel control block for UCD */
    if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL)
            || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) {
        if ( l2c_ucd_connect (rem_bda) == FALSE ) {
            osi_free (p_buf);
            return (L2CAP_DW_FAILED);
        }

        /* If we still don't have lcb and ccb after connect attempt, then can't proceed */
        if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL)
                || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) {
            osi_free (p_buf);
            return (L2CAP_DW_FAILED);
        }
    }

    /* write PSM */
    p_buf->offset -= L2CAP_UCD_OVERHEAD;
    p_buf->len += L2CAP_UCD_OVERHEAD;
    p = (UINT8 *)(p_buf + 1) + p_buf->offset;

    UINT16_TO_STREAM (p, psm);

    /* UCD MTU check */
    if ((p_lcb->ucd_mtu) && (p_buf->len > p_lcb->ucd_mtu)) {
        L2CAP_TRACE_WARNING ("L2CAP - Handle: 0x%04x  UCD bigger than peer's UCD mtu size cannot be sent", p_lcb->handle);
        osi_free (p_buf);
        return (L2CAP_DW_FAILED);
    }

    /* If already congested, do not accept any more packets */
    if (p_ccb->cong_sent) {
        L2CAP_TRACE_ERROR ("L2CAP - Handle: 0x%04x UCD cannot be sent, already congested count: %u  buff_quota: %u",
                           p_lcb->handle,
                           (fixed_queue_length(p_ccb->xmit_hold_q) +
                            fixed_queue_length(p_lcb->ucd_out_sec_pending_q)),
                           p_ccb->buff_quota);

        osi_free (p_buf);
        return (L2CAP_DW_FAILED);
    }

    /* channel based, packet based flushable or non-flushable */
    p_buf->layer_specific = flags;

    l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_buf);

    if (p_ccb->cong_sent) {
        return (L2CAP_DW_CONGESTED);
    } else {
        return (L2CAP_DW_SUCCESS);
    }
}
Example #4
0
/*******************************************************************************
**
** Function         PORT_DataInd
**
** Description      This function is called from the RFCOMM layer when data
**                  buffer is received from the peer.
**
*******************************************************************************/
void PORT_DataInd (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
{
    tPORT  *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
    UINT8  rx_char1;
    UINT32 events = 0;
    UINT8  *p;
    int    i;

    RFCOMM_TRACE_EVENT("PORT_DataInd with data length %d, p_mcb:%p,p_port:%p,dlci:%d",
                       p_buf->len, p_mcb, p_port, dlci);
    if (!p_port) {
        osi_free (p_buf);
        return;
    }
    /* If client registered callout callback with flow control we can just deliver receive data */
    if (p_port->p_data_co_callback) {
        /* Another packet is delivered to user.  Send credits to peer if required */

        if (p_port->p_data_co_callback(p_port->inx, (UINT8 *)p_buf, -1, DATA_CO_CALLBACK_TYPE_INCOMING)) {
            port_flow_control_peer(p_port, TRUE, 1);
        } else {
            port_flow_control_peer(p_port, FALSE, 0);
        }
        //osi_free (p_buf);
        return;
    } else {
        RFCOMM_TRACE_DEBUG("PORT_DataInd, p_port:%p, p_data_co_callback is null", p_port);
    }
    /* If client registered callback we can just deliver receive data */
    if (p_port->p_data_callback) {
        /* Another packet is delivered to user.  Send credits to peer if required */
        port_flow_control_peer(p_port, TRUE, 1);

        p_port->p_data_callback (p_port->inx, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
        osi_free (p_buf);
        return;
    }

    /* Check if rx queue exceeds the limit */
    if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM)
     || (fixed_queue_length(p_port->rx.queue) + 1 > p_port->rx_buf_critical)) {
        RFCOMM_TRACE_EVENT ("PORT_DataInd. Buffer over run. Dropping the buffer");
        osi_free (p_buf);

        RFCOMM_LineStatusReq (p_mcb, dlci, LINE_STATUS_OVERRUN);
        return;
    }

    /* If user registered to receive notification when a particular byte is */
    /* received we mast check all received bytes */
    if (((rx_char1 = p_port->user_port_pars.rx_char1) != 0)
            && (p_port->ev_mask & PORT_EV_RXFLAG)) {
        for (i = 0, p = (UINT8 *)(p_buf + 1) + p_buf->offset; i < p_buf->len; i++) {
            if (*p++ == rx_char1) {
                events |= PORT_EV_RXFLAG;
                break;
            }
        }
    }

    osi_mutex_global_lock();

    fixed_queue_enqueue(p_port->rx.queue, p_buf);
    p_port->rx.queue_size += p_buf->len;

    osi_mutex_global_unlock();

    /* perform flow control procedures if necessary */
    port_flow_control_peer(p_port, FALSE, 0);

    /* If user indicated flow control can not deliver any notifications to him */
    if (p_port->rx.user_fc) {
        if (events & PORT_EV_RXFLAG) {
            p_port->rx_flag_ev_pending = TRUE;
        }

        return;
    }

    events |= PORT_EV_RXCHAR;

    /* Mask out all events that are not of interest to user */
    events &= p_port->ev_mask;

    if (p_port->p_callback && events) {
        p_port->p_callback (events, p_port->inx);
    }
}
Example #5
0
/*******************************************************************************
**
** Function         port_flow_control_peer
**
** Description      Send flow control messages to the peer for both enabling
**                  and disabling flow control, for both credit-based and
**                  TS 07.10 flow control mechanisms.
**
** Returns          nothing
**
*******************************************************************************/
void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
{
    if (!p_port->rfc.p_mcb) {
        return;
    }

    /* If using credit based flow control */
    if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
        /* if want to enable flow from peer */
        if (enable) {
            /* update rx credits */
            if (count > p_port->credit_rx) {
                p_port->credit_rx = 0;
            } else {
                p_port->credit_rx -= count;
            }

            /* If credit count is less than low credit watermark, and user */
            /* did not force flow control, send a credit update */
            /* There might be a special case when we just adjusted rx_max */
            if ((p_port->credit_rx <= p_port->credit_rx_low)
                    && !p_port->rx.user_fc
                    && (p_port->credit_rx_max > p_port->credit_rx)) {
                rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
                                (UINT8) (p_port->credit_rx_max - p_port->credit_rx));

                p_port->credit_rx = p_port->credit_rx_max;

                p_port->rx.peer_fc = FALSE;
            }
        }
        /* else want to disable flow from peer */
        else {
            /* if client registered data callback, just do what they want */
            if (p_port->p_data_callback || p_port->p_data_co_callback) {
                p_port->rx.peer_fc = TRUE;
            }
            /* if queue count reached credit rx max, set peer fc */
            else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max) {
                p_port->rx.peer_fc = TRUE;
            }
        }
    }
    /* else using TS 07.10 flow control */
    else {
        /* if want to enable flow from peer */
        if (enable) {
            /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
            /* check if it can be resumed now */
            if (p_port->rx.peer_fc
                    && (p_port->rx.queue_size < PORT_RX_LOW_WM)
                    && (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) {
                p_port->rx.peer_fc = FALSE;

                /* If user did not force flow control allow traffic now */
                if (!p_port->rx.user_fc) {
                    RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, TRUE);
                }
            }
        }
        /* else want to disable flow from peer */
        else {
            /* if client registered data callback, just do what they want */
            if (p_port->p_data_callback || p_port->p_data_co_callback) {
                p_port->rx.peer_fc = TRUE;
                RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
            }
            /* Check the size of the rx queue.  If it exceeds certain */
            /* level and flow control has not been sent to the peer do it now */
            else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
                      || (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM))
                      && !p_port->rx.peer_fc) {
                RFCOMM_TRACE_EVENT ("PORT_DataInd Data reached HW. Sending FC set.");

                p_port->rx.peer_fc = TRUE;
                RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
            }
        }
    }
}