/******************************************************************************* ** ** Function port_rfc_send_tx_data ** ** Description This function is when forward data can be sent to the peer ** *******************************************************************************/ UINT32 port_rfc_send_tx_data (tPORT *p_port) { UINT32 events = 0; BT_HDR *p_buf; /* if there is data to be sent */ if (p_port->tx.queue_size > 0) { /* while the rfcomm peer is not flow controlling us, and peer is ready */ while (!p_port->tx.peer_fc && p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready) { /* get data from tx queue and send it */ osi_mutex_global_lock(); if ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL) { p_port->tx.queue_size -= p_buf->len; osi_mutex_global_unlock(); RFCOMM_TRACE_DEBUG ("Sending RFCOMM_DataReq tx.queue_size=%d", p_port->tx.queue_size); RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf); events |= PORT_EV_TXCHAR; if (p_port->tx.queue_size == 0) { events |= PORT_EV_TXEMPTY; break; } } /* queue is empty-- all data sent */ else { osi_mutex_global_unlock(); events |= PORT_EV_TXEMPTY; break; } } /* If we flow controlled user based on the queue size enable data again */ events |= port_flow_control_user (p_port); } return (events & p_port->ev_mask); }
/******************************************************************************* ** ** 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); } }
/******************************************************************************* ** ** Function port_release_port ** ** Description Release port infor control block. ** ** Returns Pointer to the PORT or NULL if not found ** *******************************************************************************/ void port_release_port (tPORT *p_port) { BT_HDR *p_buf; UINT32 mask; tPORT_CALLBACK *p_port_cb; tPORT_STATE user_port_pars; osi_mutex_global_lock(); RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port); while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL) { osi_free (p_buf); } p_port->rx.queue_size = 0; while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL) { osi_free (p_buf); } p_port->tx.queue_size = 0; osi_mutex_global_unlock(); p_port->state = PORT_STATE_CLOSED; if (p_port->rfc.state == RFC_STATE_CLOSED) { RFCOMM_TRACE_DEBUG ("rfc_port_closed DONE"); if (p_port->rfc.p_mcb) { p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0; /* If there are no more ports opened on this MCB release it */ rfc_check_mcb_active (p_port->rfc.p_mcb); } rfc_port_timer_stop (p_port); fixed_queue_free(p_port->tx.queue, NULL); p_port->tx.queue = NULL; fixed_queue_free(p_port->rx.queue, NULL); p_port->rx.queue = NULL; RFCOMM_TRACE_DEBUG ("port_release_port:p_port->keep_port_handle:%d", p_port->keep_port_handle); if ( p_port->keep_port_handle ) { RFCOMM_TRACE_DEBUG ("port_release_port:Initialize handle:%d", p_port->inx); /* save event mask and callback */ mask = p_port->ev_mask; p_port_cb = p_port->p_callback; user_port_pars = p_port->user_port_pars; port_set_defaults(p_port); /* restore */ p_port->ev_mask = mask; p_port->p_callback = p_port_cb; p_port->user_port_pars = user_port_pars; p_port->mtu = p_port->keep_mtu; p_port->state = PORT_STATE_OPENING; p_port->rfc.p_mcb = NULL; if (p_port->is_server) { p_port->dlci &= 0xfe; } p_port->local_ctrl.modem_signal = p_port->default_signal_state; memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN); } else { RFCOMM_TRACE_DEBUG ("port_release_port:Clean-up handle:%d", p_port->inx); memset (p_port, 0, sizeof (tPORT)); } } }