16ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach/******************************************************************************
26ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *
36ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  Copyright (C) 1999-2012 Broadcom Corporation
46ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *
56ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  Licensed under the Apache License, Version 2.0 (the "License");
66ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  you may not use this file except in compliance with the License.
76ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  You may obtain a copy of the License at:
86ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *
96ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  http://www.apache.org/licenses/LICENSE-2.0
106ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *
116ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  Unless required by applicable law or agreed to in writing, software
126ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  distributed under the License is distributed on an "AS IS" BASIS,
136ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
146ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  See the License for the specific language governing permissions and
156ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  limitations under the License.
166ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *
176ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach ******************************************************************************/
186ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach
196ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach/******************************************************************************
206ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *
216ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *  Port Emulation entity utilities
226ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach *
236ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach ******************************************************************************/
24e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include <string.h>
25e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
26e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "bt_target.h"
27e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "gki.h"
28e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "rfcdefs.h"
29e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "port_api.h"
30e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "port_int.h"
31e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "rfc_int.h"
32e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "l2cdefs.h"
33e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "btm_int.h"
34e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach#include "btu.h"
35e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
3666aa5171e4e7c9f942971a30419c03134e67a4a4Harish Paryani#include <cutils/log.h>
37595bced8e7c280e37a75b9bf9c1f36263434041cMatthew Xie#define info(fmt, ...)  ALOGI ("%s: " fmt,__FUNCTION__,  ## __VA_ARGS__)
38595bced8e7c280e37a75b9bf9c1f36263434041cMatthew Xie#define debug(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__,  ## __VA_ARGS__)
39595bced8e7c280e37a75b9bf9c1f36263434041cMatthew Xie#define error(fmt, ...) ALOGE ("## ERROR : %s: " fmt "##",__FUNCTION__,  ## __VA_ARGS__)
40595bced8e7c280e37a75b9bf9c1f36263434041cMatthew Xie#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
4166aa5171e4e7c9f942971a30419c03134e67a4a4Harish Paryani
42e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
436ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbachstatic const tPORT_STATE default_port_pars =
44e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
45e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_BAUD_RATE_9600,
46e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_8_BITS,
47e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_ONESTOPBIT,
48e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_PARITY_NO,
49e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_ODD_PARITY,
50e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_FC_OFF,
51e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    0,                      /* No rx_char */
52e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_XON_DC1,
53e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_XOFF_DC3,
54e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach};
55e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
56e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
57e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
58e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
59e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
60e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_allocate_port
61e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
62e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      Look through the Port Control Blocks for a free one.  Note
63e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  that one server can open several ports with the same SCN
646ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach**                  if it can support simulteneous requests from different
65e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  clients.
66e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
67e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Returns          Pointer to the PORT or NULL if not found
68e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
69e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
70e448862a47c08eb23185aaed574b39264f5005fcAndre EisenbachtPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr)
71e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
72e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    tPORT  *p_port = &rfc_cb.port.port[0];
73e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT8  xx, yy;
74e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
75e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++)
76e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
77e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (yy >= MAX_RFC_PORTS)
78e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            yy = 0;
79e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
80e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        p_port = &rfc_cb.port.port[yy];
81e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (!p_port->in_use)
82e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
83e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            memset (p_port, 0, sizeof (tPORT));
84e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
85e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->in_use = TRUE;
86e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->inx    = yy + 1;
87e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
88e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->dlci   = dlci;
89e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN);
90e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
91e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* During the open set default state for the port connection */
92e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            port_set_defaults (p_port);
93e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
94e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            rfc_cb.rfc.last_port = yy;
9566aa5171e4e7c9f942971a30419c03134e67a4a4Harish Paryani            debug("rfc_cb.port.port[%d] allocated, last_port:%d", yy, rfc_cb.rfc.last_port);
96e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            return (p_port);
97e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
98e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
99e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
100e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    /* If here, no free PORT found */
101e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    return (NULL);
102e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
103e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
104e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
105e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
106e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
107e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_set_defaults
108e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
109e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      Set defualt port parameters
110e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
111e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
112e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
113e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbachvoid port_set_defaults (tPORT *p_port)
114e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
115e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->ev_mask        = 0;
116e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->p_callback     = NULL;
117e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->port_ctrl      = 0;
118e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->error          = 0;
119e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->line_status    = 0;
120e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->rx_flag_ev_pending = FALSE;
121e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->peer_mtu       = RFCOMM_DEFAULT_MTU;
122e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
123e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->user_port_pars = default_port_pars;
124e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->peer_port_pars = default_port_pars;
125e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
126e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->credit_tx      = 0;
127e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->credit_rx      = 0;
128e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*  p_port->credit_rx_max  = PORT_CREDIT_RX_MAX;            Determined later */
129e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*  p_port->credit_rx_low  = PORT_CREDIT_RX_LOW;            Determined later */
130e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
131e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    memset (&p_port->local_ctrl, 0, sizeof (p_port->local_ctrl));
132e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    memset (&p_port->peer_ctrl, 0, sizeof (p_port->peer_ctrl));
133e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    memset (&p_port->rx, 0, sizeof (p_port->rx));
134e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    memset (&p_port->tx, 0, sizeof (p_port->tx));
135e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
136e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
137e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
138e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
139e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_select_mtu
140e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
141e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      Select MTU which will best serve connection from our
1426ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach**                  point of view.
143e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  If our device is 1.2 or lower we calculate how many DH5s
144e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  fit into 1 RFCOMM buffer.
145e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
146e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
147e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
148e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbachvoid port_select_mtu (tPORT *p_port)
149e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
150e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT16 packet_size;
151e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
152e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    /* Will select MTU only if application did not setup something */
153e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (p_port->mtu == 0)
154e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
155e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        /* find packet size which connection supports */
156e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        packet_size = btm_get_max_packet_size (p_port->bd_addr);
157e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (packet_size == 0)
158e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
159e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* something is very wrong */
160e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            RFCOMM_TRACE_WARNING0 ("port_select_mtu bad packet size");
161e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->mtu = RFCOMM_DEFAULT_MTU;
162e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
163e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        else
164e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
165e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* We try to negotiate MTU that each packet can be split into whole
166e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            number of max packets.  For example if link is 1.2 max packet size is 339 bytes.
167e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            At first calculate how many whole packets it is.  MAX L2CAP is 1691 + 4 overhead.
1686ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach            1695, that will be 5 Dh5 packets.  Now maximum RFCOMM packet is
169e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            5 * 339 = 1695. Minus 4 bytes L2CAP header 1691.  Minus RFCOMM 6 bytes header overhead 1685
170e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
171e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            For EDR 2.0 packet size is 1027.  So we better send RFCOMM packet as 1 3DH5 packet
172e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            1 * 1027 = 1027.  Minus 4 bytes L2CAP header 1023.  Minus RFCOMM 6 bytes header overhead 1017 */
173e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size)
174e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
175e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
176e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                RFCOMM_TRACE_DEBUG1 ("port_select_mtu selected %d based on connection speed", p_port->mtu);
177e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
178e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            else
179e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
180e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
181e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                RFCOMM_TRACE_DEBUG1 ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
182e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
183e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
184e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
185e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    else
186e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
187e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        RFCOMM_TRACE_DEBUG1 ("port_select_mtu application selected %d", p_port->mtu);
188e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
189e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->credit_rx_max  = (PORT_RX_HIGH_WM / p_port->mtu);
190e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if( p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM )
191e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
192e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->credit_rx_low  = (PORT_RX_LOW_WM / p_port->mtu);
193e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if( p_port->credit_rx_low > PORT_RX_BUF_LOW_WM )
194e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
195e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
196e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if( p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM )
197e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
1986ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach    RFCOMM_TRACE_DEBUG3 ("port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
199e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                          p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
200e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
201e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
202e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
203e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
204e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
205e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_release_port
206e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
2076ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach** Description      Release port infor control block.
208e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
209e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Returns          Pointer to the PORT or NULL if not found
210e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
211e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
212e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbachvoid port_release_port (tPORT *p_port)
213e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
214e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    BT_HDR *p_buf;
215e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT32 mask;
216e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    tPORT_CALLBACK *p_port_cb;
217e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    tPORT_STATE user_port_pars;
218e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
219e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_SCHEDULE_LOCK;
22066aa5171e4e7c9f942971a30419c03134e67a4a4Harish Paryani    debug("port_release_port, p_port:%p", p_port);
221e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL)
222e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        GKI_freebuf (p_buf);
223e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
224e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->rx.queue_size = 0;
225e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
226e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
227e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        GKI_freebuf (p_buf);
228e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
229e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->tx.queue_size = 0;
230e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
231e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    PORT_SCHEDULE_UNLOCK;
232e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
233e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->state = PORT_STATE_CLOSED;
234e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
235e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (p_port->rfc.state == RFC_STATE_CLOSED)
236e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
237e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        RFCOMM_TRACE_DEBUG0 ("rfc_port_closed DONE");
238e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (p_port->rfc.p_mcb)
239e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
240e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
241e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
242e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* If there are no more ports opened on this MCB release it */
243e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            rfc_check_mcb_active (p_port->rfc.p_mcb);
244e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
245e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        rfc_port_timer_stop (p_port);
246e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
247e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if( p_port->keep_port_handle )
248e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
249e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            RFCOMM_TRACE_DEBUG1 ("port_release_port:Initialize handle:%d", p_port->inx);
250e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* save event mask and callback */
251e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            mask = p_port->ev_mask;
252e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port_cb = p_port->p_callback;
253e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            user_port_pars = p_port->user_port_pars;
2546ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach
255e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            port_set_defaults(p_port);
256e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* restore */
257e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->ev_mask         = mask;
258e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->p_callback      = p_port_cb;
259e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->user_port_pars  = user_port_pars;
260e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->mtu             = p_port->keep_mtu;
261e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
262e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->state           = PORT_STATE_OPENING;
263e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->rfc.p_mcb       = NULL;
264e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            if(p_port->is_server)
265e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->dlci       &= 0xfe;
266e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
267e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            p_port->local_ctrl.modem_signal = p_port->default_signal_state;
268e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
269e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
270e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        else
271e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
272e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            RFCOMM_TRACE_DEBUG1 ("port_release_port:Clean-up handle:%d", p_port->inx);
273e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            memset (p_port, 0, sizeof (tPORT));
274e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
275e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
276e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
277e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
278e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
279e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
280e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
281e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_find_mcb
282e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
283e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      This function checks if connection exists to device with
284e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  the BD_ADDR.
285e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
286e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
287e448862a47c08eb23185aaed574b39264f5005fcAndre EisenbachtRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
288e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
289e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    int      i;
290e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
291e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    for (i = 0; i < MAX_BD_CONNECTIONS; i++)
292e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
293e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
294e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach         && !memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN))
295e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
296e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* Multiplexer channel found do not change anything */
297e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            return (&rfc_cb.port.rfc_mcb[i]);
298e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
299e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
300e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    return (NULL);
301e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
302e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
303e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
304e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
305e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
306e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_find_mcb_dlci_port
307e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
3086ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach** Description      Find port on the multiplexer channel based on DLCI.  If
309e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  this port with DLCI not found try to use even DLCI.  This
310e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  is for the case when client is establishing connection on
311e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  none-initiator MCB.
312e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
313e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Returns          Pointer to the PORT or NULL if not found
314e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
315e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
316e448862a47c08eb23185aaed574b39264f5005fcAndre EisenbachtPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci)
317e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
318e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT8 inx;
3196ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach
320e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (!p_mcb)
321e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        return (NULL);
322e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
323e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (dlci > RFCOMM_MAX_DLCI)
324e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        return (NULL);
325e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
326e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    inx = p_mcb->port_inx[dlci];
327e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (inx == 0)
328e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        return (NULL);
329e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    else
330e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        return (&rfc_cb.port.port[inx - 1]);
331e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
332e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
333e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
334e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
335e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
336e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_find_dlci_port
337e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
338e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      Find port with DLCI not assigned to multiplexer channel
339e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
340e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Returns          Pointer to the PORT or NULL if not found
341e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
342e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
343e448862a47c08eb23185aaed574b39264f5005fcAndre EisenbachtPORT *port_find_dlci_port (UINT8 dlci)
344e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
345e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT16 i;
346e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    tPORT  *p_port;
347e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
348e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    for (i = 0; i < MAX_RFC_PORTS; i++)
349e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
350e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        p_port = &rfc_cb.port.port[i];
351e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (p_port->in_use && (p_port->rfc.p_mcb == NULL))
352e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
353e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            if (p_port->dlci == dlci)
354e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
355e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                return (p_port);
356e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
357e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1)))
358e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
359e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->dlci++;
360e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                return (p_port);
361e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
362e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
363e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
364e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    return (NULL);
365e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
366e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
367e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
368e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
369e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
370e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_find_port
371e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
372e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      Find port with DLCI, BD_ADDR
373e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
374e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Returns          Pointer to the PORT or NULL if not found
375e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
376e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
377e448862a47c08eb23185aaed574b39264f5005fcAndre EisenbachtPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr)
378e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
379e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT16 i;
380e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    tPORT  *p_port;
381e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
382e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    for (i = 0; i < MAX_RFC_PORTS; i++)
383e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
384e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        p_port = &rfc_cb.port.port[i];
3856ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach        if (p_port->in_use
386e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach         && (p_port->dlci == dlci)
387e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach         && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN))
388e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
389e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            return (p_port);
390e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
391e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
392e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    return (NULL);
393e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
394e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
395e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
396e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
397e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
398e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_flow_control_user
399e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
400e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      Check the current user flow control and if necessary return
4016ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach**                  events to be send to the user based on the user's specified
402e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  flow control type.
403e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
404e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Returns          event mask to be returned to the application
405e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
406e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
407e448862a47c08eb23185aaed574b39264f5005fcAndre EisenbachUINT32 port_flow_control_user (tPORT *p_port)
408e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
409e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT32 event = 0;
410e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
411e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    /* Flow control to the user can be caused by flow controlling by the peer */
412e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
413e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    /* tx_queue is full */
4146ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach    BOOLEAN fc = p_port->tx.peer_fc
415e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach              || !p_port->rfc.p_mcb
416e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach              || !p_port->rfc.p_mcb->peer_ready
417e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach              || (p_port->tx.queue_size > PORT_TX_HIGH_WM)
418e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach              || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM);
419e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
420e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (p_port->tx.user_fc == fc)
421e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        return (0);
422e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
423e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    p_port->tx.user_fc = fc;
424e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
425e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (fc)
426e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        event = PORT_EV_FC;
427e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    else
428e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        event = PORT_EV_FC | PORT_EV_FCS;
429e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
430e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    return (event);
431e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
432e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
433e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
434e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
435e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
436e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_get_signal_changes
437e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
438e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      Check modem signals that has been changed
439e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
440e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Returns          event mask to be returned to the application
441e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
442e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
443e448862a47c08eb23185aaed574b39264f5005fcAndre EisenbachUINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal)
444e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
445e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT8  changed_signals = (signal ^ old_signals);
446e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    UINT32 events = 0;
447e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
448e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (changed_signals & PORT_DTRDSR_ON)
449e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
450e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        events |= PORT_EV_DSR;
451e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
452e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (signal & PORT_DTRDSR_ON)
453e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            events |= PORT_EV_DSRS;
454e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
455e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
456e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (changed_signals & PORT_CTSRTS_ON)
457e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
458e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        events |= PORT_EV_CTS;
459e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
460e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (signal & PORT_CTSRTS_ON)
461e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            events |= PORT_EV_CTSS;
462e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
463e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
464e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (changed_signals & PORT_RING_ON)
465e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        events |= PORT_EV_RING;
466e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
467e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (changed_signals & PORT_DCD_ON)
468e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
469e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        events |= PORT_EV_RLSD;
470e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
471e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (signal & PORT_DCD_ON)
472e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            events |= PORT_EV_RLSDS;
473e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
474e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
475e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    return (p_port->ev_mask & events);
476e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
477e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
478e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach/*******************************************************************************
479e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
480e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Function         port_flow_control_peer
481e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
482e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Description      Send flow control messages to the peer for both enabling
483e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  and disabling flow control, for both credit-based and
484e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**                  TS 07.10 flow control mechanisms.
485e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
486e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach** Returns          nothing
487e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach**
488e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach*******************************************************************************/
489e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbachvoid port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
490e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach{
491e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (!p_port->rfc.p_mcb)
492e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        return;
493e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
494e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    /* If using credit based flow control */
495e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
496e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
497e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        /* if want to enable flow from peer */
498e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (enable)
499e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
500e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* update rx credits */
501e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            if (count > p_port->credit_rx)
502e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
503e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->credit_rx = 0;
504e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
505e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            else
506e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
507e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->credit_rx -= count;
508e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
509e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
510e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* If credit count is less than low credit watermark, and user */
511e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* did not force flow control, send a credit update */
512e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* There might be a special case when we just adjusted rx_max */
5136ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach            if ((p_port->credit_rx <= p_port->credit_rx_low)
514e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach             && !p_port->rx.user_fc
515e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach             && (p_port->credit_rx_max > p_port->credit_rx))
516e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
517e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
518e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                                (UINT8) (p_port->credit_rx_max - p_port->credit_rx));
519e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
520e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->credit_rx = p_port->credit_rx_max;
5216ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach
522e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->rx.peer_fc = FALSE;
523e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
524e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
525e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        /* else want to disable flow from peer */
526e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        else
527e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
528e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* if client registered data callback, just do what they want */
52966aa5171e4e7c9f942971a30419c03134e67a4a4Harish Paryani            if (p_port->p_data_callback || p_port->p_data_co_callback)
530e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
531e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->rx.peer_fc = TRUE;
532e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
533e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* if queue count reached credit rx max, set peer fc */
534e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            else if (p_port->rx.queue.count >= p_port->credit_rx_max)
535e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
536e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->rx.peer_fc = TRUE;
537e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
538e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
539e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
540e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    /* else using TS 07.10 flow control */
5416ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach    else
542e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    {
543e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        /* if want to enable flow from peer */
544e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        if (enable)
545e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
546e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
547e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* check if it can be resumed now */
5486ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach            if (p_port->rx.peer_fc
549e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach             && (p_port->rx.queue_size < PORT_RX_LOW_WM)
550e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach             && (p_port->rx.queue.count < PORT_RX_BUF_LOW_WM))
551e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
552e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->rx.peer_fc = FALSE;
553e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
554e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                /* If user did not force flow control allow traffic now */
555e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                if (!p_port->rx.user_fc)
556e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                    RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, TRUE);
557e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
558e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
559e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        /* else want to disable flow from peer */
560e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        else
561e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        {
562e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* if client registered data callback, just do what they want */
56366aa5171e4e7c9f942971a30419c03134e67a4a4Harish Paryani            if (p_port->p_data_callback || p_port->p_data_co_callback)
564e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
565e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->rx.peer_fc = TRUE;
566e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
567e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            }
568e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* Check the size of the rx queue.  If it exceeds certain */
569e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            /* level and flow control has not been sent to the peer do it now */
5706ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach            else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
571e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                     || (p_port->rx.queue.count > PORT_RX_BUF_HIGH_WM))
572e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                     && !p_port->rx.peer_fc)
573e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach            {
574e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                RFCOMM_TRACE_EVENT0 ("PORT_DataInd Data reached HW. Sending FC set.");
575e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
576e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                p_port->rx.peer_fc = TRUE;
577e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach                RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
5786ef101187774e30ddba6b46bbedef549a42196adAndre Eisenbach            }
579e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach        }
580e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach    }
581e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach}
582e448862a47c08eb23185aaed574b39264f5005fcAndre Eisenbach
583