diff options
Diffstat (limited to 'bta/ag/bta_ag_rfc.c')
-rw-r--r-- | bta/ag/bta_ag_rfc.c | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/bta/ag/bta_ag_rfc.c b/bta/ag/bta_ag_rfc.c new file mode 100644 index 0000000..3575020 --- /dev/null +++ b/bta/ag/bta_ag_rfc.c @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * Copyright (C) 2004-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 audio gateway functions controlling the RFCOMM + * connections. + * + ******************************************************************************/ + +#include <string.h> +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_ag_api.h" +#include "bta_ag_int.h" +#include "bta_ag_co.h" +#include "btm_api.h" +#include "port_api.h" +#include "rfcdefs.h" +#include "gki.h" +#include "bd.h" + +/* Event mask for RfCOMM port callback */ +#define BTA_AG_PORT_EV_MASK PORT_EV_RXCHAR + +/* each scb has its own rfcomm callbacks */ +void bta_ag_port_cback_1(UINT32 code, UINT16 port_handle); +void bta_ag_port_cback_2(UINT32 code, UINT16 port_handle); +void bta_ag_port_cback_3(UINT32 code, UINT16 port_handle); + +void bta_ag_mgmt_cback_1(UINT32 code, UINT16 port_handle); +void bta_ag_mgmt_cback_2(UINT32 code, UINT16 port_handle); +void bta_ag_mgmt_cback_3(UINT32 code, UINT16 port_handle); + +int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len); +int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len); +int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len); + +/* rfcomm callback function tables */ +typedef tPORT_CALLBACK *tBTA_AG_PORT_CBACK; +const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] = +{ + bta_ag_port_cback_1, + bta_ag_port_cback_2, + bta_ag_port_cback_3 +}; + +const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] = +{ + bta_ag_mgmt_cback_1, + bta_ag_mgmt_cback_2, + bta_ag_mgmt_cback_3 +}; + +typedef tPORT_DATA_CALLBACK *tBTA_AG_DATA_CBACK; +const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] = +{ + bta_ag_data_cback_1, + bta_ag_data_cback_2, + bta_ag_data_cback_3 +}; + +/******************************************************************************* +** +** Function bta_ag_port_cback +** +** Description RFCOMM Port callback +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_port_cback(UINT32 code, UINT16 port_handle, UINT16 handle) +{ + BT_HDR *p_buf; + tBTA_AG_SCB *p_scb; + + if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) + { + /* ignore port events for port handles other than connected handle */ + if (port_handle != p_scb->conn_handle) + { + APPL_TRACE_DEBUG3("ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d", + port_handle, p_scb->conn_handle, handle); + return; + } + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) + { + p_buf->event = BTA_AG_RFC_DATA_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } + } +} + +/******************************************************************************* +** +** Function bta_ag_mgmt_cback +** +** Description RFCOMM management callback +** +** +** Returns void +** +*******************************************************************************/ +static void bta_ag_mgmt_cback(UINT32 code, UINT16 port_handle, UINT16 handle) +{ + tBTA_AG_RFC *p_buf; + tBTA_AG_SCB *p_scb; + UINT16 event; + UINT8 i; + BOOLEAN found_handle = FALSE; + + APPL_TRACE_DEBUG3("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d", + code, port_handle, handle); + + if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) + { + /* ignore close event for port handles other than connected handle */ + if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) + { + APPL_TRACE_DEBUG1("ag_mgmt_cback ignoring handle:%d", port_handle); + return; + } + + if (code == PORT_SUCCESS) + { + if (p_scb->conn_handle) /* Outgoing connection */ + { + if (port_handle == p_scb->conn_handle) + found_handle = TRUE; + } + else /* Incoming connection */ + { + for (i = 0; i < BTA_AG_NUM_IDX; i++) + { + if (port_handle == p_scb->serv_handle[i]) + found_handle = TRUE; + } + } + + if (!found_handle) + { + APPL_TRACE_ERROR1 ("bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle); + return; + } + + event = BTA_AG_RFC_OPEN_EVT; + } + /* distinguish server close events */ + else if (port_handle == p_scb->conn_handle) + { + event = BTA_AG_RFC_CLOSE_EVT; + } + else + { + event = BTA_AG_RFC_SRV_CLOSE_EVT; + } + + if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL) + { + p_buf->hdr.event = event; + p_buf->hdr.layer_specific = handle; + p_buf->port_handle = port_handle; + bta_sys_sendmsg(p_buf); + } + } +} + +/******************************************************************************* +** +** Function bta_ag_data_cback +** +** Description RFCOMM data callback +** +** +** Returns void +** +*******************************************************************************/ +static int bta_ag_data_cback(UINT16 port_handle, void *p_data, UINT16 len, UINT16 handle) +{ + /* call data call-out directly */ + bta_ag_co_tx_write(handle, (UINT8 *) p_data, len); + return 0; +} + +/******************************************************************************* +** +** Function bta_ag_port_cback_1 to 3 +** bta_ag_mgmt_cback_1 to 3 +** +** Description RFCOMM callback functions. This is an easy way to +** distinguish scb from the callback. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_mgmt_cback_1(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 1);} +void bta_ag_mgmt_cback_2(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 2);} +void bta_ag_mgmt_cback_3(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 3);} +void bta_ag_port_cback_1(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 1);} +void bta_ag_port_cback_2(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 2);} +void bta_ag_port_cback_3(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 3);} + +/******************************************************************************* +** +** Function bta_ag_data_cback_1 to 3 +** +** Description RFCOMM data callback functions. This is an easy way to +** distinguish scb from the callback. +** +** +** Returns void +** +*******************************************************************************/ +int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len) +{ + return bta_ag_data_cback(port_handle, p_data, len, 1); +} +int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len) +{ + return bta_ag_data_cback(port_handle, p_data, len, 2); +} +int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len) +{ + return bta_ag_data_cback(port_handle, p_data, len, 3); +} + +/******************************************************************************* +** +** Function bta_ag_setup_port +** +** Description Setup RFCOMM port for use by AG. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_setup_port(tBTA_AG_SCB *p_scb, UINT16 handle) +{ + UINT16 i = bta_ag_scb_to_idx(p_scb) - 1; + + /* set up data callback if using pass through mode */ + if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) + { + PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]); + } + + PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK); + PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]); +} + +/******************************************************************************* +** +** Function bta_ag_start_servers +** +** Description Setup RFCOMM servers for use by AG. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services) +{ + int i; + int bta_ag_port_status; + + services >>= BTA_HSP_SERVICE_ID; + for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) + { + /* if service is set in mask */ + if (services & 1) + { + BTM_SetSecurityLevel(FALSE, "", bta_ag_sec_id[i], p_scb->serv_sec_mask, + BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_ag_cb.profile[i].scn); + + bta_ag_port_status = RFCOMM_CreateConnection(bta_ag_uuid[i], bta_ag_cb.profile[i].scn, + TRUE, BTA_AG_MTU, (UINT8 *) bd_addr_any, &(p_scb->serv_handle[i]), + bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]); + + if( bta_ag_port_status == PORT_SUCCESS ) + { + bta_ag_setup_port(p_scb, p_scb->serv_handle[i]); + } + else + { + /* TODO: CR#137125 to handle to error properly */ + APPL_TRACE_DEBUG1("bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d", bta_ag_port_status); + } + } + } +} + +/******************************************************************************* +** +** Function bta_ag_close_servers +** +** Description Close RFCOMM servers port for use by AG. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services) +{ + int i; + + services >>= BTA_HSP_SERVICE_ID; + for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) + { + /* if service is set in mask */ + if (services & 1) + { + RFCOMM_RemoveServer(p_scb->serv_handle[i]); + p_scb->serv_handle[i] = 0; + } + } +} + +/******************************************************************************* +** +** Function bta_ag_is_server_closed +** +** Description Returns TRUE if all servers are closed. +** +** +** Returns TRUE if all servers are closed, FALSE otherwise +** +*******************************************************************************/ +BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb) +{ + UINT8 xx; + BOOLEAN is_closed = TRUE; + + for (xx = 0; xx < BTA_AG_NUM_IDX; xx++) + { + if (p_scb->serv_handle[xx] != 0) + is_closed = FALSE; + } + + return is_closed; +} + +/******************************************************************************* +** +** Function bta_ag_rfc_do_open +** +** Description Open an RFCOMM connection to the peer device. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + BTM_SetSecurityLevel(TRUE, "", bta_ag_sec_id[p_scb->conn_service], + p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, p_scb->peer_scn); + + if (RFCOMM_CreateConnection(bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, + FALSE, BTA_AG_MTU, p_scb->peer_addr, &(p_scb->conn_handle), + bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == PORT_SUCCESS) + { + bta_ag_setup_port(p_scb, p_scb->conn_handle); + APPL_TRACE_DEBUG1("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle); + } + /* RFCOMM create connection failed; send ourselves RFCOMM close event */ + else + { + bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_ag_rfc_do_close +** +** Description Close RFCOMM connection. +** +** +** Returns void +** +*******************************************************************************/ +void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) +{ + tBTA_AG_RFC *p_buf; + + if (p_scb->conn_handle) + { + RFCOMM_RemoveConnection(p_scb->conn_handle); + } + else + { + /* Close API was called while AG is in Opening state. */ + /* Need to trigger the state machine to send callback to the app */ + /* and move back to INIT state. */ + if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL) + { + p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT; + p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb); + bta_sys_sendmsg(p_buf); + } + + /* Cancel SDP if it had been started. */ + /* + if(p_scb->p_disc_db) + { + (void)SDP_CancelServiceSearch (p_scb->p_disc_db); + } + */ + } + +#ifdef _WIN32_WCE + { + /* Windows versions of RFCOMM does NOT generate a closed callback when we close */ + tPORT_CALLBACK *rfc_mgmt_cback = bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]; + + if (rfc_mgmt_cback) + { + (rfc_mgmt_cback)(PORT_CLOSED, p_scb->conn_handle); + } + } +#endif +} + |