blob: 7f5f5a8bd19663cea709559ea164f5168280c2f0 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
2 *
3 * Copyright (C) 1999-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19/******************************************************************************
20 *
21 * Port Emulation entity utilities
22 *
23 ******************************************************************************/
24#include <string.h>
25
Andre Eisenbachd3842ed2015-10-12 18:32:46 -070026#include "osi/include/mutex.h"
27
The Android Open Source Project5738f832012-12-12 16:00:35 -080028#include "bt_target.h"
Pavlin Radoslavov258c2532015-09-27 20:59:05 -070029#include "bt_common.h"
Andre Eisenbachd3842ed2015-10-12 18:32:46 -070030#include "btm_int.h"
31#include "btu.h"
32#include "l2cdefs.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080033#include "port_api.h"
34#include "port_int.h"
35#include "rfc_int.h"
Andre Eisenbachd3842ed2015-10-12 18:32:46 -070036#include "rfcdefs.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080037
The Android Open Source Project5738f832012-12-12 16:00:35 -080038static const tPORT_STATE default_port_pars =
39{
40 PORT_BAUD_RATE_9600,
41 PORT_8_BITS,
42 PORT_ONESTOPBIT,
43 PORT_PARITY_NO,
44 PORT_ODD_PARITY,
45 PORT_FC_OFF,
46 0, /* No rx_char */
47 PORT_XON_DC1,
48 PORT_XOFF_DC3,
49};
50
51
52
53/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -080054 *
55 * Function port_allocate_port
56 *
57 * Description Look through the Port Control Blocks for a free one. Note
58 * that one server can open several ports with the same SCN
59 * if it can support simulteneous requests from different
60 * clients.
61 *
62 * Returns Pointer to the PORT or NULL if not found
63 *
64 ******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -070065tPORT *port_allocate_port (uint8_t dlci, BD_ADDR bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -080066{
67 tPORT *p_port = &rfc_cb.port.port[0];
Marie Janssend19e0782016-07-15 12:48:27 -070068 uint8_t xx, yy;
The Android Open Source Project5738f832012-12-12 16:00:35 -080069
70 for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++)
71 {
72 if (yy >= MAX_RFC_PORTS)
73 yy = 0;
74
75 p_port = &rfc_cb.port.port[yy];
76 if (!p_port->in_use)
77 {
Pavlin Radoslavov78bcff72015-12-04 17:36:34 -080078 memset(p_port, 0, sizeof (tPORT));
The Android Open Source Project5738f832012-12-12 16:00:35 -080079
Marie Janssend19e0782016-07-15 12:48:27 -070080 p_port->in_use = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -080081 p_port->inx = yy + 1;
82
The Android Open Source Project5738f832012-12-12 16:00:35 -080083 /* During the open set default state for the port connection */
84 port_set_defaults (p_port);
85
Andre Eisenbach072bd752016-03-18 02:09:58 -070086 p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
The Android Open Source Project5738f832012-12-12 16:00:35 -080087 rfc_cb.rfc.last_port = yy;
Andre Eisenbach072bd752016-03-18 02:09:58 -070088
89 p_port->dlci = dlci;
90 memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN);
91
Sharvil Nanavatid5bba902014-05-04 01:33:15 -070092 RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy, p_port, rfc_cb.rfc.last_port);
93 RFCOMM_TRACE_DEBUG("port_allocate_port:bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
Matthew Xie9ac641d2013-01-15 15:54:03 -080094 bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
The Android Open Source Project5738f832012-12-12 16:00:35 -080095 return (p_port);
96 }
97 }
98
99 /* If here, no free PORT found */
100 return (NULL);
101}
102
103
104/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800105 *
106 * Function port_set_defaults
107 *
108 * Description Set defualt port parameters
109 *
110 *
111 ******************************************************************************/
The Android Open Source Project5738f832012-12-12 16:00:35 -0800112void port_set_defaults (tPORT *p_port)
113{
114 p_port->ev_mask = 0;
115 p_port->p_callback = NULL;
116 p_port->port_ctrl = 0;
117 p_port->error = 0;
118 p_port->line_status = 0;
Marie Janssend19e0782016-07-15 12:48:27 -0700119 p_port->rx_flag_ev_pending = false;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800120 p_port->peer_mtu = RFCOMM_DEFAULT_MTU;
121
122 p_port->user_port_pars = default_port_pars;
123 p_port->peer_port_pars = default_port_pars;
124
125 p_port->credit_tx = 0;
126 p_port->credit_rx = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800127
128 memset (&p_port->local_ctrl, 0, sizeof (p_port->local_ctrl));
129 memset (&p_port->peer_ctrl, 0, sizeof (p_port->peer_ctrl));
130 memset (&p_port->rx, 0, sizeof (p_port->rx));
131 memset (&p_port->tx, 0, sizeof (p_port->tx));
Andre Eisenbach072bd752016-03-18 02:09:58 -0700132
Pavlin Radoslavov1a3844f2015-09-25 11:21:15 -0700133 p_port->tx.queue = fixed_queue_new(SIZE_MAX);
Andre Eisenbach072bd752016-03-18 02:09:58 -0700134 p_port->rx.queue = fixed_queue_new(SIZE_MAX);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800135}
136
137/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800138 *
139 * Function port_select_mtu
140 *
141 * Description Select MTU which will best serve connection from our
142 * point of view.
143 * If our device is 1.2 or lower we calculate how many DH5s
144 * fit into 1 RFCOMM buffer.
145 *
146 *
147 ******************************************************************************/
The Android Open Source Project5738f832012-12-12 16:00:35 -0800148void port_select_mtu (tPORT *p_port)
149{
Marie Janssend19e0782016-07-15 12:48:27 -0700150 uint16_t packet_size;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800151
152 /* Will select MTU only if application did not setup something */
153 if (p_port->mtu == 0)
154 {
155 /* find packet size which connection supports */
156 packet_size = btm_get_max_packet_size (p_port->bd_addr);
157 if (packet_size == 0)
158 {
159 /* something is very wrong */
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700160 RFCOMM_TRACE_WARNING ("port_select_mtu bad packet size");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800161 p_port->mtu = RFCOMM_DEFAULT_MTU;
162 }
163 else
164 {
165 /* We try to negotiate MTU that each packet can be split into whole
166 number of max packets. For example if link is 1.2 max packet size is 339 bytes.
167 At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4 overhead.
168 1695, that will be 5 Dh5 packets. Now maximum RFCOMM packet is
169 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691. Minus RFCOMM 6 bytes header overhead 1685
170
171 For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1 3DH5 packet
172 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. Minus RFCOMM 6 bytes header overhead 1017 */
173 if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size)
174 {
175 p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700176 RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on connection speed", p_port->mtu);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800177 }
178 else
179 {
180 p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700181 RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800182 }
183 }
184 }
185 else
186 {
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700187 RFCOMM_TRACE_DEBUG ("port_select_mtu application selected %d", p_port->mtu);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800188 }
189 p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
190 if( p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM )
191 p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
192 p_port->credit_rx_low = (PORT_RX_LOW_WM / p_port->mtu);
193 if( p_port->credit_rx_low > PORT_RX_BUF_LOW_WM )
194 p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
195 p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
196 if( p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM )
197 p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700198 RFCOMM_TRACE_DEBUG ("port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800199 p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
200}
201
The Android Open Source Project5738f832012-12-12 16:00:35 -0800202/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800203 *
204 * Function port_release_port
205 *
206 * Description Release port control block.
207 *
208 * Returns Pointer to the PORT or NULL if not found
209 *
210 ******************************************************************************/
Andre Eisenbach072bd752016-03-18 02:09:58 -0700211void port_release_port(tPORT *p_port)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800212{
Andre Eisenbach072bd752016-03-18 02:09:58 -0700213 RFCOMM_TRACE_DEBUG("%s p_port: %p state: %d keep_handle: %d", __func__,
214 p_port, p_port->rfc.state, p_port->keep_port_handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800215
Pavlin Radoslavove29c3432015-09-27 23:27:10 -0700216 mutex_global_lock();
Andre Eisenbach072bd752016-03-18 02:09:58 -0700217 BT_HDR *p_buf;
Pavlin Radoslavov1a3844f2015-09-25 11:21:15 -0700218 while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL)
Pavlin Radoslavovcceb4302016-02-05 13:54:43 -0800219 osi_free(p_buf);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800220 p_port->rx.queue_size = 0;
221
Pavlin Radoslavov1a3844f2015-09-25 11:21:15 -0700222 while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL)
Pavlin Radoslavovcceb4302016-02-05 13:54:43 -0800223 osi_free(p_buf);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800224 p_port->tx.queue_size = 0;
Pavlin Radoslavove29c3432015-09-27 23:27:10 -0700225 mutex_global_unlock();
The Android Open Source Project5738f832012-12-12 16:00:35 -0800226
Pavlin Radoslavov78bcff72015-12-04 17:36:34 -0800227 alarm_cancel(p_port->rfc.port_timer);
228
The Android Open Source Project5738f832012-12-12 16:00:35 -0800229 p_port->state = PORT_STATE_CLOSED;
230
231 if (p_port->rfc.state == RFC_STATE_CLOSED)
232 {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800233 if (p_port->rfc.p_mcb)
234 {
235 p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
236
237 /* If there are no more ports opened on this MCB release it */
Andre Eisenbach072bd752016-03-18 02:09:58 -0700238 rfc_check_mcb_active(p_port->rfc.p_mcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800239 }
Andre Eisenbach072bd752016-03-18 02:09:58 -0700240
The Android Open Source Project5738f832012-12-12 16:00:35 -0800241 rfc_port_timer_stop (p_port);
Andre Eisenbach072bd752016-03-18 02:09:58 -0700242 fixed_queue_free(p_port->tx.queue, NULL);
Pavlin Radoslavov8cbc2912016-06-16 16:37:57 -0700243 p_port->tx.queue = NULL;
Andre Eisenbach072bd752016-03-18 02:09:58 -0700244 fixed_queue_free(p_port->rx.queue, NULL);
Pavlin Radoslavov8cbc2912016-06-16 16:37:57 -0700245 p_port->rx.queue = NULL;
Andre Eisenbach072bd752016-03-18 02:09:58 -0700246
247 if (p_port->keep_port_handle)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800248 {
Andre Eisenbach072bd752016-03-18 02:09:58 -0700249 RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
250
The Android Open Source Project5738f832012-12-12 16:00:35 -0800251 /* save event mask and callback */
Marie Janssend19e0782016-07-15 12:48:27 -0700252 uint32_t mask = p_port->ev_mask;
Andre Eisenbach072bd752016-03-18 02:09:58 -0700253 tPORT_CALLBACK *p_port_cb = p_port->p_callback;
254 tPORT_STATE user_port_pars = p_port->user_port_pars;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800255
256 port_set_defaults(p_port);
Andre Eisenbach072bd752016-03-18 02:09:58 -0700257
The Android Open Source Project5738f832012-12-12 16:00:35 -0800258 /* restore */
259 p_port->ev_mask = mask;
260 p_port->p_callback = p_port_cb;
261 p_port->user_port_pars = user_port_pars;
262 p_port->mtu = p_port->keep_mtu;
263
264 p_port->state = PORT_STATE_OPENING;
265 p_port->rfc.p_mcb = NULL;
Andre Eisenbach072bd752016-03-18 02:09:58 -0700266 if (p_port->is_server)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800267 p_port->dlci &= 0xfe;
268
269 p_port->local_ctrl.modem_signal = p_port->default_signal_state;
270 memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
Andre Eisenbach072bd752016-03-18 02:09:58 -0700271 } else {
272 RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->inx);
Pavlin Radoslavov78bcff72015-12-04 17:36:34 -0800273 alarm_free(p_port->rfc.port_timer);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800274 memset (p_port, 0, sizeof (tPORT));
275 }
276 }
277}
278
The Android Open Source Project5738f832012-12-12 16:00:35 -0800279/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800280 *
281 * Function port_find_mcb
282 *
283 * Description This function checks if connection exists to device with
284 * the BD_ADDR.
285 *
286 ******************************************************************************/
The Android Open Source Project5738f832012-12-12 16:00:35 -0800287tRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
288{
289 int i;
290
291 for (i = 0; i < MAX_BD_CONNECTIONS; i++)
292 {
293 if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
294 && !memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN))
295 {
296 /* Multiplexer channel found do not change anything */
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700297 RFCOMM_TRACE_DEBUG("port_find_mcb: found bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
Matthew Xie9ac641d2013-01-15 15:54:03 -0800298 bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700299 RFCOMM_TRACE_DEBUG("port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d",
Matthew Xie9ac641d2013-01-15 15:54:03 -0800300 i, &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800301 return (&rfc_cb.port.rfc_mcb[i]);
302 }
303 }
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700304 RFCOMM_TRACE_DEBUG("port_find_mcb: not found, bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
Matthew Xie9ac641d2013-01-15 15:54:03 -0800305 bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800306 return (NULL);
307}
308
309
310/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800311 *
312 * Function port_find_mcb_dlci_port
313 *
314 * Description Find port on the multiplexer channel based on DLCI. If
315 * this port with DLCI not found try to use even DLCI. This
316 * is for the case when client is establishing connection on
317 * none-initiator MCB.
318 *
319 * Returns Pointer to the PORT or NULL if not found
320 *
321 ******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700322tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, uint8_t dlci)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800323{
Marie Janssend19e0782016-07-15 12:48:27 -0700324 uint8_t inx;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800325
326 if (!p_mcb)
327 return (NULL);
328
329 if (dlci > RFCOMM_MAX_DLCI)
330 return (NULL);
331
332 inx = p_mcb->port_inx[dlci];
333 if (inx == 0)
Matthew Xie9ac641d2013-01-15 15:54:03 -0800334 {
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700335 RFCOMM_TRACE_DEBUG("port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb, dlci);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800336 return (NULL);
Matthew Xie9ac641d2013-01-15 15:54:03 -0800337 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800338 else
339 return (&rfc_cb.port.port[inx - 1]);
340}
341
342
343/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800344 *
345 * Function port_find_dlci_port
346 *
347 * Description Find port with DLCI not assigned to multiplexer channel
348 *
349 * Returns Pointer to the PORT or NULL if not found
350 *
351 ******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700352tPORT *port_find_dlci_port (uint8_t dlci)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800353{
Marie Janssend19e0782016-07-15 12:48:27 -0700354 uint16_t i;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800355 tPORT *p_port;
356
357 for (i = 0; i < MAX_RFC_PORTS; i++)
358 {
359 p_port = &rfc_cb.port.port[i];
Matthew Xie9ac641d2013-01-15 15:54:03 -0800360
The Android Open Source Project5738f832012-12-12 16:00:35 -0800361 if (p_port->in_use && (p_port->rfc.p_mcb == NULL))
362 {
363 if (p_port->dlci == dlci)
364 {
365 return (p_port);
366 }
367 else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1)))
368 {
369 p_port->dlci++;
370 return (p_port);
371 }
372 }
373 }
374 return (NULL);
375}
376
377
378/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800379 *
380 * Function port_find_port
381 *
382 * Description Find port with DLCI, BD_ADDR
383 *
384 * Returns Pointer to the PORT or NULL if not found
385 *
386 ******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700387tPORT *port_find_port (uint8_t dlci, BD_ADDR bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800388{
Marie Janssend19e0782016-07-15 12:48:27 -0700389 uint16_t i;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800390 tPORT *p_port;
391
392 for (i = 0; i < MAX_RFC_PORTS; i++)
393 {
394 p_port = &rfc_cb.port.port[i];
395 if (p_port->in_use
396 && (p_port->dlci == dlci)
397 && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN))
398 {
399 return (p_port);
400 }
401 }
402 return (NULL);
403}
404
405
406/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800407 *
408 * Function port_flow_control_user
409 *
410 * Description Check the current user flow control and if necessary return
411 * events to be send to the user based on the user's specified
412 * flow control type.
413 *
414 * Returns event mask to be returned to the application
415 *
416 ******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700417uint32_t port_flow_control_user (tPORT *p_port)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800418{
Marie Janssend19e0782016-07-15 12:48:27 -0700419 uint32_t event = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800420
421 /* Flow control to the user can be caused by flow controlling by the peer */
422 /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
423 /* tx_queue is full */
Marie Janssend19e0782016-07-15 12:48:27 -0700424 bool fc = p_port->tx.peer_fc
The Android Open Source Project5738f832012-12-12 16:00:35 -0800425 || !p_port->rfc.p_mcb
426 || !p_port->rfc.p_mcb->peer_ready
427 || (p_port->tx.queue_size > PORT_TX_HIGH_WM)
Pavlin Radoslavov1a3844f2015-09-25 11:21:15 -0700428 || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800429
430 if (p_port->tx.user_fc == fc)
431 return (0);
432
433 p_port->tx.user_fc = fc;
434
435 if (fc)
436 event = PORT_EV_FC;
437 else
438 event = PORT_EV_FC | PORT_EV_FCS;
439
440 return (event);
441}
442
443
444/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800445 *
446 * Function port_get_signal_changes
447 *
448 * Description Check modem signals that has been changed
449 *
450 * Returns event mask to be returned to the application
451 *
452 ******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700453uint32_t port_get_signal_changes (tPORT *p_port, uint8_t old_signals, uint8_t signal)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800454{
Marie Janssend19e0782016-07-15 12:48:27 -0700455 uint8_t changed_signals = (signal ^ old_signals);
456 uint32_t events = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800457
458 if (changed_signals & PORT_DTRDSR_ON)
459 {
460 events |= PORT_EV_DSR;
461
462 if (signal & PORT_DTRDSR_ON)
463 events |= PORT_EV_DSRS;
464 }
465
466 if (changed_signals & PORT_CTSRTS_ON)
467 {
468 events |= PORT_EV_CTS;
469
470 if (signal & PORT_CTSRTS_ON)
471 events |= PORT_EV_CTSS;
472 }
473
474 if (changed_signals & PORT_RING_ON)
475 events |= PORT_EV_RING;
476
477 if (changed_signals & PORT_DCD_ON)
478 {
479 events |= PORT_EV_RLSD;
480
481 if (signal & PORT_DCD_ON)
482 events |= PORT_EV_RLSDS;
483 }
484
485 return (p_port->ev_mask & events);
486}
487
488/*******************************************************************************
Myles Watsonee96a3c2016-11-23 14:49:54 -0800489 *
490 * Function port_flow_control_peer
491 *
492 * Description Send flow control messages to the peer for both enabling
493 * and disabling flow control, for both credit-based and
494 * TS 07.10 flow control mechanisms.
495 *
496 * Returns nothing
497 *
498 ******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700499void port_flow_control_peer(tPORT *p_port, bool enable, uint16_t count)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800500{
501 if (!p_port->rfc.p_mcb)
502 return;
503
504 /* If using credit based flow control */
505 if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
506 {
507 /* if want to enable flow from peer */
508 if (enable)
509 {
510 /* update rx credits */
511 if (count > p_port->credit_rx)
512 {
513 p_port->credit_rx = 0;
514 }
515 else
516 {
517 p_port->credit_rx -= count;
518 }
519
520 /* If credit count is less than low credit watermark, and user */
521 /* did not force flow control, send a credit update */
522 /* There might be a special case when we just adjusted rx_max */
523 if ((p_port->credit_rx <= p_port->credit_rx_low)
524 && !p_port->rx.user_fc
525 && (p_port->credit_rx_max > p_port->credit_rx))
526 {
527 rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
Marie Janssend19e0782016-07-15 12:48:27 -0700528 (uint8_t) (p_port->credit_rx_max - p_port->credit_rx));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800529
530 p_port->credit_rx = p_port->credit_rx_max;
531
Marie Janssend19e0782016-07-15 12:48:27 -0700532 p_port->rx.peer_fc = false;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800533 }
534 }
535 /* else want to disable flow from peer */
536 else
537 {
538 /* if client registered data callback, just do what they want */
539 if (p_port->p_data_callback || p_port->p_data_co_callback)
540 {
Marie Janssend19e0782016-07-15 12:48:27 -0700541 p_port->rx.peer_fc = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800542 }
543 /* if queue count reached credit rx max, set peer fc */
Pavlin Radoslavov1a3844f2015-09-25 11:21:15 -0700544 else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800545 {
Marie Janssend19e0782016-07-15 12:48:27 -0700546 p_port->rx.peer_fc = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800547 }
548 }
549 }
550 /* else using TS 07.10 flow control */
551 else
552 {
553 /* if want to enable flow from peer */
554 if (enable)
555 {
556 /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
557 /* check if it can be resumed now */
558 if (p_port->rx.peer_fc
559 && (p_port->rx.queue_size < PORT_RX_LOW_WM)
Pavlin Radoslavov1a3844f2015-09-25 11:21:15 -0700560 && (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800561 {
Marie Janssend19e0782016-07-15 12:48:27 -0700562 p_port->rx.peer_fc = false;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800563
564 /* If user did not force flow control allow traffic now */
565 if (!p_port->rx.user_fc)
Marie Janssend19e0782016-07-15 12:48:27 -0700566 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, true);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800567 }
568 }
569 /* else want to disable flow from peer */
570 else
571 {
572 /* if client registered data callback, just do what they want */
573 if (p_port->p_data_callback || p_port->p_data_co_callback)
574 {
Marie Janssend19e0782016-07-15 12:48:27 -0700575 p_port->rx.peer_fc = true;
576 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, false);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800577 }
578 /* Check the size of the rx queue. If it exceeds certain */
579 /* level and flow control has not been sent to the peer do it now */
580 else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
Pavlin Radoslavov1a3844f2015-09-25 11:21:15 -0700581 || (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800582 && !p_port->rx.peer_fc)
583 {
Sharvil Nanavatid5bba902014-05-04 01:33:15 -0700584 RFCOMM_TRACE_EVENT ("PORT_DataInd Data reached HW. Sending FC set.");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800585
Marie Janssend19e0782016-07-15 12:48:27 -0700586 p_port->rx.peer_fc = true;
587 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, false);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800588 }
589 }
590 }
591}
592