OSDN Git Service

Initiate SCO after Mode change event
[android-x86/system-bt.git] / stack / btm / btm_sco.c
index d9d0fbc..8c374f9 100644 (file)
@@ -26,7 +26,7 @@
 #include <string.h>
 #include "bt_types.h"
 #include "bt_target.h"
-#include "gki.h"
+#include "bt_common.h"
 #include "bt_types.h"
 #include "hcimsgs.h"
 #include "btu.h"
@@ -49,6 +49,7 @@
 #define SCO_ST_DISCONNECTING    5
 #define SCO_ST_PEND_UNPARK      6
 #define SCO_ST_PEND_ROLECHANGE  7
+#define SCO_ST_PEND_MODECHANGE  8
 
 /********************************************************************************/
 /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
@@ -88,10 +89,8 @@ void btm_sco_flush_sco_data(UINT16 sco_inx)
     if (sco_inx < BTM_MAX_SCO_LINKS)
     {
         p = &btm_cb.sco_cb.sco_db[sco_inx];
-        while (p->xmit_data_q.p_first)
-        {
-            if ((p_buf = (BT_HDR *)GKI_dequeue (&p->xmit_data_q)) != NULL)
-                GKI_freebuf (p_buf);
+        while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p->xmit_data_q)) != NULL)
+            osi_free(p_buf);
         }
     }
 #else
@@ -115,6 +114,12 @@ 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(SIZE_MAX);
+#endif
+
     /* Initialize nonzero defaults */
     btm_cb.sco_cb.sco_disc_reason  = BTM_INVALID_SCO_DISC_REASON;
 
@@ -176,61 +181,50 @@ static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda,
     else    /* Connection is being accepted */
     {
         p_sco->state = SCO_ST_CONNECTING;
-        if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_1_2)
+        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 = &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;
-            }
+            *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);
+        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;
-
-                if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
-                {
-                    temp_pkt_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
-                }
-            }
-             /* OR in any exception packet types if at least 2.0 version of spec */
-            else if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
-            {
-                temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
-                    (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
-            }
+        /* 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!!!");
-            }
+        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    /* Controller is version 1.1 or earlier */
+        else
         {
-            btsnd_hcic_accept_conn (bda, 0);
+            BTM_TRACE_ERROR("Could not accept SCO conn: No Buffer!!!");
         }
     }
 #endif
@@ -250,21 +244,19 @@ static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda,
 *******************************************************************************/
 void btm_sco_check_send_pkts (UINT16 sco_inx)
 {
-    BT_HDR  *p_buf;
     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 */
-    while (p_ccb->xmit_data_q.p_first != NULL)
+    BT_HDR  *p_buf;
+    while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) != NULL)
     {
-        p_buf = NULL;
-
 #if BTM_SCO_HCI_DEBUG
-        BTM_TRACE_DEBUG ("btm: [%d] buf in xmit_data_q", p_ccb->xmit_data_q.count );
+        BTM_TRACE_DEBUG("btm: [%d] buf in xmit_data_q",
+                        fixed_queue_length(p_ccb->xmit_data_q) + 1);
 #endif
-        p_buf = (BT_HDR *)GKI_dequeue (&p_ccb->xmit_data_q);
 
-        HCI_SCO_DATA_TO_LOWER (p_buf);
+        HCI_SCO_DATA_TO_LOWER(p_buf);
     }
 }
 #endif /* BTM_SCO_HCI_INCLUDED == TRUE */
@@ -298,7 +290,7 @@ void  btm_route_sco_data(BT_HDR *p_msg)
         /* send data callback */
         if (!btm_cb.sco_cb.p_data_cb )
             /* if no data callback registered,  just free the buffer  */
-            GKI_freebuf (p_msg);
+            osi_free(p_msg);
         else
         {
             (*btm_cb.sco_cb.p_data_cb)(sco_inx, p_msg, (tBTM_SCO_DATA_FLAG) pkt_status);
@@ -306,10 +298,10 @@ void  btm_route_sco_data(BT_HDR *p_msg)
     }
     else /* no mapping handle SCO connection is active, free the buffer */
     {
-        GKI_freebuf (p_msg);
+        osi_free(p_msg);
     }
 #else
-    GKI_freebuf(p_msg);
+    osi_free(p_msg);
 #endif
 }
 
@@ -348,7 +340,7 @@ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
         if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE)
         {
             BTM_TRACE_ERROR ("BTM SCO - cannot send buffer, offset: %d", p_buf->offset);
-            GKI_freebuf (p_buf);
+            osi_free(p_buf);
             status = BTM_ILLEGAL_VALUE;
         }
         else    /* write HCI header */
@@ -370,14 +362,14 @@ tBTM_STATUS BTM_WriteScoData (UINT16 sco_inx, BT_HDR *p_buf)
             UINT8_TO_STREAM (p, (UINT8)p_buf->len);
             p_buf->len += HCI_SCO_PREAMBLE_SIZE;
 
-            GKI_enqueue (&p_ccb->xmit_data_q, p_buf);
+            fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf);
 
             btm_sco_check_send_pkts (sco_inx);
         }
     }
     else
     {
-        GKI_freebuf(p_buf);
+        osi_free(p_buf);
 
         BTM_TRACE_WARNING ("BTM_WriteScoData, invalid sco index: %d at state [%d]",
             sco_inx, btm_cb.sco_cb.sco_db[sco_inx].state);
@@ -421,12 +413,9 @@ static tBTM_STATUS btm_send_connect_request(UINT16 acl_handle,
         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 at least 2.0 version of spec */
-        if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
-        {
-            temp_pkt_types |= ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
-                (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
-        }
+        /* 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 */
@@ -448,6 +437,29 @@ static tBTM_STATUS btm_send_connect_request(UINT16 acl_handle,
                 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_PKT_TYPE_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 == 0)
+                {
+                    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__);
+            }
         }
 
 
@@ -570,12 +582,12 @@ tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 pkt_types
     UINT16            temp_pkt_types;
     tACL_CONN        *p_acl;
 
-#if (BTM_PWR_MGR_INCLUDED == TRUE) && (BTM_SCO_WAKE_PARKED_LINK == TRUE)
-    tBTM_PM_MODE      md;
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
     tBTM_PM_PWR_MD    pm;
+    tBTM_PM_STATE     state;
 #else
     UINT8             mode;
-#endif
+#endif  // BTM_SCO_WAKE_PARKED_LINK
 
     *p_sco_inx = BTM_INVALID_SCO_INDEX;
 
@@ -619,24 +631,23 @@ tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 pkt_types
                 if (is_orig)
                 {
                     /* can not create SCO link if in park mode */
-#if (BTM_PWR_MGR_INCLUDED == TRUE) && (BTM_SCO_WAKE_PARKED_LINK == TRUE)
-                    if(BTM_ReadPowerMode(remote_bda, &md) == BTM_SUCCESS)
+#if BTM_SCO_WAKE_PARKED_LINK == TRUE
+                    if ((btm_read_power_mode_state(p->esco.data.bd_addr, &state) == BTM_SUCCESS))
                     {
-                        if (md == BTM_PM_MD_PARK || md == BTM_PM_MD_SNIFF)
+                        if (state == BTM_PM_ST_SNIFF || state == BTM_PM_ST_PARK ||
+                            state == BTM_PM_ST_PENDING)
                         {
+                            BTM_TRACE_DEBUG("%s In sniff, park or pend mode: %d", __func__, state);
                             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;
                         }
                     }
-#elif BTM_PWR_MGR_INCLUDED == TRUE
+#else  // BTM_SCO_WAKE_PARKED_LINK
                     if( (BTM_ReadPowerMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_PM_MD_PARK) )
                         return (BTM_WRONG_MODE);
-#else
-                    if( (BTM_ReadAclMode(remote_bda, &mode) == BTM_SUCCESS) && (mode == BTM_ACL_MODE_PARK) )
-                        return (BTM_WRONG_MODE);
-#endif
+#endif  // BTM_SCO_WAKE_PARKED_LINK
                 }
                 memcpy (p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN);
                 p->rem_bd_known = TRUE;
@@ -656,18 +667,15 @@ tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 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 at least 2.0 version of spec */
-            if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
+            /* OR in any exception packet types */
+            if (btm_cb.sco_cb.desired_sco_mode == HCI_LINK_TYPE_ESCO)
             {
-                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;
-                }
+                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;
@@ -719,7 +727,7 @@ tBTM_STATUS BTM_CreateSco (BD_ADDR remote_bda, BOOLEAN is_orig, UINT16 pkt_types
     return (BTM_NO_RESOURCES);
 }
 
-#if (BTM_PWR_MGR_INCLUDED == TRUE) && (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
 /*******************************************************************************
 **
 ** Function         btm_sco_chk_pend_unpark
@@ -750,9 +758,9 @@ void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle)
                 p->state = SCO_ST_CONNECTING;
         }
     }
-#endif
+#endif  // BTM_MAX_SCO_LINKS
 }
-#endif
+#endif  // BTM_SCO_WAKE_PARKED_LINK
 
 /*******************************************************************************
 **
@@ -788,6 +796,37 @@ void btm_sco_chk_pend_rolechange (UINT16 hci_handle)
 
 /*******************************************************************************
 **
+** Function        btm_sco_disc_chk_pend_for_modechange
+**
+** Description     This function is called by btm when there is a mode change
+**                 event to see if there are SCO  disconnect commands waiting for the mode change.
+**
+** Returns         void
+**
+*******************************************************************************/
+void btm_sco_disc_chk_pend_for_modechange (UINT16 hci_handle)
+{
+#if (BTM_MAX_SCO_LINKS>0)
+    tSCO_CONN   *p = &btm_cb.sco_cb.sco_db[0];
+
+    BTM_TRACE_DEBUG("%s: hci_handle 0x%04x, p->state 0x%02x", __func__,
+                     hci_handle, p->state);
+
+    for (UINT16 xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++)
+    {
+        if ((p->state == SCO_ST_PEND_MODECHANGE) &&
+            (BTM_GetHCIConnHandle (p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle)
+
+        {
+            BTM_TRACE_DEBUG("%s: SCO Link handle 0x%04x", __func__, p->hci_handle);
+            BTM_RemoveSco(xx);
+        }
+    }
+#endif
+}
+
+/*******************************************************************************
+**
 ** Function         btm_sco_conn_req
 **
 ** Description      This function is called by BTIF when an SCO connection
@@ -810,8 +849,10 @@ void btm_sco_conn_req (BD_ADDR bda,  DEV_CLASS dev_class, UINT8 link_type)
          * If the sco state is in the SCO_ST_CONNECTING state, we still need
          * to return accept sco to avoid race conditon for sco creation
          */
-        if (((p->state == SCO_ST_LISTENING && p->rem_bd_known) || p->state == SCO_ST_CONNECTING)
-         && (!memcmp (p->esco.data.bd_addr, bda, BD_ADDR_LEN)))
+        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;
@@ -1022,6 +1063,9 @@ 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;
+    tBTM_PM_STATE   state = BTM_PM_ST_INVALID;
+
+    BTM_TRACE_DEBUG("%s", __func__);
 
     /* Validity check */
     if ((sco_inx >= BTM_MAX_SCO_LINKS) || (p->state == SCO_ST_UNUSED))
@@ -1036,6 +1080,15 @@ tBTM_STATUS BTM_RemoveSco (UINT16 sco_inx)
         return (BTM_SUCCESS);
     }
 
+    if ((btm_read_power_mode_state(p->esco.data.bd_addr, &state) == BTM_SUCCESS)
+        && state == BTM_PM_ST_PENDING)
+    {
+        BTM_TRACE_DEBUG("%s: BTM_PM_ST_PENDING for ACL mapped with SCO Link 0x%04x",
+                          __func__, p->hci_handle);
+        p->state = SCO_ST_PEND_MODECHANGE;
+        return (BTM_CMD_STARTED);
+    }
+
     tempstate = p->state;
     p->state = SCO_ST_DISCONNECTING;
 
@@ -1366,11 +1419,8 @@ tBTM_STATUS BTM_SetEScoMode (tBTM_SCO_TYPE sco_mode, tBTM_ESCO_PARAMS *p_parms)
                 p_def->voice_contfmt    = 0x0060;
                 p_def->retrans_effort   = 0;
 
-                /* OR in any exception packet types if at least 2.0 version of spec */
-                if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
-                {
-                    p_def->packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
-                }
+                /* OR in any exception packet types */
+                p_def->packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
             }
         }
         p_esco->desired_sco_mode = sco_mode;
@@ -1534,12 +1584,9 @@ tBTM_STATUS BTM_ChangeEScoLinkParms (UINT16 sco_inx, tBTM_CHG_ESCO_PARAMS *p_par
         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 if at least 2.0 version of spec */
-        if (btm_cb.devcb.local_version.hci_version >= HCI_PROTO_VERSION_2_0)
-        {
-            temp_pkt_types |= ((p_parms->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
-                (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
-        }
+        /* 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",