mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 21:14:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1895 lines
		
	
	
		
			69 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1895 lines
		
	
	
		
			69 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /******************************************************************************
 | |
|  *
 | |
|  *  Copyright (C) 2000-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 functions that handle SCO connections. This includes
 | |
|  *  operations such as connect, disconnect, change supported packet types.
 | |
|  *
 | |
|  ******************************************************************************/
 | |
| 
 | |
| #include <string.h>
 | |
| #include "stack/bt_types.h"
 | |
| #include "common/bt_target.h"
 | |
| #include "stack/bt_types.h"
 | |
| #include "stack/hcimsgs.h"
 | |
| #include "stack/btu.h"
 | |
| #include "stack/btm_api.h"
 | |
| #include "osi/allocator.h"
 | |
| #include "btm_int.h"
 | |
| #include "stack/hcidefs.h"
 | |
| //#include "bt_utils.h"
 | |
| 
 | |
| #if BTM_SCO_INCLUDED == TRUE
 | |
| 
 | |
| /********************************************************************************/
 | |
| /*                 L O C A L    D A T A    D E F I N I T I O N S                */
 | |
| /********************************************************************************/
 | |
| 
 | |
| #define SCO_ST_UNUSED           0
 | |
| #define SCO_ST_LISTENING        1
 | |
| #define SCO_ST_W4_CONN_RSP      2
 | |
| #define SCO_ST_CONNECTING       3
 | |
| #define SCO_ST_CONNECTED        4
 | |
| #define SCO_ST_DISCONNECTING    5
 | |
| #define SCO_ST_PEND_UNPARK      6
 | |
| #define SCO_ST_PEND_ROLECHANGE  7
 | |
| 
 | |
| /********************************************************************************/
 | |
| /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
 | |
| /********************************************************************************/
 | |
| 
 | |
| static const tBTM_ESCO_PARAMS btm_esco_defaults = {
 | |
|     BTM_64KBITS_RATE,               /* TX Bandwidth (64 kbits/sec)              */
 | |
|     BTM_64KBITS_RATE,               /* RX Bandwidth (64 kbits/sec)              */
 | |
|     0x000a,                         /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3)  */
 | |
|     0x0060,                         /* Inp Linear, Air CVSD, 2s Comp, 16bit     */
 | |
|     (BTM_SCO_PKT_TYPES_MASK_HV1 +   /* Packet Types                             */
 | |
|     BTM_SCO_PKT_TYPES_MASK_HV2 +
 | |
|     BTM_SCO_PKT_TYPES_MASK_HV3 +
 | |
|     BTM_SCO_PKT_TYPES_MASK_EV3 +
 | |
|     BTM_SCO_PKT_TYPES_MASK_EV4 +
 | |
|     BTM_SCO_PKT_TYPES_MASK_EV5),
 | |
|     BTM_ESCO_RETRANS_POWER        /* Retransmission Effort (Power)   */
 | |
| };
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_flush_sco_data
 | |
| **
 | |
| ** Description      This function is called to flush the SCO data for this channel.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_flush_sco_data(UINT16 sco_inx)
 | |
| {
 | |
| #if BTM_SCO_HCI_INCLUDED == TRUE
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p ;
 | |
|     BT_HDR      *p_buf;
 | |
| 
 | |
|     if (sco_inx < BTM_MAX_SCO_LINKS) {
 | |
|         p = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|         while ((p_buf = (BT_HDR *)fixed_queue_dequeue(p->xmit_data_q, 0)) != NULL) {
 | |
|             osi_free(p_buf);
 | |
|         }
 | |
|     }
 | |
| #else
 | |
|     UNUSED(sco_inx);
 | |
| #endif
 | |
| #else
 | |
|     UNUSED(sco_inx);
 | |
| #endif
 | |
| }
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_init
 | |
| **
 | |
| ** Description      This function is called at BTM startup to initialize
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_init (void)
 | |
| {
 | |
| #if 0  /* cleared in btm_init; put back in if called from anywhere else! */
 | |
|     memset (&btm_cb.sco_cb, 0, sizeof(tSCO_CB));
 | |
| #endif
 | |
| #if (BTM_SCO_HCI_INCLUDED == TRUE)
 | |
|     for (int i = 0; i < BTM_MAX_SCO_LINKS; i++) {
 | |
|         btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(QUEUE_SIZE_MAX);
 | |
|     }
 | |
| #endif
 | |
|     /* Initialize nonzero defaults */
 | |
|     btm_cb.sco_cb.def_esco_parms = btm_esco_defaults; /* Initialize with defaults */
 | |
|     btm_cb.sco_cb.desired_sco_mode = BTM_DEFAULT_SCO_MODE;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_free
 | |
| **
 | |
| ** Description      Free sco specific fixed_queue from btm control block
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_free(void)
 | |
| {
 | |
| #if (BTM_SCO_HCI_INCLUDED == TRUE)
 | |
|     for (int i = 0; i < BTM_MAX_SCO_LINKS; i++) {
 | |
|         fixed_queue_free(btm_cb.sco_cb.sco_db[i].xmit_data_q, osi_free_func);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_esco_conn_rsp
 | |
| **
 | |
| ** Description      This function is called upon receipt of an (e)SCO connection
 | |
| **                  request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
 | |
| **                  the request. Parameters used to negotiate eSCO links.
 | |
| **                  If p_parms is NULL, then default values are used.
 | |
| **                  If the link type of the incoming request is SCO, then only
 | |
| **                  the tx_bw, max_latency, content format, and packet_types are
 | |
| **                  valid.  The hci_status parameter should be
 | |
| **                  ([0x0] to accept, [0x0d..0x0f] to reject)
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda,
 | |
|                                tBTM_ESCO_PARAMS *p_parms)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN        *p_sco = NULL;
 | |
|     tBTM_ESCO_PARAMS *p_setup;
 | |
|     UINT16            temp_pkt_types;
 | |
| 
 | |
|     if (sco_inx < BTM_MAX_SCO_LINKS) {
 | |
|         p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|     }
 | |
| 
 | |
|     /* Reject the connect request if refused by caller or wrong state */
 | |
|     if (hci_status != HCI_SUCCESS || p_sco == NULL) {
 | |
|         if (p_sco) {
 | |
|             p_sco->state = (p_sco->state == SCO_ST_W4_CONN_RSP) ? SCO_ST_LISTENING
 | |
|                            : SCO_ST_UNUSED;
 | |
|         }
 | |
| 
 | |
|         if (!btm_cb.sco_cb.esco_supported) {
 | |
|             if (!btsnd_hcic_reject_conn (bda, hci_status)) {
 | |
|                 BTM_TRACE_ERROR("Could not reject (e)SCO conn: No Buffer!!!");
 | |
|             }
 | |
|         } else {
 | |
|             if (!btsnd_hcic_reject_esco_conn (bda, hci_status)) {
 | |
|                 BTM_TRACE_ERROR("Could not reject (e)SCO conn: No Buffer!!!");
 | |
|             }
 | |
|         }
 | |
|     } else { /* Connection is being accepted */
 | |
|         p_sco->state = SCO_ST_CONNECTING;
 | |
|         p_setup = &p_sco->esco.setup;
 | |
|         /* If parameters not specified use the default */
 | |
|         if (p_parms) {
 | |
|             *p_setup = *p_parms;
 | |
|         } else { /* Use the last setup passed thru BTM_SetEscoMode (or defaults) */
 | |
|             *p_setup = btm_cb.sco_cb.def_esco_parms;
 | |
|         }
 | |
| 
 | |
|         temp_pkt_types = (p_setup->packet_types &
 | |
|                           BTM_SCO_SUPPORTED_PKTS_MASK &
 | |
|                           btm_cb.btm_sco_pkt_types_supported);
 | |
| 
 | |
|         /* Make sure at least one eSCO packet type is sent, else might confuse peer */
 | |
|         /* Taking this out to confirm with BQB tests
 | |
|         ** Real application would like to include this though, as many devices
 | |
|         ** do not retry with SCO only if an eSCO connection fails.
 | |
|         if (!(temp_pkt_types & BTM_ESCO_LINK_ONLY_MASK))
 | |
|         {
 | |
|             temp_pkt_types |= BTM_SCO_PKT_TYPES_MASK_EV3;
 | |
|         }
 | |
|         */
 | |
|         /* If SCO request, remove eSCO packet types (conformance) */
 | |
|         if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO) {
 | |
|             temp_pkt_types &= BTM_SCO_LINK_ONLY_MASK;
 | |
|             temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
 | |
|         } else {
 | |
|             /* OR in any exception packet types */
 | |
|             temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
 | |
|                                (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
 | |
|         }
 | |
| 
 | |
|         if (btsnd_hcic_accept_esco_conn (bda, p_setup->tx_bw, p_setup->rx_bw,
 | |
|                                          p_setup->max_latency, p_setup->voice_contfmt,
 | |
|                                          p_setup->retrans_effort, temp_pkt_types)) {
 | |
|             p_setup->packet_types = temp_pkt_types;
 | |
|         } else {
 | |
|             BTM_TRACE_ERROR("Could not accept SCO conn: No Buffer!!!");
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| #if BTM_SCO_HCI_INCLUDED == TRUE
 | |
| void btm_sco_process_num_bufs (UINT16 num_lm_sco_bufs)
 | |
| {
 | |
|     BTM_TRACE_DEBUG("%s, %d", __FUNCTION__, num_lm_sco_bufs);
 | |
|     btm_cb.sco_cb.num_lm_sco_bufs = btm_cb.sco_cb.xmit_window_size = num_lm_sco_bufs;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_ConfigScoPath
 | |
| **
 | |
| ** Description      This function enable/disable SCO over HCI and registers SCO
 | |
| **                  data callback if SCO over HCI is enabled.
 | |
| **
 | |
| ** Parameter        path: SCO or HCI
 | |
| **                  p_sco_data_cb: callback function or SCO data if path is set
 | |
| **                                 to transport.
 | |
| **                  p_pcm_param: pointer to the PCM interface parameter. If a NULL
 | |
| **                               pointer is used, PCM parameter maintained in
 | |
| **                               the control block will be used; otherwise update
 | |
| **                               control block value.
 | |
| **                  err_data_rpt: Lisbon feature to enable the erroneous data report
 | |
| **                                or not.
 | |
| **
 | |
| ** Returns          BTM_SUCCESS if the successful.
 | |
| **                  BTM_NO_RESOURCES: no rsource to start the command.
 | |
| **                  BTM_ILLEGAL_VALUE: invalid callback function pointer.
 | |
| **                  BTM_CMD_STARTED :Command sent. Waiting for command cmpl event.
 | |
| **
 | |
| **
 | |
| *******************************************************************************/
 | |
| //extern
 | |
| tBTM_STATUS BTM_ConfigScoPath (tBTM_SCO_ROUTE_TYPE path,
 | |
|                                tBTM_SCO_DATA_CB *p_sco_data_cb,
 | |
|                                tBTM_SCO_PCM_PARAM *p_pcm_param,
 | |
|                                BOOLEAN err_data_rpt)
 | |
| {
 | |
|     UNUSED(err_data_rpt);
 | |
|     UNUSED(p_pcm_param);
 | |
|     btm_cb.sco_cb.sco_path = path;
 | |
|     if (path == BTM_SCO_ROUTE_PCM) {
 | |
|         return BTM_SUCCESS;
 | |
|     } else if (path == BTM_SCO_ROUTE_HCI) {
 | |
|         if (p_sco_data_cb) {
 | |
|             btm_cb.sco_cb.p_data_cb = p_sco_data_cb;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return BTM_SUCCESS;
 | |
| }
 | |
| 
 | |
| static void hci_sco_data_to_lower(BT_HDR *p_buf)
 | |
| {
 | |
|     p_buf->event = BT_EVT_TO_LM_HCI_SCO;
 | |
|     if (p_buf->offset == 0) {
 | |
|         BTM_TRACE_ERROR("offset cannot be 0");
 | |
|         osi_free(p_buf);
 | |
|     }
 | |
| 
 | |
|     bte_main_hci_send(p_buf, (UINT16)(BT_EVT_TO_LM_HCI_SCO | LOCAL_BLE_CONTROLLER_ID));
 | |
| }
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_check_send_pkts
 | |
| **
 | |
| ** Description      This function is called to check if it can send packets
 | |
| **                  to the Host Controller.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_check_send_pkts (UINT16 sco_inx)
 | |
| {
 | |
|     tSCO_CB  *p_cb = &btm_cb.sco_cb;
 | |
|     tSCO_CONN   *p_ccb = &p_cb->sco_db[sco_inx];
 | |
| 
 | |
|     /* If there is data to send, send it now */
 | |
|     BT_HDR  *p_buf;
 | |
|     while (p_cb->xmit_window_size != 0)
 | |
|     {
 | |
|         if ((p_buf = (BT_HDR *)fixed_queue_dequeue(p_ccb->xmit_data_q, 0)) == NULL) {
 | |
|             break;
 | |
|         }
 | |
| #if BTM_SCO_HCI_DEBUG
 | |
|         BTM_TRACE_DEBUG("btm: [%d] buf in xmit_data_q",
 | |
|                         fixed_queue_length(p_ccb->xmit_data_q) + 1);
 | |
| #endif
 | |
|         /* Don't go negative */
 | |
|         p_cb->xmit_window_size -= 1;
 | |
|         p_ccb->sent_not_acked += 1;
 | |
| 
 | |
|         // HCI_SCO_DATA_TO_LOWER(p_buf);
 | |
|         hci_sco_data_to_lower(p_buf);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void btm_sco_process_num_completed_pkts (UINT8 *p)
 | |
| {
 | |
|     UINT8       num_handles, xx;
 | |
|     UINT16      handle;
 | |
|     UINT16      num_sent;
 | |
|     UINT16      sco_inx;
 | |
|     tSCO_CB  *p_cb = &btm_cb.sco_cb;
 | |
|     tSCO_CONN * p_ccb;
 | |
|     STREAM_TO_UINT8 (num_handles, p);
 | |
|     for (xx = 0; xx < num_handles; xx++) {
 | |
|         STREAM_TO_UINT16 (handle, p);
 | |
|         STREAM_TO_UINT16 (num_sent, p);
 | |
|         if ((sco_inx = btm_find_scb_by_handle(handle)) == BTM_MAX_SCO_LINKS) {
 | |
|             continue;
 | |
|         }
 | |
|         BTM_TRACE_DEBUG("%s, %d, %u", __FUNCTION__, handle, p_cb->xmit_window_size); //debug
 | |
|         p_ccb = &p_cb->sco_db[sco_inx];
 | |
|         p_ccb->sent_not_acked -= num_sent;
 | |
|         // don't go negative
 | |
|         if (p_ccb->sent_not_acked < 0) {
 | |
|             BTM_TRACE_WARNING("SCO: un-acked underf: %u", p_ccb->sent_not_acked);
 | |
|             p_ccb->sent_not_acked = 0;
 | |
|         }
 | |
|         p_cb->xmit_window_size += num_sent;
 | |
|         if (p_cb->xmit_window_size > p_cb->num_lm_sco_bufs) {
 | |
|             BTM_TRACE_WARNING("SCO xwind: %d, max %d", p_cb->xmit_window_size, p_cb->num_lm_sco_bufs);
 | |
|             p_cb->xmit_window_size = p_cb->num_lm_sco_bufs;
 | |
|         }
 | |
|         btm_sco_check_send_pkts (sco_inx);
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_pkt_stat_nums_update
 | |
| **
 | |
| ** Description      Update the number of received SCO data packet status.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| static void btm_pkt_stat_nums_update(uint16_t sco_inx, uint8_t pkt_status)
 | |
| {
 | |
|     tSCO_CONN   *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|     p_ccb->pkt_stat_nums.rx_total++;
 | |
|     if (pkt_status == BTM_SCO_DATA_CORRECT) {
 | |
|         p_ccb->pkt_stat_nums.rx_correct++;
 | |
|     } else if (pkt_status == BTM_SCO_DATA_PAR_ERR) {
 | |
|         p_ccb->pkt_stat_nums.rx_err++;
 | |
|     } else if (pkt_status == BTM_SCO_DATA_NONE) {
 | |
|         p_ccb->pkt_stat_nums.rx_none++;
 | |
|     } else {
 | |
|         p_ccb->pkt_stat_nums.rx_lost++;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_pkt_stat_send_nums_update
 | |
| **
 | |
| ** Description      Update the number of send packet status.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| static void btm_pkt_stat_send_nums_update(uint16_t sco_inx, uint8_t pkt_status)
 | |
| {
 | |
|     tSCO_CONN   *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|     p_ccb->pkt_stat_nums.tx_total++;
 | |
|     if (pkt_status != BTM_SUCCESS && pkt_status != BTM_NO_RESOURCES && pkt_status != BTM_SCO_BAD_LENGTH) {
 | |
|         p_ccb->pkt_stat_nums.tx_discarded++;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_pkt_stat_nums_reset
 | |
| **
 | |
| ** Description      This function is called to reset the number of packet status struct
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| static void btm_pkt_stat_nums_reset(uint16_t sco_inx)
 | |
| {
 | |
|     memset(&btm_cb.sco_cb.sco_db[sco_inx].pkt_stat_nums, 0, sizeof(tBTM_SCO_PKT_STAT_NUMS));
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_PktStatNumsGet
 | |
| **
 | |
| ** Description      This function is called to get the number of packet status struct
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void BTM_PktStatNumsGet(uint16_t sync_conn_handle, tBTM_SCO_PKT_STAT_NUMS *p_pkt_nums)
 | |
| {
 | |
|     uint16_t sco_inx = btm_find_scb_by_handle(sync_conn_handle);
 | |
|     if (sco_inx < BTM_MAX_SCO_LINKS) {
 | |
|         memcpy(p_pkt_nums, &btm_cb.sco_cb.sco_db[sco_inx].pkt_stat_nums, sizeof(tBTM_SCO_PKT_STAT_NUMS));
 | |
|     } else {
 | |
|         memset(p_pkt_nums, 0, sizeof(tBTM_SCO_PKT_STAT_NUMS));
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif /* BTM_SCO_HCI_INCLUDED == TRUE */
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_route_sco_data
 | |
| **
 | |
| ** Description      Route received SCO data.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void  btm_route_sco_data(BT_HDR *p_msg)
 | |
| {
 | |
| #if BTM_SCO_HCI_INCLUDED == TRUE
 | |
|     UINT16      sco_inx, handle;
 | |
|     UINT8       *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
 | |
|     UINT8       pkt_size = 0;
 | |
|     UINT8       pkt_status = 0;
 | |
| 
 | |
|     /* Extract Packet_Status_Flag and handle */
 | |
|     STREAM_TO_UINT16 (handle, p);
 | |
|     pkt_status = HCID_GET_EVENT(handle);
 | |
|     handle   = HCID_GET_HANDLE (handle);
 | |
| 
 | |
|     STREAM_TO_UINT8 (pkt_size, p);
 | |
|     UNUSED(pkt_size);
 | |
|     if ((sco_inx = btm_find_scb_by_handle(handle)) != BTM_MAX_SCO_LINKS ) {
 | |
|         /* send data callback */
 | |
|         if (!btm_cb.sco_cb.p_data_cb )
 | |
|             /* if no data callback registered,  just free the buffer  */
 | |
|         {
 | |
|             osi_free (p_msg);
 | |
|         } else {
 | |
|             btm_pkt_stat_nums_update(sco_inx, pkt_status);
 | |
|             (*btm_cb.sco_cb.p_data_cb)(sco_inx, p_msg, (tBTM_SCO_DATA_FLAG) pkt_status);
 | |
|         }
 | |
|     } else { /* no mapping handle SCO connection is active, free the buffer */
 | |
|         osi_free (p_msg);
 | |
|     }
 | |
|     BTM_TRACE_DEBUG ("SCO: hdl %x, len %d, pkt_sz %d\n", handle, p_msg->len, pkt_size);
 | |
| #else
 | |
|     osi_free(p_msg);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_WriteScoData
 | |
| **
 | |
| ** Description      This function write SCO data to a specified instance. The data
 | |
| **                  to be written p_buf needs to carry an offset of
 | |
| **                  HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not
 | |
| **                  exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is set
 | |
| **                  to 60 and is configurable. Data longer than the maximum bytes
 | |
| **                  will be truncated.
 | |
| **
 | |
| ** Returns          BTM_SUCCESS: data write is successful
 | |
| **                  BTM_ILLEGAL_VALUE: SCO data contains illegal offset value.
 | |
| **                  BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO packet
 | |
| **                                      size.
 | |
| **                  BTM_NO_RESOURCES: no resources.
 | |
| **                  BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is not
 | |
| **                                    routed via HCI.
 | |
| **                  BTM_ERR_PROCESSING: transmit queue overflow
 | |
| **
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
 | |
| {
 | |
|     APPL_TRACE_DEBUG("%s", __FUNCTION__);
 | |
| #if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|     UINT8   *p;
 | |
|     tBTM_STATUS     status = BTM_SUCCESS;
 | |
| 
 | |
|     if (sco_inx < BTM_MAX_SCO_LINKS && btm_cb.sco_cb.p_data_cb &&
 | |
|             p_ccb->state == SCO_ST_CONNECTED) {
 | |
|         /* Ensure we have enough space in the buffer for the SCO and HCI headers */
 | |
|         if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE) {
 | |
|             BTM_TRACE_ERROR ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset);
 | |
|             status = BTM_ILLEGAL_VALUE;
 | |
|         } else { /* write HCI header */
 | |
|             /* Step back 3 bytes to add the headers */
 | |
|             p_buf->offset -= HCI_SCO_PREAMBLE_SIZE;
 | |
|             /* Set the pointer to the beginning of the data */
 | |
|             p = (UINT8 *)(p_buf + 1) + p_buf->offset;
 | |
|             /* add HCI handle */
 | |
|             UINT16_TO_STREAM (p, p_ccb->hci_handle);
 | |
|             /* only sent the first BTM_SCO_DATA_SIZE_MAX bytes data if more than max,
 | |
|                and set warning status */
 | |
|             if (p_buf->len > BTM_SCO_DATA_SIZE_MAX) {
 | |
|                 BTM_TRACE_WARNING ("BTM SCO hdl %x, bad len %u", p_ccb->hci_handle, p_buf->len);
 | |
|                 p_buf->len = BTM_SCO_DATA_SIZE_MAX;
 | |
|                 status = BTM_SCO_BAD_LENGTH;
 | |
|             }
 | |
| 
 | |
|             UINT8_TO_STREAM (p, (UINT8)p_buf->len);
 | |
| 
 | |
|             p_buf->len += HCI_SCO_PREAMBLE_SIZE;
 | |
| 
 | |
|             if (fixed_queue_length(p_ccb->xmit_data_q) < BTM_SCO_XMIT_QUEUE_THRS) {
 | |
|                 if (fixed_queue_length(p_ccb->xmit_data_q) >= BTM_SCO_XMIT_QUEUE_HIGH_WM) {
 | |
|                     status = BTM_NO_RESOURCES;
 | |
|                 }
 | |
|                 fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
 | |
|                 btm_sco_check_send_pkts (sco_inx);
 | |
|             } else {
 | |
|                 BTM_TRACE_WARNING ("SCO xmit Q overflow, pkt dropped");
 | |
|                 status = BTM_ERR_PROCESSING;
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         BTM_TRACE_WARNING ("BTM_WriteScoData, invalid sco index: %d at state [%d]",
 | |
|                            sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state);
 | |
|         status = BTM_UNKNOWN_ADDR;
 | |
|     }
 | |
| 
 | |
|     if (status != BTM_SUCCESS && status!= BTM_NO_RESOURCES && status != BTM_SCO_BAD_LENGTH) {
 | |
|         BTM_TRACE_WARNING ("stat %d", status);
 | |
|         osi_free(p_buf);
 | |
|     }
 | |
|     btm_pkt_stat_send_nums_update(sco_inx, status);
 | |
|     return (status);
 | |
| 
 | |
| #else
 | |
|     UNUSED(sco_inx);
 | |
|     UNUSED(p_buf);
 | |
|     return (BTM_NO_RESOURCES);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_send_connect_request
 | |
| **
 | |
| ** Description      This function is called to respond to SCO connect indications
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| static tBTM_STATUS btm_send_connect_request(UINT16 acl_handle,
 | |
|         tBTM_ESCO_PARAMS *p_setup)
 | |
| {
 | |
|     UINT16 temp_pkt_types;
 | |
|     tACL_CONN *p_acl;
 | |
| 
 | |
|     /* Send connect request depending on version of spec */
 | |
|     if (!btm_cb.sco_cb.esco_supported) {
 | |
|         if (!btsnd_hcic_add_SCO_conn (acl_handle, BTM_ESCO_2_SCO(p_setup->packet_types))) {
 | |
|             return (BTM_NO_RESOURCES);
 | |
|         }
 | |
|     } else {
 | |
|         temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
 | |
|                           btm_cb.btm_sco_pkt_types_supported);
 | |
| 
 | |
|         /* OR in any exception packet types */
 | |
|         temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
 | |
|                            (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
 | |
| 
 | |
|         /* Finally, remove EDR eSCO if the remote device doesn't support it */
 | |
|         /* UPF25:  Only SCO was brought up in this case */
 | |
|         p_acl = btm_handle_to_acl(acl_handle);
 | |
|         if (p_acl) {
 | |
|             if (!HCI_EDR_ESCO_2MPS_SUPPORTED(p_acl->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
 | |
| 
 | |
|                 BTM_TRACE_WARNING("BTM Remote does not support 2-EDR eSCO");
 | |
|                 temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 |
 | |
|                                    HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5);
 | |
|             }
 | |
|             if (!HCI_EDR_ESCO_3MPS_SUPPORTED(p_acl->peer_lmp_features[HCI_EXT_FEATURES_PAGE_0])) {
 | |
| 
 | |
|                 BTM_TRACE_WARNING("BTM Remote does not support 3-EDR eSCO");
 | |
|                 temp_pkt_types |= (HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 |
 | |
|                                    HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5);
 | |
|             }
 | |
| 
 | |
|             /* Check to see if BR/EDR Secure Connections is being used
 | |
|             ** If so, we cannot use SCO-only packet types (HFP 1.7)
 | |
|             */
 | |
|             if (BTM_BothEndsSupportSecureConnections(p_acl->remote_addr)) {
 | |
|                 temp_pkt_types &= ~(BTM_SCO_LINK_ONLY_MASK);
 | |
|                 BTM_TRACE_DEBUG("%s: SCO Conn: pkt_types after removing SCO (0x%04x)", __FUNCTION__,
 | |
|                                 temp_pkt_types);
 | |
| 
 | |
|                 /* Return error if no packet types left */
 | |
|                 if (temp_pkt_types == BTM_SCO_EXCEPTION_PKTS_MASK) {
 | |
|                     BTM_TRACE_ERROR("%s: SCO Conn (BR/EDR SC): No packet types available",__FUNCTION__);
 | |
|                     return (BTM_WRONG_MODE);
 | |
|                 }
 | |
|             } else {
 | |
|                 BTM_TRACE_DEBUG("%s: SCO Conn(BR/EDR SC):local or peer does not support BR/EDR SC",__FUNCTION__);
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         BTM_TRACE_API("txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
 | |
|                       p_setup->tx_bw, p_setup->rx_bw,
 | |
|                       p_setup->max_latency, p_setup->voice_contfmt,
 | |
|                       p_setup->retrans_effort, temp_pkt_types);
 | |
| 
 | |
|         if (!btsnd_hcic_setup_esco_conn(acl_handle,
 | |
|                                         p_setup->tx_bw,
 | |
|                                         p_setup->rx_bw,
 | |
|                                         p_setup->max_latency,
 | |
|                                         p_setup->voice_contfmt,
 | |
|                                         p_setup->retrans_effort,
 | |
|                                         temp_pkt_types)) {
 | |
|             return (BTM_NO_RESOURCES);
 | |
|         } else {
 | |
|             p_setup->packet_types = temp_pkt_types;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return (BTM_CMD_STARTED);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_set_sco_ind_cback
 | |
| **
 | |
| ** Description      This function is called to register for TCS SCO connect
 | |
| **                  indications.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_set_sco_ind_cback( tBTM_SCO_IND_CBACK *sco_ind_cb )
 | |
| {
 | |
|     btm_cb.sco_cb.app_sco_ind_cb = sco_ind_cb;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_accept_sco_link
 | |
| **
 | |
| ** Description      This function is called to respond to TCS SCO connect
 | |
| **                  indications
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_accept_sco_link(UINT16 sco_inx, tBTM_ESCO_PARAMS *p_setup,
 | |
|                          tBTM_SCO_CB *p_conn_cb, tBTM_SCO_CB *p_disc_cb)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN        *p_sco;
 | |
| 
 | |
|     if (sco_inx >= BTM_MAX_SCO_LINKS) {
 | |
|         BTM_TRACE_ERROR("btm_accept_sco_link: Invalid sco_inx(%d)", sco_inx);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     /* Link role is ignored in for this message */
 | |
|     p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|     p_sco->p_conn_cb = p_conn_cb;
 | |
|     p_sco->p_disc_cb = p_disc_cb;
 | |
|     p_sco->esco.data.link_type = BTM_LINK_TYPE_ESCO; /* Accept with all supported types */
 | |
| 
 | |
|     BTM_TRACE_DEBUG("TCS accept SCO: Packet Types 0x%04x", p_setup->packet_types);
 | |
| 
 | |
|     btm_esco_conn_rsp(sco_inx, HCI_SUCCESS, p_sco->esco.data.bd_addr, p_setup);
 | |
| #else
 | |
|     btm_reject_sco_link(sco_inx);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_reject_sco_link
 | |
| **
 | |
| ** Description      This function is called to respond to SCO connect indications
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_reject_sco_link( UINT16 sco_inx )
 | |
| {
 | |
|     btm_esco_conn_rsp(sco_inx, HCI_ERR_HOST_REJECT_RESOURCES,
 | |
|                       btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr, NULL);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_CreateSco
 | |
| **
 | |
| ** Description      This function is called to create an SCO connection. If the
 | |
| **                  "is_orig" flag is TRUE, the connection will be originated,
 | |
| **                  otherwise BTM will wait for the other side to connect.
 | |
| **
 | |
| **                  NOTE:  If BTM_IGNORE_SCO_PKT_TYPE is passed in the pkt_types
 | |
| **                      parameter the default packet types is used.
 | |
| **
 | |
| ** Returns          BTM_UNKNOWN_ADDR if the ACL connection is not up
 | |
| **                  BTM_BUSY         if another SCO being set up to
 | |
| **                                   the same BD address
 | |
| **                  BTM_NO_RESOURCES if the max SCO limit has been reached
 | |
| **                  BTM_CMD_STARTED  if the connection establishment is started.
 | |
| **                                   In this case, "*p_sco_inx" is filled in
 | |
| **                                   with the sco index used for the connection.
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 pkt_types,
 | |
|                            UINT16 *p_sco_inx, tBTM_SCO_CB *p_conn_cb,
 | |
|                            tBTM_SCO_CB *p_disc_cb)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS > 0)
 | |
|     tBTM_ESCO_PARAMS *p_setup;
 | |
|     tSCO_CONN        *p = &btm_cb.sco_cb.sco_db[0];
 | |
|     UINT16            xx;
 | |
|     UINT16            acl_handle = 0;
 | |
|     UINT16            temp_pkt_types;
 | |
|     tACL_CONN        *p_acl;
 | |
| 
 | |
| #if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
 | |
|     tBTM_PM_MODE      md;
 | |
|     tBTM_PM_PWR_MD    pm;
 | |
| #else  // BTM_SCO_WAKE_PARKED_LINK
 | |
|     UINT8             mode;
 | |
| #endif  // BTM_SCO_WAKE_PARKED_LINK
 | |
| 
 | |
|     *p_sco_inx = BTM_INVALID_SCO_INDEX;
 | |
| 
 | |
|     /* If originating, ensure that there is an ACL connection to the BD Address */
 | |
|     if (is_orig) {
 | |
|         if ((!remote_bda) || ((acl_handle = BTM_GetHCIConnHandle (remote_bda, BT_TRANSPORT_BR_EDR)) == 0xFFFF)) {
 | |
|             return (BTM_UNKNOWN_ADDR);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (remote_bda) {
 | |
|         /* If any SCO is being established to the remote BD address, refuse this */
 | |
|         for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|             if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING)
 | |
|                     || (p->state == SCO_ST_PEND_UNPARK))
 | |
|                     && (!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN))) {
 | |
|                 return (BTM_BUSY);
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         /* Support only 1 wildcard BD address at a time */
 | |
|         for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|             if ((p->state == SCO_ST_LISTENING) && (!p->rem_bd_known)) {
 | |
|                 return (BTM_BUSY);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Now, try to find an unused control block, and kick off the SCO establishment */
 | |
|     for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if (p->state == SCO_ST_UNUSED) {
 | |
|             if (remote_bda) {
 | |
|                 if (is_orig) {
 | |
|                     /* can not create SCO link if in park mode */
 | |
| #if BTM_SCO_WAKE_PARKED_LINK == TRUE
 | |
|                     if (BTM_ReadPowerMode(remote_bda, &md) == BTM_SUCCESS) {
 | |
|                         if (md == BTM_PM_MD_PARK || md == BTM_PM_MD_SNIFF) {
 | |
|                             memset( (void *)&pm, 0, sizeof(pm));
 | |
|                             pm.mode = BTM_PM_MD_ACTIVE;
 | |
|                             BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm);
 | |
|                             p->state = SCO_ST_PEND_UNPARK;
 | |
|                         }
 | |
|                     }
 | |
| #else  // BTM_SCO_WAKE_PARKED_LINK
 | |
|                     if ( (BTM_ReadPowerMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_PM_MD_PARK) ) {
 | |
|                         return (BTM_WRONG_MODE);
 | |
|                     }
 | |
| #endif  // BTM_SCO_WAKE_PARKED_LINK
 | |
|                 }
 | |
|                 memcpy (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN);
 | |
|                 p->rem_bd_known = TRUE;
 | |
|             } else {
 | |
|                 p->rem_bd_known = FALSE;
 | |
|             }
 | |
| 
 | |
|             /* Link role is ignored in for this message */
 | |
|             if (pkt_types == BTM_IGNORE_SCO_PKT_TYPE) {
 | |
|                 pkt_types = btm_cb.sco_cb.def_esco_parms.packet_types;
 | |
|             }
 | |
| 
 | |
|             p_setup = &p->esco.setup;
 | |
|             *p_setup = btm_cb.sco_cb.def_esco_parms;
 | |
|             p_setup->packet_types = (btm_cb.sco_cb.desired_sco_mode == BTM_LINK_TYPE_SCO)
 | |
|                                     ? (pkt_types & BTM_SCO_LINK_ONLY_MASK) : pkt_types;
 | |
| 
 | |
|             temp_pkt_types = (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
 | |
|                               btm_cb.btm_sco_pkt_types_supported);
 | |
| 
 | |
|             /* OR in any exception packet types */
 | |
|             if (btm_cb.sco_cb.desired_sco_mode == HCI_LINK_TYPE_ESCO) {
 | |
|                 temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
 | |
|                                    (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
 | |
|             } else { /* Only using SCO packet types; turn off EDR also */
 | |
|                 temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
 | |
|             }
 | |
| 
 | |
|             p_setup->packet_types = temp_pkt_types;
 | |
|             p->p_conn_cb  = p_conn_cb;
 | |
|             p->p_disc_cb  = p_disc_cb;
 | |
|             p->hci_handle = BTM_INVALID_HCI_HANDLE;
 | |
|             p->is_orig = is_orig;
 | |
| 
 | |
|             if ( p->state != SCO_ST_PEND_UNPARK ) {
 | |
|                 if (is_orig) {
 | |
|                     /* If role change is in progress, do not proceed with SCO setup
 | |
|                      * Wait till role change is complete */
 | |
|                     p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
 | |
|                     if (p_acl && p_acl->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) {
 | |
|                         BTM_TRACE_API("Role Change is in progress for ACL handle 0x%04x", acl_handle);
 | |
|                         p->state = SCO_ST_PEND_ROLECHANGE;
 | |
| 
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if ( p->state != SCO_ST_PEND_UNPARK && p->state != SCO_ST_PEND_ROLECHANGE ) {
 | |
|                 if (is_orig) {
 | |
|                     BTM_TRACE_API("BTM_CreateSco -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d",
 | |
|                                   acl_handle, btm_cb.sco_cb.desired_sco_mode);
 | |
| 
 | |
|                     if ((btm_send_connect_request(acl_handle, p_setup)) != BTM_CMD_STARTED) {
 | |
|                         return (BTM_NO_RESOURCES);
 | |
|                     }
 | |
| 
 | |
|                     p->state = SCO_ST_CONNECTING;
 | |
|                 } else {
 | |
|                     p->state = SCO_ST_LISTENING;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             *p_sco_inx = xx;
 | |
| 
 | |
|             return (BTM_CMD_STARTED);
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #endif
 | |
|     /* If here, all SCO blocks in use */
 | |
|     return (BTM_NO_RESOURCES);
 | |
| }
 | |
| 
 | |
| #if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_chk_pend_unpark
 | |
| **
 | |
| ** Description      This function is called by BTIF when there is a mode change
 | |
| **                  event to see if there are SCO commands waiting for the unpark.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     UINT16      xx;
 | |
|     UINT16      acl_handle;
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if ((p->state == SCO_ST_PEND_UNPARK) &&
 | |
|                 ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
 | |
| 
 | |
|         {
 | |
|             BTM_TRACE_API("btm_sco_chk_pend_unpark -> (e)SCO Link for ACL handle 0x%04x, Desired Type %d, hci_status 0x%02x",
 | |
|                           acl_handle, btm_cb.sco_cb.desired_sco_mode, hci_status);
 | |
| 
 | |
|             if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED) {
 | |
|                 p->state = SCO_ST_CONNECTING;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| #endif  // BTM_MAX_SCO_LINKS
 | |
| }
 | |
| #endif  // BTM_SCO_WAKE_PARKED_LINK
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_chk_pend_rolechange
 | |
| **
 | |
| ** Description      This function is called by BTIF when there is a role change
 | |
| **                  event to see if there are SCO commands waiting for the role change.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_chk_pend_rolechange (UINT16 hci_handle)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     UINT16      xx;
 | |
|     UINT16      acl_handle;
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if ((p->state == SCO_ST_PEND_ROLECHANGE) &&
 | |
|                 ((acl_handle = BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
 | |
| 
 | |
|         {
 | |
|             BTM_TRACE_API("btm_sco_chk_pend_rolechange -> (e)SCO Link for ACL handle 0x%04x", acl_handle);
 | |
| 
 | |
|             if ((btm_send_connect_request(acl_handle, &p->esco.setup)) == BTM_CMD_STARTED) {
 | |
|                 p->state = SCO_ST_CONNECTING;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_conn_req
 | |
| **
 | |
| ** Description      This function is called by BTIF when an SCO connection
 | |
| **                  request is received from a remote.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_conn_req (BD_ADDR bda,  DEV_CLASS dev_class, UINT8 link_type)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CB     *p_sco = &btm_cb.sco_cb;
 | |
|     tSCO_CONN   *p = &p_sco->sco_db[0];
 | |
|     UINT16      xx;
 | |
|     tBTM_ESCO_CONN_REQ_EVT_DATA evt_data;
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         /*
 | |
|          * If the sco state is in the SCO_ST_CONNECTING state, we still need
 | |
|          * to return accept sco to avoid race condition for sco creation
 | |
|          */
 | |
|         int rem_bd_matches = p->rem_bd_known &&
 | |
|                              !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
 | |
|         if (((p->state == SCO_ST_CONNECTING) && rem_bd_matches) ||
 | |
|                 ((p->state == SCO_ST_LISTENING) && (rem_bd_matches || !p->rem_bd_known))) {
 | |
|             /* If this guy was a wildcard, he is not one any more */
 | |
|             p->rem_bd_known = TRUE;
 | |
|             p->esco.data.link_type = link_type;
 | |
|             p->state = SCO_ST_W4_CONN_RSP;
 | |
|             memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
 | |
| 
 | |
|             /* If no callback, auto-accept the connection if packet types match */
 | |
|             if (!p->esco.p_esco_cback) {
 | |
|                 /* If requesting eSCO reject if default parameters are SCO only */
 | |
|                 if ((link_type == BTM_LINK_TYPE_ESCO
 | |
|                         && !(p_sco->def_esco_parms.packet_types & BTM_ESCO_LINK_ONLY_MASK)
 | |
|                         && ((p_sco->def_esco_parms.packet_types & BTM_SCO_EXCEPTION_PKTS_MASK)
 | |
|                             == BTM_SCO_EXCEPTION_PKTS_MASK))
 | |
| 
 | |
|                         /* Reject request if SCO is desired but no SCO packets delected */
 | |
|                         || (link_type == BTM_LINK_TYPE_SCO
 | |
|                             && !(p_sco->def_esco_parms.packet_types & BTM_SCO_LINK_ONLY_MASK))) {
 | |
|                     btm_esco_conn_rsp(xx, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
 | |
|                 } else { /* Accept the request */
 | |
|                     btm_esco_conn_rsp(xx, HCI_SUCCESS, bda, NULL);
 | |
|                 }
 | |
|             } else { /* Notify upper layer of connect indication */
 | |
|                 memcpy(evt_data.bd_addr, bda, BD_ADDR_LEN);
 | |
|                 memcpy(evt_data.dev_class, dev_class, DEV_CLASS_LEN);
 | |
|                 evt_data.link_type = link_type;
 | |
|                 evt_data.sco_inx = xx;
 | |
|                 p->esco.p_esco_cback(BTM_ESCO_CONN_REQ_EVT, (tBTM_ESCO_EVT_DATA *)&evt_data);
 | |
|             }
 | |
| 
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* TCS usage */
 | |
|     if (btm_cb.sco_cb.app_sco_ind_cb) {
 | |
|         /* Now, try to find an unused control block */
 | |
|         for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|             if (p->state == SCO_ST_UNUSED) {
 | |
|                 p->is_orig = FALSE;
 | |
|                 p->state = SCO_ST_LISTENING;
 | |
| 
 | |
|                 p->esco.data.link_type = link_type;
 | |
|                 memcpy (p->esco.data.bd_addr, bda, BD_ADDR_LEN);
 | |
|                 p->rem_bd_known = TRUE;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         if ( xx < BTM_MAX_SCO_LINKS) {
 | |
|             btm_cb.sco_cb.app_sco_ind_cb(xx);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #endif
 | |
|     /* If here, no one wants the SCO connection. Reject it */
 | |
|     BTM_TRACE_WARNING("btm_sco_conn_req: No one wants this SCO connection; rejecting it");
 | |
|     btm_esco_conn_rsp(BTM_MAX_SCO_LINKS, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_connected
 | |
| **
 | |
| ** Description      This function is called by BTIF when an (e)SCO connection
 | |
| **                  is connected.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_connected (UINT8 hci_status, BD_ADDR bda, UINT16 hci_handle,
 | |
|                         tBTM_ESCO_DATA *p_esco_data)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
 | |
|     UINT16      xx;
 | |
|     BOOLEAN     spt = FALSE;
 | |
|     tBTM_CHG_ESCO_PARAMS parms;
 | |
| #endif
 | |
| 
 | |
|     BTM_TRACE_API("%s, handle %x", __FUNCTION__, hci_handle);
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if (((p->state == SCO_ST_CONNECTING) ||
 | |
|                 (p->state == SCO_ST_LISTENING)  ||
 | |
|                 (p->state == SCO_ST_W4_CONN_RSP))
 | |
|                 && (p->rem_bd_known)
 | |
|                 && (!bda || !memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN))) {
 | |
|             if (hci_status != HCI_SUCCESS) {
 | |
|                 /* Report the error if originator, otherwise remain in Listen mode */
 | |
|                 if (p->is_orig) {
 | |
|                     /* If role switch is pending, we need try again after role switch is complete */
 | |
|                     if (hci_status == HCI_ERR_ROLE_SWITCH_PENDING) {
 | |
|                         BTM_TRACE_API("Role Change pending for HCI handle 0x%04x", hci_handle);
 | |
|                         p->state = SCO_ST_PEND_ROLECHANGE;
 | |
|                     }
 | |
|                     /* avoid calling disconnect callback because of sco creation race */
 | |
|                     else if (hci_status != HCI_ERR_LMP_ERR_TRANS_COLLISION) {
 | |
|                         p->state = SCO_ST_UNUSED;
 | |
|                         (*p->p_disc_cb)(xx);
 | |
|                     }
 | |
|                 } else {
 | |
|                     /* Notify the upper layer that incoming sco connection has failed. */
 | |
|                     if (p->state == SCO_ST_CONNECTING) {
 | |
|                         p->state = SCO_ST_UNUSED;
 | |
|                         (*p->p_disc_cb)(xx);
 | |
|                     } else {
 | |
|                         p->state = SCO_ST_LISTENING;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             if (p->state == SCO_ST_LISTENING) {
 | |
|                 spt = TRUE;
 | |
|             }
 | |
| #if BTM_SCO_HCI_INCLUDED == TRUE
 | |
|             p->sent_not_acked = 0;
 | |
|             btm_pkt_stat_nums_reset(xx);
 | |
| #endif
 | |
|             p->state = SCO_ST_CONNECTED;
 | |
|             p->hci_handle = hci_handle;
 | |
| 
 | |
|             if (!btm_cb.sco_cb.esco_supported) {
 | |
|                 p->esco.data.link_type = BTM_LINK_TYPE_SCO;
 | |
|                 if (spt) {
 | |
|                     parms.packet_types = p->esco.setup.packet_types;
 | |
|                     /* Keep the other parameters the same for SCO */
 | |
|                     parms.max_latency = p->esco.setup.max_latency;
 | |
|                     parms.retrans_effort = p->esco.setup.retrans_effort;
 | |
| 
 | |
|                     BTM_ChangeEScoLinkParms(xx, &parms);
 | |
|                 }
 | |
|             } else {
 | |
|                 if (p_esco_data) {
 | |
|                     p->esco.data = *p_esco_data;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             (*p->p_conn_cb)(xx);
 | |
| 
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_find_scb_by_handle
 | |
| **
 | |
| ** Description      Look through all active SCO connection for a match based on the
 | |
| **                  HCI handle.
 | |
| **
 | |
| ** Returns          index to matched SCO connection CB, or BTM_MAX_SCO_LINKS if
 | |
| **                  no match.
 | |
| **
 | |
| *******************************************************************************/
 | |
| UINT16  btm_find_scb_by_handle (UINT16 handle)
 | |
| {
 | |
|     int         xx;
 | |
|     tSCO_CONN    *p = &btm_cb.sco_cb.sco_db[0];
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if ((p->state == SCO_ST_CONNECTED) && (p->hci_handle == handle)) {
 | |
|             return (xx);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* If here, no match found */
 | |
|     return (xx);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_RemoveSco
 | |
| **
 | |
| ** Description      This function is called to remove a specific SCO connection.
 | |
| **
 | |
| ** Returns          status of the operation
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|     UINT16       tempstate;
 | |
| 
 | |
|     /* Validity check */
 | |
|     if ((sco_inx >= BTM_MAX_SCO_LINKS) || (p->state == SCO_ST_UNUSED)) {
 | |
|         return (BTM_UNKNOWN_ADDR);
 | |
|     }
 | |
| 
 | |
|     /* If no HCI handle, simply drop the connection and return */
 | |
|     if (p->hci_handle == BTM_INVALID_HCI_HANDLE || p->state == SCO_ST_PEND_UNPARK) {
 | |
|         p->hci_handle = BTM_INVALID_HCI_HANDLE;
 | |
|         p->state = SCO_ST_UNUSED;
 | |
|         p->esco.p_esco_cback = NULL;    /* Deregister the eSCO event callback */
 | |
|         return (BTM_SUCCESS);
 | |
|     }
 | |
| 
 | |
|     tempstate = p->state;
 | |
|     p->state = SCO_ST_DISCONNECTING;
 | |
| 
 | |
|     if (!btsnd_hcic_disconnect (p->hci_handle, HCI_ERR_PEER_USER)) {
 | |
|         p->state = tempstate;
 | |
|         return (BTM_NO_RESOURCES);
 | |
|     }
 | |
| 
 | |
|     return (BTM_CMD_STARTED);
 | |
| #else
 | |
|     return (BTM_NO_RESOURCES);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_remove_sco_links
 | |
| **
 | |
| ** Description      This function is called to remove all sco links for an ACL link.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_remove_sco_links (BD_ADDR bda)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
 | |
|     UINT16       xx;
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if (p->rem_bd_known && (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN))) {
 | |
|             BTM_RemoveSco(xx);
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_removed
 | |
| **
 | |
| ** Description      This function is called by BTIF when an SCO connection
 | |
| **                  is removed.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| BOOLEAN btm_sco_removed (UINT16 hci_handle, UINT8 reason)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
 | |
|     UINT16      xx;
 | |
| 
 | |
|     p = &btm_cb.sco_cb.sco_db[0];
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if ((p->state != SCO_ST_UNUSED) && (p->state != SCO_ST_LISTENING) && (p->hci_handle == hci_handle)) {
 | |
|             btm_sco_flush_sco_data(xx);
 | |
|             p->state = SCO_ST_UNUSED;
 | |
| #if BTM_SCO_HCI_INCLUDED == TRUE
 | |
|             btm_cb.sco_cb.xmit_window_size += p->sent_not_acked;
 | |
|             /* avoid overflow */
 | |
|             if (btm_cb.sco_cb.xmit_window_size > btm_cb.sco_cb.num_lm_sco_bufs) {
 | |
|                 btm_cb.sco_cb.xmit_window_size = btm_cb.sco_cb.num_lm_sco_bufs;
 | |
|             }
 | |
|             p->sent_not_acked = 0;
 | |
| #endif
 | |
|             p->hci_handle = BTM_INVALID_HCI_HANDLE;
 | |
|             p->rem_bd_known = FALSE;
 | |
|             p->esco.p_esco_cback = NULL;    /* Deregister eSCO callback */
 | |
|             (*p->p_disc_cb)(xx);
 | |
| 
 | |
|             return TRUE;
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_sco_acl_removed
 | |
| **
 | |
| ** Description      This function is called when an ACL connection is
 | |
| **                  removed. If the BD address is NULL, it is assumed that
 | |
| **                  the local device is down, and all SCO links are removed.
 | |
| **                  If a specific BD address is passed, only SCO connections
 | |
| **                  to that BD address are removed.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_sco_acl_removed (BD_ADDR bda)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
 | |
|     UINT16      xx;
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if (p->state != SCO_ST_UNUSED) {
 | |
|             if ((!bda) || (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN) && p->rem_bd_known)) {
 | |
|                 btm_sco_flush_sco_data(xx);
 | |
| 
 | |
|                 p->state = SCO_ST_UNUSED;
 | |
|                 p->esco.p_esco_cback = NULL;    /* Deregister eSCO callback */
 | |
|                 (*p->p_disc_cb)(xx);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_SetScoPacketTypes
 | |
| **
 | |
| ** Description      This function is called to set the packet types used for
 | |
| **                  a specific SCO connection,
 | |
| **
 | |
| ** Parameters       pkt_types - One or more of the following
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV1
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV2
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV4
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV5
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
 | |
| **
 | |
| **                  BTM_SCO_LINK_ALL_MASK   - enables all supported types
 | |
| **
 | |
| ** Returns          status of the operation
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tBTM_CHG_ESCO_PARAMS parms;
 | |
|     tSCO_CONN           *p;
 | |
| 
 | |
|     /* Validity check */
 | |
|     if (sco_inx >= BTM_MAX_SCO_LINKS) {
 | |
|         return (BTM_UNKNOWN_ADDR);
 | |
|     }
 | |
| 
 | |
|     p = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|     parms.packet_types = pkt_types;
 | |
| 
 | |
|     /* Keep the other parameters the same for SCO */
 | |
|     parms.max_latency = p->esco.setup.max_latency;
 | |
|     parms.retrans_effort = p->esco.setup.retrans_effort;
 | |
| 
 | |
|     return (BTM_ChangeEScoLinkParms(sco_inx, &parms));
 | |
| #else
 | |
|     return (BTM_UNKNOWN_ADDR);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_ReadScoPacketTypes
 | |
| **
 | |
| ** Description      This function is read the packet types used for a specific
 | |
| **                  SCO connection.
 | |
| **
 | |
| ** Returns          Packet types supported for the connection
 | |
| **                  One or more of the following (bitmask):
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV1
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV2
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV4
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV5
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
 | |
| **
 | |
| *******************************************************************************/
 | |
| UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN *p = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
| 
 | |
|     /* Validity check */
 | |
|     if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED)) {
 | |
|         return (p->esco.setup.packet_types);
 | |
|     } else {
 | |
|         return (0);
 | |
|     }
 | |
| #else
 | |
|     return (0);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_ReadDeviceScoPacketTypes
 | |
| **
 | |
| ** Description      This function is read the SCO packet types that
 | |
| **                  the device supports.
 | |
| **
 | |
| ** Returns          Packet types supported by the device.
 | |
| **                  One or more of the following (bitmask):
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV1
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV2
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_HV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV4
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_EV5
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
 | |
| **                  BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
 | |
| **
 | |
| *******************************************************************************/
 | |
| UINT16 BTM_ReadDeviceScoPacketTypes (void)
 | |
| {
 | |
|     return (btm_cb.btm_sco_pkt_types_supported);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_ReadScoHandle
 | |
| **
 | |
| ** Description      This function is used to read the HCI handle used for a specific
 | |
| **                  SCO connection,
 | |
| **
 | |
| ** Returns          handle for the connection, or 0xFFFF if invalid SCO index.
 | |
| **
 | |
| *******************************************************************************/
 | |
| UINT16 BTM_ReadScoHandle (UINT16 sco_inx)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
| 
 | |
|     /* Validity check */
 | |
|     if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED)) {
 | |
|         return (p->hci_handle);
 | |
|     } else {
 | |
|         return (BTM_INVALID_HCI_HANDLE);
 | |
|     }
 | |
| #else
 | |
|     return (BTM_INVALID_HCI_HANDLE);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_ReadScoBdAddr
 | |
| **
 | |
| ** Description      This function is read the remote BD Address for a specific
 | |
| **                  SCO connection,
 | |
| **
 | |
| ** Returns          pointer to BD address or NULL if not known
 | |
| **
 | |
| *******************************************************************************/
 | |
| UINT8 *BTM_ReadScoBdAddr (UINT16 sco_inx)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
| 
 | |
|     /* Validity check */
 | |
|     if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->rem_bd_known)) {
 | |
|         return (p->esco.data.bd_addr);
 | |
|     } else {
 | |
|         return (NULL);
 | |
|     }
 | |
| #else
 | |
|     return (NULL);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_SetEScoMode
 | |
| **
 | |
| ** Description      This function sets up the negotiated parameters for SCO or
 | |
| **                  eSCO, and sets as the default mode used for outgoing calls to
 | |
| **                  BTM_CreateSco.  It does not change any currently active (e)SCO links.
 | |
| **                  Note:  Incoming (e)SCO connections will always use packet types
 | |
| **                      supported by the controller.  If eSCO is not desired the
 | |
| **                      feature should be disabled in the controller's feature mask.
 | |
| **
 | |
| ** Returns          BTM_SUCCESS if the successful.
 | |
| **                  BTM_BUSY if there are one or more active (e)SCO links.
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms)
 | |
| {
 | |
|     tSCO_CB          *p_esco = &btm_cb.sco_cb;
 | |
|     tBTM_ESCO_PARAMS *p_def = &p_esco->def_esco_parms;
 | |
| 
 | |
|     if (p_esco->esco_supported) {
 | |
|         if (p_parms) {
 | |
|             if (sco_mode == BTM_LINK_TYPE_ESCO) {
 | |
|                 *p_def = *p_parms;    /* Save as the default parameters */
 | |
|             } else { /* Load only the SCO packet types */
 | |
|                 p_def->packet_types = p_parms->packet_types;
 | |
|                 p_def->tx_bw            = BTM_64KBITS_RATE;
 | |
|                 p_def->rx_bw            = BTM_64KBITS_RATE;
 | |
|                 p_def->max_latency      = 0x000a;
 | |
|                 p_def->voice_contfmt    = 0x0060;
 | |
|                 p_def->retrans_effort   = 0;
 | |
| 
 | |
|                 /* OR in any exception packet types */
 | |
|                 p_def->packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
 | |
|             }
 | |
|         }
 | |
|         p_esco->desired_sco_mode = sco_mode;
 | |
|         BTM_TRACE_API("BTM_SetEScoMode -> mode %d",  sco_mode);
 | |
|     } else {
 | |
|         p_esco->desired_sco_mode = BTM_LINK_TYPE_SCO;
 | |
|         p_def->packet_types &= BTM_SCO_LINK_ONLY_MASK;
 | |
|         p_def->retrans_effort = 0;
 | |
|         BTM_TRACE_API("BTM_SetEScoMode -> mode SCO (eSCO not supported)");
 | |
|     }
 | |
| 
 | |
|     BTM_TRACE_DEBUG("    txbw 0x%08x, rxbw 0x%08x, max_lat 0x%04x, voice 0x%04x, pkt 0x%04x, rtx effort 0x%02x",
 | |
|                     p_def->tx_bw, p_def->rx_bw, p_def->max_latency,
 | |
|                     p_def->voice_contfmt, p_def->packet_types,
 | |
|                     p_def->retrans_effort);
 | |
| 
 | |
|     return (BTM_SUCCESS);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_RegForEScoEvts
 | |
| **
 | |
| ** Description      This function registers a SCO event callback with the
 | |
| **                  specified instance.  It should be used to received
 | |
| **                  connection indication events and change of link parameter
 | |
| **                  events.
 | |
| **
 | |
| ** Returns          BTM_SUCCESS if the successful.
 | |
| **                  BTM_ILLEGAL_VALUE if there is an illegal sco_inx
 | |
| **                  BTM_MODE_UNSUPPORTED if controller version is not BT1.2 or
 | |
| **                          later or does not support eSCO.
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     if (!btm_cb.sco_cb.esco_supported) {
 | |
|         btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = NULL;
 | |
|         return (BTM_MODE_UNSUPPORTED);
 | |
|     }
 | |
| 
 | |
|     if (sco_inx < BTM_MAX_SCO_LINKS &&
 | |
|             btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_UNUSED) {
 | |
|         btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = p_esco_cback;
 | |
|         return (BTM_SUCCESS);
 | |
|     }
 | |
|     return (BTM_ILLEGAL_VALUE);
 | |
| #else
 | |
|     return (BTM_MODE_UNSUPPORTED);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_ReadEScoLinkParms
 | |
| **
 | |
| ** Description      This function returns the current eSCO link parameters for
 | |
| **                  the specified handle.  This can be called anytime a connection
 | |
| **                  is active, but is typically called after receiving the SCO
 | |
| **                  opened callback.
 | |
| **
 | |
| **                  Note: If called over a 1.1 controller, only the packet types
 | |
| **                        field has meaning.
 | |
| **
 | |
| ** Returns          BTM_SUCCESS if returned data is valid connection.
 | |
| **                  BTM_WRONG_MODE if no connection with a peer device or bad sco_inx.
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     UINT8 index;
 | |
| 
 | |
|     BTM_TRACE_API("BTM_ReadEScoLinkParms -> sco_inx 0x%04x", sco_inx);
 | |
| 
 | |
|     if (sco_inx < BTM_MAX_SCO_LINKS &&
 | |
|             btm_cb.sco_cb.sco_db[sco_inx].state >= SCO_ST_CONNECTED) {
 | |
|         *p_parms = btm_cb.sco_cb.sco_db[sco_inx].esco.data;
 | |
|         return (BTM_SUCCESS);
 | |
|     }
 | |
| 
 | |
|     if (sco_inx == BTM_FIRST_ACTIVE_SCO_INDEX) {
 | |
|         for (index = 0; index < BTM_MAX_SCO_LINKS; index++) {
 | |
|             if (btm_cb.sco_cb.sco_db[index].state >= SCO_ST_CONNECTED) {
 | |
|                 BTM_TRACE_API("BTM_ReadEScoLinkParms the first active SCO index is %d", index);
 | |
|                 *p_parms = btm_cb.sco_cb.sco_db[index].esco.data;
 | |
|                 return (BTM_SUCCESS);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #endif
 | |
| 
 | |
|     BTM_TRACE_API("BTM_ReadEScoLinkParms cannot find the SCO index!");
 | |
|     memset(p_parms, 0, sizeof(tBTM_ESCO_DATA));
 | |
|     return (BTM_WRONG_MODE);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_ChangeEScoLinkParms
 | |
| **
 | |
| ** Description      This function requests renegotiation of the parameters on
 | |
| **                  the current eSCO Link.  If any of the changes are accepted
 | |
| **                  by the controllers, the BTM_ESCO_CHG_EVT event is sent in
 | |
| **                  the tBTM_ESCO_CBACK function with the current settings of
 | |
| **                  the link. The callback is registered through the call to
 | |
| **                  BTM_SetEScoMode.
 | |
| **
 | |
| **                  Note: If called over a SCO link (including 1.1 controller),
 | |
| **                        a change packet type request is sent out instead.
 | |
| **
 | |
| ** Returns          BTM_CMD_STARTED if command is successfully initiated.
 | |
| **                  BTM_NO_RESOURCES - not enough resources to initiate command.
 | |
| **                  BTM_WRONG_MODE if no connection with a peer device or bad sco_inx.
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tBTM_ESCO_PARAMS *p_setup;
 | |
|     tSCO_CONN        *p_sco;
 | |
|     UINT16            temp_pkt_types;
 | |
| 
 | |
|     /* Make sure sco handle is valid and on an active link */
 | |
|     if (sco_inx >= BTM_MAX_SCO_LINKS ||
 | |
|             btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_CONNECTED) {
 | |
|         return (BTM_WRONG_MODE);
 | |
|     }
 | |
| 
 | |
|     p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
 | |
|     p_setup = &p_sco->esco.setup;
 | |
| 
 | |
|     /* If SCO connection OR eSCO not supported just send change packet types */
 | |
|     if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO ||
 | |
|             !btm_cb.sco_cb.esco_supported) {
 | |
|         p_setup->packet_types = p_parms->packet_types &
 | |
|                                 (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_LINK_ONLY_MASK);
 | |
| 
 | |
| 
 | |
|         BTM_TRACE_API("BTM_ChangeEScoLinkParms -> SCO Link for handle 0x%04x, pkt 0x%04x",
 | |
|                       p_sco->hci_handle, p_setup->packet_types);
 | |
| 
 | |
|         if (!btsnd_hcic_change_conn_type (p_sco->hci_handle,
 | |
|                                           BTM_ESCO_2_SCO(p_setup->packet_types))) {
 | |
|             return (BTM_NO_RESOURCES);
 | |
|         }
 | |
|     } else {
 | |
|         temp_pkt_types = (p_parms->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
 | |
|                           btm_cb.btm_sco_pkt_types_supported);
 | |
| 
 | |
|         /* OR in any exception packet types */
 | |
|         temp_pkt_types |= ((p_parms->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
 | |
|                            (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
 | |
| 
 | |
|         BTM_TRACE_API("BTM_ChangeEScoLinkParms -> eSCO Link for handle 0x%04x", p_sco->hci_handle);
 | |
|         BTM_TRACE_API("      txbw 0x%x, rxbw 0x%x, lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
 | |
|                       p_setup->tx_bw, p_setup->rx_bw, p_parms->max_latency,
 | |
|                       p_setup->voice_contfmt, p_parms->retrans_effort, temp_pkt_types);
 | |
| 
 | |
|         /* When changing an existing link, only change latency, retrans, and pkts */
 | |
|         if (!btsnd_hcic_setup_esco_conn(p_sco->hci_handle, p_setup->tx_bw,
 | |
|                                         p_setup->rx_bw, p_parms->max_latency,
 | |
|                                         p_setup->voice_contfmt,
 | |
|                                         p_parms->retrans_effort,
 | |
|                                         temp_pkt_types)) {
 | |
|             return (BTM_NO_RESOURCES);
 | |
|         } else {
 | |
|             p_parms->packet_types = temp_pkt_types;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return (BTM_CMD_STARTED);
 | |
| #else
 | |
|     return (BTM_WRONG_MODE);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_EScoConnRsp
 | |
| **
 | |
| ** Description      This function is called upon receipt of an (e)SCO connection
 | |
| **                  request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
 | |
| **                  the request. Parameters used to negotiate eSCO links.
 | |
| **                  If p_parms is NULL, then values set through BTM_SetEScoMode
 | |
| **                  are used.
 | |
| **                  If the link type of the incoming request is SCO, then only
 | |
| **                  the tx_bw, max_latency, content format, and packet_types are
 | |
| **                  valid.  The hci_status parameter should be
 | |
| **                  ([0x0] to accept, [0x0d..0x0f] to reject)
 | |
| **
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, tBTM_ESCO_PARAMS *p_parms)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     if (sco_inx < BTM_MAX_SCO_LINKS &&
 | |
|             btm_cb.sco_cb.sco_db[sco_inx].state == SCO_ST_W4_CONN_RSP) {
 | |
|         btm_esco_conn_rsp(sco_inx, hci_status,
 | |
|                           btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr,
 | |
|                           p_parms);
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_read_def_esco_mode
 | |
| **
 | |
| ** Description      This function copies the current default esco settings into
 | |
| **                  the return buffer.
 | |
| **
 | |
| ** Returns          tBTM_SCO_TYPE
 | |
| **
 | |
| *******************************************************************************/
 | |
| tBTM_SCO_TYPE btm_read_def_esco_mode (tBTM_ESCO_PARAMS *p_parms)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     *p_parms = btm_cb.sco_cb.def_esco_parms;
 | |
|     return btm_cb.sco_cb.desired_sco_mode;
 | |
| #else
 | |
|     return BTM_LINK_TYPE_SCO;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_esco_proc_conn_chg
 | |
| **
 | |
| ** Description      This function is called by BTIF when an SCO connection
 | |
| **                  is changed.
 | |
| **
 | |
| ** Returns          void
 | |
| **
 | |
| *******************************************************************************/
 | |
| void btm_esco_proc_conn_chg (UINT8 status, UINT16 handle, UINT8 tx_interval,
 | |
|                              UINT8 retrans_window, UINT16 rx_pkt_len,
 | |
|                              UINT16 tx_pkt_len)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN               *p = &btm_cb.sco_cb.sco_db[0];
 | |
|     tBTM_CHG_ESCO_EVT_DATA   data;
 | |
|     UINT16                   xx;
 | |
| 
 | |
|     BTM_TRACE_EVENT("btm_esco_proc_conn_chg -> handle 0x%04x, status 0x%02x",
 | |
|                     handle, status);
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if (p->state == SCO_ST_CONNECTED && handle == p->hci_handle) {
 | |
|             /* If upper layer wants notification */
 | |
|             if (p->esco.p_esco_cback) {
 | |
|                 memcpy(data.bd_addr, p->esco.data.bd_addr, BD_ADDR_LEN);
 | |
|                 data.hci_status = status;
 | |
|                 data.sco_inx = xx;
 | |
|                 data.rx_pkt_len = p->esco.data.rx_pkt_len = rx_pkt_len;
 | |
|                 data.tx_pkt_len = p->esco.data.tx_pkt_len = tx_pkt_len;
 | |
|                 data.tx_interval = p->esco.data.tx_interval = tx_interval;
 | |
|                 data.retrans_window = p->esco.data.retrans_window = retrans_window;
 | |
| 
 | |
|                 (*p->esco.p_esco_cback)(BTM_ESCO_CHG_EVT,
 | |
|                                         (tBTM_ESCO_EVT_DATA *)&data);
 | |
|             }
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_is_sco_active
 | |
| **
 | |
| ** Description      This function is called to see if a SCO handle is already in
 | |
| **                  use.
 | |
| **
 | |
| ** Returns          BOOLEAN
 | |
| **
 | |
| *******************************************************************************/
 | |
| BOOLEAN btm_is_sco_active (UINT16 handle)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     UINT16     xx;
 | |
|     tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if (handle == p->hci_handle && p->state == SCO_ST_CONNECTED) {
 | |
|             return (TRUE);
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
|     return (FALSE);
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         BTM_GetNumScoLinks
 | |
| **
 | |
| ** Description      This function returns the number of active sco links.
 | |
| **
 | |
| ** Returns          UINT8
 | |
| **
 | |
| *******************************************************************************/
 | |
| UINT8 BTM_GetNumScoLinks (void)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
 | |
|     UINT16     xx;
 | |
|     UINT8      num_scos = 0;
 | |
| 
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         switch (p->state) {
 | |
|         case SCO_ST_W4_CONN_RSP:
 | |
|         case SCO_ST_CONNECTING:
 | |
|         case SCO_ST_CONNECTED:
 | |
|         case SCO_ST_DISCONNECTING:
 | |
|         case SCO_ST_PEND_UNPARK:
 | |
|             num_scos++;
 | |
|         }
 | |
|     }
 | |
|     return (num_scos);
 | |
| #else
 | |
|     return (0);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| ** Function         btm_is_sco_active_by_bdaddr
 | |
| **
 | |
| ** Description      This function is called to see if a SCO active to a bd address.
 | |
| **
 | |
| ** Returns          BOOLEAN
 | |
| **
 | |
| *******************************************************************************/
 | |
| BOOLEAN btm_is_sco_active_by_bdaddr (BD_ADDR remote_bda)
 | |
| {
 | |
| #if (BTM_MAX_SCO_LINKS>0)
 | |
|     UINT8 xx;
 | |
|     tSCO_CONN *p = &btm_cb.sco_cb.sco_db[0];
 | |
| 
 | |
|     /* If any SCO is being established to the remote BD address, refuse this */
 | |
|     for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
 | |
|         if ((!memcmp (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN)) && (p->state == SCO_ST_CONNECTED)) {
 | |
|             return (TRUE);
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
|     return (FALSE);
 | |
| }
 | |
| #else   /* SCO_EXCLUDED == TRUE (Link in stubs) */
 | |
| 
 | |
| tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig,
 | |
|                            UINT16 pkt_types, UINT16 *p_sco_inx,
 | |
|                            tBTM_SCO_CB *p_conn_cb,
 | |
|                            tBTM_SCO_CB *p_disc_cb)
 | |
| {
 | |
|     return (BTM_NO_RESOURCES);
 | |
| }
 | |
| tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx)
 | |
| {
 | |
|     return (BTM_NO_RESOURCES);
 | |
| }
 | |
| tBTM_STATUS BTM_SetScoPacketTypes (UINT16 sco_inx, UINT16 pkt_types)
 | |
| {
 | |
|     return (BTM_NO_RESOURCES);
 | |
| }
 | |
| UINT16 BTM_ReadScoPacketTypes (UINT16 sco_inx)
 | |
| {
 | |
|     return (0);
 | |
| }
 | |
| UINT16 BTM_ReadDeviceScoPacketTypes (void)
 | |
| {
 | |
|     return (0);
 | |
| }
 | |
| UINT16 BTM_ReadScoHandle (UINT16 sco_inx)
 | |
| {
 | |
|     return (BTM_INVALID_HCI_HANDLE);
 | |
| }
 | |
| UINT8 *BTM_ReadScoBdAddr(UINT16 sco_inx)
 | |
| {
 | |
|     return ((UINT8 *) NULL);
 | |
| }
 | |
| tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms)
 | |
| {
 | |
|     return (BTM_MODE_UNSUPPORTED);
 | |
| }
 | |
| tBTM_STATUS BTM_RegForEScoEvts (UINT16 sco_inx, tBTM_ESCO_CBACK *p_esco_cback)
 | |
| {
 | |
|     return (BTM_ILLEGAL_VALUE);
 | |
| }
 | |
| tBTM_STATUS BTM_ReadEScoLinkParms (UINT16 sco_inx, tBTM_ESCO_DATA *p_parms)
 | |
| {
 | |
|     return (BTM_MODE_UNSUPPORTED);
 | |
| }
 | |
| tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_parms)
 | |
| {
 | |
|     return (BTM_MODE_UNSUPPORTED);
 | |
| }
 | |
| void BTM_EScoConnRsp (UINT16 sco_inx, UINT8 hci_status, tBTM_ESCO_PARAMS *p_parms) {}
 | |
| UINT8 BTM_GetNumScoLinks (void)
 | |
| {
 | |
|     return (0);
 | |
| }
 | |
| 
 | |
| #endif /* If SCO is being used */
 | 
