OSDN Git Service

Avoid sending SCO disconnect when power mode is processing
authorMallikarjuna GB <gbmalli@codeaurora.org>
Sat, 30 May 2015 18:03:58 +0000 (23:33 +0530)
committerAndre Eisenbach <eisenbach@google.com>
Wed, 23 Mar 2016 17:43:19 +0000 (17:43 +0000)
Use case:
1. Pair and connect with Mercedes car kit.
2. Answer incoming call by phone or car kit.
3. Switch audio between car kit and phone.
4. Repease 1-3 steps.

Failure:
Car kit is going into bad state and not accepting SCO disconnect.

Root cause:
Phone has sent SCO disconnect command to car kit when
power mode command(sniff/unsniff) is in the processing
on the ACL where SCO is active. Car kit didn't accept
remove SCO request command and gone into bad state.

Fix:
AG should send sco disconnect once power mode change is completed
to avoid this failure.

Change-Id: I7eba162a8fd9615795009ab26005535a3e5c7e86

stack/btm/btm_int.h
stack/btm/btm_pm.c
stack/btm/btm_sco.c

index 0561f27..4bbc656 100644 (file)
@@ -406,6 +406,8 @@ extern 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);
 extern void     btm_reject_sco_link(UINT16 sco_inx );
 extern void btm_sco_chk_pend_rolechange (UINT16 hci_handle);
+extern void btm_sco_disc_chk_pend_for_modechange (UINT16 hci_handle);
+
 #else
 #define btm_accept_sco_link(sco_inx, p_setup, p_conn_cb, p_disc_cb)
 #define btm_reject_sco_link(sco_inx)
@@ -642,7 +644,8 @@ enum
     BTM_PM_ST_HOLD    = BTM_PM_STS_HOLD,
     BTM_PM_ST_SNIFF   = BTM_PM_STS_SNIFF,
     BTM_PM_ST_PARK    = BTM_PM_STS_PARK,
-    BTM_PM_ST_PENDING = BTM_PM_STS_PENDING
+    BTM_PM_ST_PENDING = BTM_PM_STS_PENDING,
+    BTM_PM_ST_INVALID = 0xFF
 };
 typedef UINT8 tBTM_PM_STATE;
 
@@ -989,6 +992,8 @@ extern void btm_pm_proc_cmd_status(UINT8 status);
 extern void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode,
                                      UINT16 interval);
 extern void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len);
+extern tBTM_STATUS btm_read_power_mode_state (BD_ADDR remote_bda,
+                                                      tBTM_PM_STATE *pmState);
 #if BTM_SCO_INCLUDED == TRUE
 extern void btm_sco_chk_pend_unpark (UINT8 hci_status, UINT16 hci_handle);
 #else
index 95046fb..e24563b 100644 (file)
@@ -294,6 +294,38 @@ tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
 
 /*******************************************************************************
 **
+** Function         btm_read_power_mode_state
+**
+** Description      This returns the current pm state for a specific
+**                  ACL connection.
+**
+** Input Param      remote_bda - device address of desired ACL connection
+**
+** Output Param     pmState - address where the current  pm state is copied into.
+**                          BTM_PM_ST_ACTIVE
+**                          BTM_PM_ST_HOLD
+**                          BTM_PM_ST_SNIFF
+**                          BTM_PM_ST_PARK
+**                          BTM_PM_ST_PENDING
+**                          (valid only if return code is BTM_SUCCESS)
+**
+** Returns          BTM_SUCCESS if successful,
+**                  BTM_UNKNOWN_ADDR if bd addr is not active or bad
+**
+*******************************************************************************/
+tBTM_STATUS btm_read_power_mode_state (BD_ADDR remote_bda, tBTM_PM_STATE *pmState)
+{
+    int acl_ind = btm_pm_find_acl_ind(remote_bda);
+
+    if( acl_ind == MAX_L2CAP_LINKS)
+        return (BTM_UNKNOWN_ADDR);
+
+    *pmState = btm_cb.pm_mode_db[acl_ind].state;
+    return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+**
 ** Function         BTM_SetSsrParams
 **
 ** Description      This sends the given SSR parameters for the given ACL
@@ -851,6 +883,10 @@ void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, U
             (*btm_cb.pm_reg_db[yy].cback)( p->remote_addr, mode, interval, hci_status);
         }
     }
+#if BTM_SCO_INCLUDED == TRUE
+    /*check if sco disconnect  is waiting for the mode change */
+    btm_sco_disc_chk_pend_for_modechange(hci_handle);
+#endif
 
     /* If mode change was because of an active role switch or change link key */
     btm_cont_rswitch(p, btm_find_dev(p->remote_addr), hci_status);
index 62916d1..24a4d6c 100644 (file)
@@ -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            */
@@ -793,6 +794,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
@@ -1029,6 +1061,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))
@@ -1043,6 +1078,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;