summaryrefslogtreecommitdiffstats
path: root/stack/rfcomm/port_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'stack/rfcomm/port_api.c')
-rw-r--r--stack/rfcomm/port_api.c1730
1 files changed, 1730 insertions, 0 deletions
diff --git a/stack/rfcomm/port_api.c b/stack/rfcomm/port_api.c
new file mode 100644
index 0000000..617d31b
--- /dev/null
+++ b/stack/rfcomm/port_api.c
@@ -0,0 +1,1730 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the Serial Port API code
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "gki.h"
+#include "rfcdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "btm_int.h"
+#include "btm_api.h"
+#include "rfc_int.h"
+#include "l2c_api.h"
+#include "sdp_api.h"
+
+/* duration of break in 200ms units */
+#define PORT_BREAK_DURATION 1
+
+#include <cutils/log.h>
+#define info(fmt, ...) ALOGI ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define debug(fmt, ...) ALOGD ("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define error(fmt, ...) ALOGE ("## ERROR : %s: " fmt "##",__FUNCTION__, ## __VA_ARGS__)
+#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
+
+/*******************************************************************************
+**
+** Function RFCOMM_CreateConnection
+**
+** Description RFCOMM_CreateConnection function is used from the application
+** to establish serial port connection to the peer device,
+** or allow RFCOMM to accept a connection from the peer
+** application.
+**
+** Parameters: scn - Service Channel Number as registered with
+** the SDP (server) or obtained using SDP from
+** the peer device (client).
+** is_server - TRUE if requesting application is a server
+** mtu - Maximum frame size the application can accept
+** bd_addr - BD_ADDR of the peer (client)
+** mask - specifies events to be enabled. A value
+** of zero disables all events.
+** p_handle - OUT pointer to the handle.
+** p_mgmt_cb - pointer to callback function to receive
+** connection up/down events.
+** Notes:
+**
+** Server can call this function with the same scn parameter multiple times if
+** it is ready to accept multiple simulteneous connections.
+**
+** DLCI for the connection is (scn * 2 + 1) if client originates connection on
+** existing none initiator multiplexer channel. Otherwise it is (scn * 2).
+** For the server DLCI can be changed later if client will be calling it using
+** (scn * 2 + 1) dlci.
+**
+*******************************************************************************/
+int RFCOMM_CreateConnection (UINT16 uuid, UINT8 scn, BOOLEAN is_server,
+ UINT16 mtu, BD_ADDR bd_addr, UINT16 *p_handle,
+ tPORT_CALLBACK *p_mgmt_cb)
+{
+ tPORT *p_port;
+ int i;
+ UINT8 dlci;
+ tRFC_MCB *p_mcb = port_find_mcb (bd_addr);
+ UINT16 rfcomm_mtu;
+
+ RFCOMM_TRACE_API3 ("RFCOMM_CreateConnection() called SCN: %d is_server:%d mtu:%d",
+ scn, is_server, mtu);
+ RFCOMM_TRACE_API6 ("RFCOMM_CreateConnection() BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ *p_handle = 0;
+
+ if (( scn == 0 )||(scn >= PORT_MAX_RFC_PORTS ))
+ {
+ /* Server Channel Number(SCN) should be in range 1...30 */
+ RFCOMM_TRACE_ERROR0 ("RFCOMM_CreateConnection - invalid SCN");
+ return (PORT_INVALID_SCN);
+ }
+
+ /* For client that originate connection on the existing none initiator */
+ /* multiplexer channel DLCI should be odd */
+ if (p_mcb && !p_mcb->is_initiator && !is_server)
+ dlci = (scn << 1) + 1;
+ else
+ dlci = (scn << 1);
+
+ /* For the server side always allocate a new port. On the client side */
+ /* do not allow the same (dlci, bd_addr) to be opened twice by application */
+ if (!is_server && ((p_port = port_find_port (dlci, bd_addr)) != NULL))
+ {
+ /* if existing port is also a client port */
+ if (p_port->is_server == FALSE)
+ {
+ RFCOMM_TRACE_ERROR3 ("RFCOMM_CreateConnection - already opened state:%d, RFC state:%d, MCB state:%d",
+ p_port->state, p_port->rfc.state, p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0);
+ return (PORT_ALREADY_OPENED);
+ }
+ }
+
+ if ((p_port = port_allocate_port (dlci, bd_addr)) == NULL)
+ {
+ RFCOMM_TRACE_WARNING0 ("RFCOMM_CreateConnection - no resources");
+ return (PORT_NO_RESOURCES);
+ }
+
+ p_port->default_signal_state = (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ switch (uuid)
+ {
+ case UUID_PROTOCOL_OBEX:
+ p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_SERIAL_PORT:
+ p_port->default_signal_state = PORT_SPP_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_LAN_ACCESS_USING_PPP:
+ p_port->default_signal_state = PORT_PPP_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_DIALUP_NETWORKING:
+ case UUID_SERVCLASS_FAX:
+ p_port->default_signal_state = PORT_DUN_DEFAULT_SIGNAL_STATE;
+ break;
+ }
+
+ RFCOMM_TRACE_EVENT2 ("RFCOMM_CreateConnection dlci:%d signal state:0x%x", dlci, p_port->default_signal_state);
+
+ *p_handle = p_port->inx;
+
+ p_port->state = PORT_STATE_OPENING;
+ p_port->uuid = uuid;
+ p_port->is_server = is_server;
+ p_port->scn = scn;
+ p_port->ev_mask = 0;
+
+ /* If the MTU is not specified (0), keep MTU decision until the
+ * PN frame has to be send
+ * at that time connection should be established and we
+ * will know for sure our prefered MTU
+ */
+
+ rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+
+ if (mtu)
+ p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
+ else
+ p_port->mtu = rfcomm_mtu;
+
+ /* server doesn't need to release port when closing */
+ if( is_server )
+ {
+ p_port->keep_port_handle = TRUE;
+
+ /* keep mtu that user asked, p_port->mtu could be updated during param negotiation */
+ p_port->keep_mtu = p_port->mtu;
+ }
+
+ p_port->local_ctrl.modem_signal = p_port->default_signal_state;
+ p_port->local_ctrl.fc = FALSE;
+
+ p_port->p_mgmt_callback = p_mgmt_cb;
+
+ for (i = 0; i < BD_ADDR_LEN; i++)
+ p_port->bd_addr[i] = bd_addr[i];
+
+ /* If this is not initiator of the connection need to just wait */
+ if (p_port->is_server)
+ {
+ return (PORT_SUCCESS);
+ }
+
+ /* Open will be continued after security checks are passed */
+ return port_open_continue (p_port);
+}
+
+
+/*******************************************************************************
+**
+** Function RFCOMM_RemoveConnection
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int RFCOMM_RemoveConnection (UINT16 handle)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("RFCOMM_RemoveConnection() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_RemoveConnection() BAD handle:%d", handle);
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_EVENT1 ("RFCOMM_RemoveConnection() Not opened:%d", handle);
+ return (PORT_SUCCESS);
+ }
+
+ p_port->state = PORT_STATE_CLOSING;
+
+ port_start_close (p_port);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function RFCOMM_RemoveServer
+**
+** Description This function is called to close the server port.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+**
+*******************************************************************************/
+int RFCOMM_RemoveServer (UINT16 handle)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("RFCOMM_RemoveServer() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ RFCOMM_TRACE_ERROR1 ("RFCOMM_RemoveServer() BAD handle:%d", handle);
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ /* Do not report any events to the client any more. */
+ p_port->p_mgmt_callback = NULL;
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_EVENT1 ("RFCOMM_RemoveServer() Not opened:%d", handle);
+ return (PORT_SUCCESS);
+ }
+
+ /* this port will be deallocated after closing */
+ p_port->keep_port_handle = FALSE;
+ p_port->state = PORT_STATE_CLOSING;
+
+ port_start_close (p_port);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetEventCallback
+**
+** Description This function is called to provide an address of the
+** function which will be called when one of the events
+** specified in the mask occures.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when an event
+** specified in the mask occures.
+**
+**
+*******************************************************************************/
+int PORT_SetEventCallback (UINT16 port_handle, tPORT_CALLBACK *p_port_cb)
+{
+ tPORT *p_port;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ RFCOMM_TRACE_API1 ("PORT_SetEventCallback() handle:%d", port_handle);
+
+ p_port->p_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_SetDataCallback
+**
+** Description This function is when a data packet is received
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when data packet
+** is received.
+**
+**
+*******************************************************************************/
+int PORT_SetDataCallback (UINT16 port_handle, tPORT_DATA_CALLBACK *p_port_cb)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SetDataCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->p_data_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function PORT_SetCODataCallback
+**
+** Description This function is when a data packet is received
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_callback - address of the callback function which should
+** be called from the RFCOMM when data packet
+** is received.
+**
+**
+*******************************************************************************/
+int PORT_SetDataCOCallback (UINT16 port_handle, tPORT_DATA_CO_CALLBACK *p_port_cb)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SetDataCOCallback() handle:%d cb 0x%x", port_handle, p_port_cb);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->p_data_co_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function PORT_SetEventMask
+**
+** Description This function is called to close the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** mask - Bitmask of the events the host is interested in
+**
+*******************************************************************************/
+int PORT_SetEventMask (UINT16 port_handle, UINT32 mask)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SetEventMask() handle:%d mask:0x%x", port_handle, mask);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->ev_mask = mask;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_CheckConnection
+**
+** Description This function returns PORT_SUCCESS if connection referenced
+** by handle is up and running
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** bd_addr - OUT bd_addr of the peer
+** p_lcid - OUT L2CAP's LCID
+**
+*******************************************************************************/
+int PORT_CheckConnection (UINT16 handle, BD_ADDR bd_addr, UINT16 *p_lcid)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_CheckConnection() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb
+ || !p_port->rfc.p_mcb->peer_ready
+ || (p_port->rfc.state != RFC_STATE_OPENED))
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ memcpy (bd_addr, p_port->rfc.p_mcb->bd_addr, BD_ADDR_LEN);
+ if (p_lcid)
+ *p_lcid = p_port->rfc.p_mcb->lcid;
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_IsOpening
+**
+** Description This function returns TRUE if there is any RFCOMM connection
+** opening in process.
+**
+** Parameters: TRUE if any connection opening is found
+** bd_addr - bd_addr of the peer
+**
+*******************************************************************************/
+BOOLEAN PORT_IsOpening (BD_ADDR bd_addr)
+{
+ UINT8 xx, yy;
+ tRFC_MCB *p_mcb = NULL;
+ tPORT *p_port;
+ BOOLEAN found_port;
+
+ /* Check for any rfc_mcb which is in the middle of opening. */
+ for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++)
+ {
+ if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) &&
+ (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED))
+ {
+ memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+ return TRUE;
+ }
+
+ if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED)
+ {
+ found_port = FALSE;
+ p_mcb = &rfc_cb.port.rfc_mcb[xx];
+ p_port = &rfc_cb.port.port[0];
+
+ for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++)
+ {
+ if (p_port->rfc.p_mcb == p_mcb)
+ {
+ found_port = TRUE;
+ break;
+ }
+ }
+
+ if ((!found_port) ||
+ (found_port && (p_port->rfc.state < RFC_STATE_OPENED)))
+ {
+ /* Port is not established yet. */
+ memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetState
+**
+** Description This function configures connection according to the
+** specifications in the tPORT_STATE structure.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_settings - Pointer to a tPORT_STATE structure containing
+** configuration information for the connection.
+**
+**
+*******************************************************************************/
+int PORT_SetState (UINT16 handle, tPORT_STATE *p_settings)
+{
+ tPORT *p_port;
+ UINT8 baud_rate;
+
+ RFCOMM_TRACE_API1 ("PORT_SetState() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ RFCOMM_TRACE_API2 ("PORT_SetState() handle:%d FC_TYPE:0x%x", handle,
+ p_settings->fc_type);
+
+ baud_rate = p_port->user_port_pars.baud_rate;
+ p_port->user_port_pars = *p_settings;
+
+ /* for now we've been asked to pass only baud rate */
+ if (baud_rate != p_settings->baud_rate)
+ {
+ port_start_par_neg (p_port);
+ }
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_GetRxQueueCnt
+**
+** Description This function return number of buffers on the rx queue.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_rx_queue_count - Pointer to return queue count in.
+**
+*******************************************************************************/
+int PORT_GetRxQueueCnt (UINT16 handle, UINT16 *p_rx_queue_count)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_GetRxQueueCnt() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ *p_rx_queue_count = p_port->rx.queue_size;
+
+ RFCOMM_TRACE_API2 ("PORT_GetRxQueueCnt() p_rx_queue_count:%d, p_port->rx.queue.count = %d",
+ *p_rx_queue_count, p_port->rx.queue_size);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+**
+** Function PORT_GetState
+**
+** Description This function is called to fill tPORT_STATE structure
+** with the curremt control settings for the port
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_settings - Pointer to a tPORT_STATE structure in which
+** configuration information is returned.
+**
+*******************************************************************************/
+int PORT_GetState (UINT16 handle, tPORT_STATE *p_settings)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_GetState() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ *p_settings = p_port->user_port_pars;
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Control
+**
+** Description This function directs a specified connection to pass control
+** control information to the peer device.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** signal = specify the function to be passed
+**
+*******************************************************************************/
+int PORT_Control (UINT16 handle, UINT8 signal)
+{
+ tPORT *p_port;
+ UINT8 old_modem_signal;
+
+ RFCOMM_TRACE_API2 ("PORT_Control() handle:%d signal:0x%x", handle, signal);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ old_modem_signal = p_port->local_ctrl.modem_signal;
+ p_port->local_ctrl.break_signal = 0;
+
+ switch (signal)
+ {
+ case PORT_SET_CTSRTS:
+ p_port->local_ctrl.modem_signal |= PORT_CTSRTS_ON;
+ break;
+
+ case PORT_CLR_CTSRTS:
+ p_port->local_ctrl.modem_signal &= ~PORT_CTSRTS_ON;
+ break;
+
+ case PORT_SET_DTRDSR:
+ p_port->local_ctrl.modem_signal |= PORT_DTRDSR_ON;
+ break;
+
+ case PORT_CLR_DTRDSR:
+ p_port->local_ctrl.modem_signal &= ~PORT_DTRDSR_ON;
+ break;
+
+ case PORT_SET_RI:
+ p_port->local_ctrl.modem_signal |= PORT_RING_ON;
+ break;
+
+ case PORT_CLR_RI:
+ p_port->local_ctrl.modem_signal &= ~PORT_RING_ON;
+ break;
+
+ case PORT_SET_DCD:
+ p_port->local_ctrl.modem_signal |= PORT_DCD_ON;
+ break;
+
+ case PORT_CLR_DCD:
+ p_port->local_ctrl.modem_signal &= ~PORT_DCD_ON;
+ break;
+ }
+
+ if (signal == PORT_BREAK)
+ p_port->local_ctrl.break_signal = PORT_BREAK_DURATION;
+ else if (p_port->local_ctrl.modem_signal == old_modem_signal)
+ return (PORT_SUCCESS);
+
+ port_start_control (p_port);
+
+ RFCOMM_TRACE_EVENT4 ("PORT_Control DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_FlowControl
+**
+** Description This function directs a specified connection to pass
+** flow control message to the peer device. Enable flag passed
+** shows if port can accept more data.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** enable - enables data flow
+**
+*******************************************************************************/
+int PORT_FlowControl (UINT16 handle, BOOLEAN enable)
+{
+ tPORT *p_port;
+ BOOLEAN old_fc;
+ UINT32 events;
+
+ RFCOMM_TRACE_API2 ("PORT_FlowControl() handle:%d enable: %d", handle, enable);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb)
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->rx.user_fc = !enable;
+
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+ {
+ if (!p_port->rx.user_fc)
+ {
+ port_flow_control_peer(p_port, TRUE, 0);
+ }
+ }
+ else
+ {
+ old_fc = p_port->local_ctrl.fc;
+
+ /* FC is set if user is set or peer is set */
+ p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
+
+ if (p_port->local_ctrl.fc != old_fc)
+ port_start_control (p_port);
+ }
+
+ /* Need to take care of the case when we could not deliver events */
+ /* to the application because we were flow controlled */
+ if (enable && (p_port->rx.queue_size != 0))
+ {
+ events = PORT_EV_RXCHAR;
+ if (p_port->rx_flag_ev_pending)
+ {
+ p_port->rx_flag_ev_pending = FALSE;
+ events |= PORT_EV_RXFLAG;
+ }
+
+ events &= p_port->ev_mask;
+ if (p_port->p_callback && events)
+ {
+ p_port->p_callback (events, p_port->inx);
+ }
+ }
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_GetModemStatus
+**
+** Description This function retrieves modem control signals. Normally
+** application will call this function after a callback
+** function is called with notification that one of signals
+** has been changed.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_signal - specify the pointer to control signals info
+**
+*******************************************************************************/
+int PORT_GetModemStatus (UINT16 handle, UINT8 *p_signal)
+{
+ tPORT *p_port;
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ *p_signal = p_port->peer_ctrl.modem_signal;
+
+ RFCOMM_TRACE_API2 ("PORT_GetModemStatus() handle:%d signal:%x", handle, *p_signal);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ClearError
+**
+** Description This function retreives information about a communications
+** error and reports current status of a connection. The
+** function should be called when an error occures to clear
+** the connection error flag and to enable additional read
+** and write operations.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_errors - pointer of the variable to receive error codes
+** p_status - pointer to the tPORT_STATUS structur to receive
+** connection status
+**
+*******************************************************************************/
+int PORT_ClearError (UINT16 handle, UINT16 *p_errors, tPORT_STATUS *p_status)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_ClearError() handle:%d", handle);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ *p_errors = p_port->line_status;
+
+ /* This is the only call to clear error status. We can not clear */
+ /* connection failed status. To clean it port should be closed and reopened */
+ p_port->line_status = (p_port->line_status & LINE_STATUS_FAILED);
+
+ PORT_GetQueueStatus (handle, p_status);
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_SendError
+**
+** Description This function send a communications error to the peer device
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** errors - receive error codes
+**
+*******************************************************************************/
+int PORT_SendError (UINT16 handle, UINT8 errors)
+{
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API2 ("PORT_SendError() handle:%d errors:0x%x", handle, errors);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb)
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ RFCOMM_LineStatusReq (p_port->rfc.p_mcb, p_port->dlci, errors);
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_GetQueueStatus
+**
+** Description This function reports current status of a connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_status - pointer to the tPORT_STATUS structur to receive
+** connection status
+**
+*******************************************************************************/
+int PORT_GetQueueStatus (UINT16 handle, tPORT_STATUS *p_status)
+{
+ tPORT *p_port;
+
+ /* RFCOMM_TRACE_API1 ("PORT_GetQueueStatus() handle:%d", handle); */
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_status->in_queue_size = (UINT16) p_port->rx.queue_size;
+ p_status->out_queue_size = (UINT16) p_port->tx.queue_size;
+
+ p_status->mtu_size = (UINT16) p_port->peer_mtu;
+
+ p_status->flags = 0;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_CTSRTS_ON))
+ p_status->flags |= PORT_FLAG_CTS_HOLD;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_DTRDSR_ON))
+ p_status->flags |= PORT_FLAG_DSR_HOLD;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_DCD_ON))
+ p_status->flags |= PORT_FLAG_RLSD_HOLD;
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Purge
+**
+** Description This function discards all the data from the output or
+** input queues of the specified connection.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** purge_flags - specify the action to take.
+**
+*******************************************************************************/
+int PORT_Purge (UINT16 handle, UINT8 purge_flags)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT16 count;
+ UINT32 events;
+
+ RFCOMM_TRACE_API2 ("PORT_Purge() handle:%d flags:0x%x", handle, purge_flags);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (purge_flags & PORT_PURGE_RXCLEAR)
+ {
+ PORT_SCHEDULE_LOCK; /* to prevent missing credit */
+
+ count = p_port->rx.queue.count;
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->rx.queue_size = 0;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ /* If we flowed controlled peer based on rx_queue size enable data again */
+ if (count)
+ port_flow_control_peer (p_port, TRUE, count);
+ }
+
+ if (purge_flags & PORT_PURGE_TXCLEAR)
+ {
+ PORT_SCHEDULE_LOCK; /* to prevent tx.queue_size from being negative */
+
+ while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
+ GKI_freebuf (p_buf);
+
+ p_port->tx.queue_size = 0;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ events = PORT_EV_TXEMPTY;
+
+ events |= port_flow_control_user (p_port);
+
+ events &= p_port->ev_mask;
+
+ if ((p_port->p_callback != NULL) && events)
+ (p_port->p_callback)(events, p_port->inx);
+ }
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_ReadData
+**
+** Description Normally not GKI aware application will call this function
+** after receiving PORT_EV_RXCHAR event.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+*******************************************************************************/
+int PORT_ReadData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT16 count;
+
+ RFCOMM_TRACE_API2 ("PORT_ReadData() handle:%d max_len:%d", handle, max_len);
+
+ /* Initialize this in case of an error */
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ p_buf = (BT_HDR *)GKI_getfirst (&p_port->rx.queue);
+ if (!p_buf)
+ return (PORT_SUCCESS);
+
+ count = 0;
+
+ while (max_len && p_buf)
+ {
+ if (p_buf->len > max_len)
+ {
+ memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, max_len);
+ p_buf->offset += max_len;
+ p_buf->len -= max_len;
+
+ *p_len += max_len;
+
+ PORT_SCHEDULE_LOCK;
+
+ p_port->rx.queue_size -= max_len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ break;
+ }
+ else
+ {
+ memcpy (p_data, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ *p_len += p_buf->len;
+ max_len -= p_buf->len;
+
+ PORT_SCHEDULE_LOCK;
+
+ p_port->rx.queue_size -= p_buf->len;
+
+ if (max_len)
+ {
+ p_data += p_buf->len;
+ p_buf = (BT_HDR *)GKI_getnext (p_buf);
+ }
+
+ GKI_freebuf (GKI_dequeue (&p_port->rx.queue));
+
+ PORT_SCHEDULE_UNLOCK;
+
+ count++;
+ }
+ }
+
+ if (*p_len == 1)
+ {
+ RFCOMM_TRACE_EVENT3 ("PORT_ReadData queue:%d returned:%d %x", p_port->rx.queue_size, *p_len, (p_data[0]));
+ }
+ else
+ {
+ RFCOMM_TRACE_EVENT2 ("PORT_ReadData queue:%d returned:%d", p_port->rx.queue_size, *p_len);
+ }
+
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ port_flow_control_peer (p_port, TRUE, count);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Read
+**
+** Description Normally application will call this function after receiving
+** PORT_EV_RXCHAR event.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** pp_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+int PORT_Read (UINT16 handle, BT_HDR **pp_buf)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+
+ RFCOMM_TRACE_API1 ("PORT_Read() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ return (PORT_LINE_ERR);
+ }
+
+ PORT_SCHEDULE_LOCK;
+
+ p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue);
+ if (p_buf)
+ {
+ p_port->rx.queue_size -= p_buf->len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ port_flow_control_peer (p_port, TRUE, 1);
+ }
+ else
+ {
+ PORT_SCHEDULE_UNLOCK;
+ }
+
+ *pp_buf = p_buf;
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function port_write
+**
+** Description This function when a data packet is received from the apper
+** layer task.
+**
+** Parameters: p_port - pointer to address of port control block
+** p_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+static int port_write (tPORT *p_port, BT_HDR *p_buf)
+{
+ /* We should not allow to write data in to server port when connection is not opened */
+ if (p_port->is_server && (p_port->rfc.state != RFC_STATE_OPENED))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_CLOSED);
+ }
+
+ /* Keep the data in pending queue if peer does not allow data, or */
+ /* Peer is not ready or Port is not yet opened or initial port control */
+ /* command has not been sent */
+ if (p_port->tx.peer_fc
+ || !p_port->rfc.p_mcb
+ || !p_port->rfc.p_mcb->peer_ready
+ || (p_port->rfc.state != RFC_STATE_OPENED)
+ || ((p_port->port_ctrl & (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)) !=
+ (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)))
+ {
+ if ((p_port->tx.queue_size > PORT_TX_CRITICAL_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_CRITICAL_WM))
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_Write: Queue size: %d",
+ p_port->tx.queue_size);
+
+ GKI_freebuf (p_buf);
+
+ if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR))
+ p_port->p_callback (PORT_EV_ERR, p_port->inx);
+
+ return (PORT_TX_FULL);
+ }
+
+ RFCOMM_TRACE_EVENT4 ("PORT_Write : Data is enqued. flow disabled %d peer_ready %d state %d ctrl_state %x",
+ p_port->tx.peer_fc,
+ (p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready),
+ p_port->rfc.state,
+ p_port->port_ctrl);
+
+ GKI_enqueue (&p_port->tx.queue, p_buf);
+ p_port->tx.queue_size += p_buf->len;
+
+ return (PORT_CMD_PENDING);
+ }
+ else
+ {
+ RFCOMM_TRACE_EVENT0 ("PORT_Write : Data is being sent");
+
+ RFCOMM_DataReq (p_port->rfc.p_mcb, p_port->dlci, p_buf);
+ return (PORT_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+**
+** Function PORT_Write
+**
+** Description This function when a data packet is received from the apper
+** layer task.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** pp_buf - pointer to address of buffer with data,
+**
+*******************************************************************************/
+int PORT_Write (UINT16 handle, BT_HDR *p_buf)
+{
+ tPORT *p_port;
+ UINT32 event = 0;
+ int rc;
+
+ RFCOMM_TRACE_API1 ("PORT_Write() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ GKI_freebuf (p_buf);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status)
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_Write: Data dropped line_status:0x%x",
+ p_port->line_status);
+ GKI_freebuf (p_buf);
+ return (PORT_LINE_ERR);
+ }
+
+ rc = port_write (p_port, p_buf);
+ event |= port_flow_control_user (p_port);
+
+ switch (rc)
+ {
+ case PORT_TX_FULL:
+ event |= PORT_EV_ERR;
+ break;
+
+ case PORT_SUCCESS:
+ event |= (PORT_EV_TXCHAR | PORT_EV_TXEMPTY);
+ break;
+ }
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event)
+ (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+/*******************************************************************************
+**
+** Function PORT_WriteDataCO
+**
+** Description Normally not GKI aware application will call this function
+** to send data to the port by callout functions
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** fd - socket fd
+** p_len - Byte count returned
+**
+*******************************************************************************/
+int PORT_WriteDataCO (UINT16 handle, int* p_len)
+{
+
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT32 event = 0;
+ int rc = 0;
+ UINT16 length;
+
+ RFCOMM_TRACE_API1 ("PORT_WriteDataCO() handle:%d", handle);
+ int written;
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_WriteDataByFd() no port state:%d", p_port->state);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->peer_mtu)
+ {
+ RFCOMM_TRACE_ERROR1 ("PORT_WriteDataByFd() peer_mtu:%d", p_port->peer_mtu);
+ return (PORT_UNKNOWN_ERROR);
+ }
+ int available = 0;
+ //if(ioctl(fd, FIONREAD, &available) < 0)
+ if(p_port->p_data_co_callback(handle, (UINT8*)&available, sizeof(available),
+ DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE) == FALSE)
+ {
+ RFCOMM_TRACE_ERROR1("p_data_co_callback DATA_CO_CALLBACK_TYPE_INCOMING_SIZE failed, available:%d", available);
+ return (PORT_UNKNOWN_ERROR);
+ }
+ /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */
+ length = RFCOMM_DATA_POOL_BUF_SIZE -
+ (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+ /* If there are buffers scheduled for transmission check if requested */
+ /* data fits into the end of the queue */
+ PORT_SCHEDULE_LOCK;
+
+ if (((p_buf = (BT_HDR *)p_port->tx.queue.p_last) != NULL)
+ && (((int)p_buf->len + available) <= (int)p_port->peer_mtu)
+ && (((int)p_buf->len + available) <= (int)length))
+ {
+ //if(recv(fd, (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, available, 0) != available)
+ if(p_port->p_data_co_callback(handle, (UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len,
+ available, DATA_CO_CALLBACK_TYPE_OUTGOING) == FALSE)
+
+ {
+ error("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, available:%d", available);
+ return (PORT_UNKNOWN_ERROR);
+ }
+ //memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+ p_port->tx.queue_size += (UINT16)available;
+
+ *p_len = available;
+ p_buf->len += (UINT16)available;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ return (PORT_SUCCESS);
+ }
+
+ PORT_SCHEDULE_UNLOCK;
+
+ //int max_read = length < p_port->peer_mtu ? length : p_port->peer_mtu;
+
+ //max_read = available < max_read ? available : max_read;
+
+ while (available)
+ {
+ /* if we're over buffer high water mark, we're done */
+ if ((p_port->tx.queue_size > PORT_TX_HIGH_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM))
+ break;
+
+ /* continue with rfcomm data write */
+ p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_DATA_POOL_ID);
+ if (!p_buf)
+ break;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+ p_buf->layer_specific = handle;
+
+ if (p_port->peer_mtu < length)
+ length = p_port->peer_mtu;
+ if (available < (int)length)
+ length = (UINT16)available;
+ p_buf->len = length;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ //memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length);
+ //if(recv(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, (int)length, 0) != (int)length)
+ if(p_port->p_data_co_callback(handle, (UINT8 *)(p_buf + 1) + p_buf->offset, length,
+ DATA_CO_CALLBACK_TYPE_OUTGOING) == FALSE)
+ {
+ error("p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, length:%d", length);
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+
+ RFCOMM_TRACE_EVENT1 ("PORT_WriteData %d bytes", length);
+
+ rc = port_write (p_port, p_buf);
+
+ /* If queue went below the threashold need to send flow control */
+ event |= port_flow_control_user (p_port);
+
+ if (rc == PORT_SUCCESS)
+ event |= PORT_EV_TXCHAR;
+
+ if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING))
+ break;
+
+ *p_len += length;
+ available -= (int)length;
+ }
+ if (!available && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+ event |= PORT_EV_TXEMPTY;
+
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event)
+ (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+
+
+
+/*******************************************************************************
+**
+** Function PORT_WriteData
+**
+** Description Normally not GKI aware application will call this function
+** to send data to the port.
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+** p_len - Byte count received
+**
+*******************************************************************************/
+int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len)
+{
+ tPORT *p_port;
+ BT_HDR *p_buf;
+ UINT32 event = 0;
+ int rc = 0;
+ UINT16 length;
+
+ RFCOMM_TRACE_API1 ("PORT_WriteData() max_len:%d", max_len);
+
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ RFCOMM_TRACE_WARNING1 ("PORT_WriteData() no port state:%d", p_port->state);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!max_len || !p_port->peer_mtu)
+ {
+ RFCOMM_TRACE_ERROR1 ("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu);
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */
+ length = RFCOMM_DATA_POOL_BUF_SIZE -
+ (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+ /* If there are buffers scheduled for transmission check if requested */
+ /* data fits into the end of the queue */
+ PORT_SCHEDULE_LOCK;
+
+ if (((p_buf = (BT_HDR *)p_port->tx.queue.p_last) != NULL)
+ && ((p_buf->len + max_len) <= p_port->peer_mtu)
+ && ((p_buf->len + max_len) <= length))
+ {
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+ p_port->tx.queue_size += max_len;
+
+ *p_len = max_len;
+ p_buf->len += max_len;
+
+ PORT_SCHEDULE_UNLOCK;
+
+ return (PORT_SUCCESS);
+ }
+
+ PORT_SCHEDULE_UNLOCK;
+
+ while (max_len)
+ {
+ /* if we're over buffer high water mark, we're done */
+ if ((p_port->tx.queue_size > PORT_TX_HIGH_WM)
+ || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM))
+ break;
+
+ /* continue with rfcomm data write */
+ p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_DATA_POOL_ID);
+ if (!p_buf)
+ break;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+ p_buf->layer_specific = handle;
+
+ if (p_port->peer_mtu < length)
+ length = p_port->peer_mtu;
+ if (max_len < length)
+ length = max_len;
+ p_buf->len = length;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, length);
+
+ RFCOMM_TRACE_EVENT1 ("PORT_WriteData %d bytes", length);
+
+ rc = port_write (p_port, p_buf);
+
+ /* If queue went below the threashold need to send flow control */
+ event |= port_flow_control_user (p_port);
+
+ if (rc == PORT_SUCCESS)
+ event |= PORT_EV_TXCHAR;
+
+ if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING))
+ break;
+
+ *p_len += length;
+ max_len -= length;
+ p_data += length;
+
+ }
+ if (!max_len && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+ event |= PORT_EV_TXEMPTY;
+
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event)
+ (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+
+
+/*******************************************************************************
+**
+** Function PORT_Test
+**
+** Description Application can call this function to send RFCOMM Test frame
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** p_data - Data area
+** max_len - Byte count requested
+**
+*******************************************************************************/
+int PORT_Test (UINT16 handle, UINT8 *p_data, UINT16 len)
+{
+ BT_HDR *p_buf;
+ tPORT *p_port;
+
+ RFCOMM_TRACE_API1 ("PORT_Test() len:%d", len);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (len > ((p_port->mtu == 0) ? RFCOMM_DEFAULT_MTU : p_port->mtu))
+ {
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ if ((p_buf = (BT_HDR *)GKI_getpoolbuf (RFCOMM_CMD_POOL_ID)) != NULL)
+ {
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
+ p_buf->len = len;
+
+ memcpy ((UINT8 *)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+ rfc_send_test (p_port->rfc.p_mcb, TRUE, p_buf);
+ return (PORT_SUCCESS);
+ }
+ else
+ {
+ return (PORT_NO_MEM);
+ }
+}
+
+/*******************************************************************************
+**
+** Function RFCOMM_Init
+**
+** Description This function is called to initialize RFCOMM layer
+**
+*******************************************************************************/
+void RFCOMM_Init (void)
+{
+ memset (&rfc_cb, 0, sizeof (tRFC_CB)); /* Init RFCOMM control block */
+
+ rfc_cb.rfc.last_mux = MAX_BD_CONNECTIONS;
+
+#if defined(RFCOMM_INITIAL_TRACE_LEVEL)
+ rfc_cb.trace_level = RFCOMM_INITIAL_TRACE_LEVEL;
+#else
+ rfc_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ rfcomm_l2cap_if_init ();
+}
+
+/*******************************************************************************
+**
+** Function PORT_SetTraceLevel
+**
+** Description This function sets the trace level for RFCOMM. If called with
+** a value of 0xFF, it simply reads the current trace level.
+**
+** Returns the new (current) trace level
+**
+*******************************************************************************/
+UINT8 PORT_SetTraceLevel (UINT8 new_level)
+{
+ if (new_level != 0xFF)
+ rfc_cb.trace_level = new_level;
+
+ return (rfc_cb.trace_level);
+}
+