Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0aee6870 authored by Mallikarjuna GB's avatar Mallikarjuna GB Committed by Andre Eisenbach
Browse files

Avoid sending SCO disconnect when power mode is processing

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
parent db169872
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -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
+36 −0
Original line number Diff line number Diff line
@@ -292,6 +292,38 @@ tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
    return BTM_SUCCESS;
}

/*******************************************************************************
**
** 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
@@ -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);
+44 −0
Original line number Diff line number Diff line
@@ -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            */
@@ -791,6 +792,37 @@ void btm_sco_chk_pend_rolechange (UINT16 hci_handle)
#endif
}

/*******************************************************************************
**
** 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
@@ -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;