/****************************************************************************** * * 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 #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 #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); }