Home | History | Annotate | Download | only in btm
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2000-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 /*****************************************************************************
     20  *
     21  *  This file contains functions that manages ACL link modes.
     22  *  This includes operations such as active, hold,
     23  *  park and sniff modes.
     24  *
     25  *  This module contains both internal and external (API)
     26  *  functions. External (API) functions are distinguishable
     27  *  by their names beginning with uppercase BTM.
     28  *
     29  *****************************************************************************/
     30 
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <stdio.h>
     34 #include <stddef.h>
     35 #include "bt_types.h"
     36 #include "gki.h"
     37 #include "hcimsgs.h"
     38 #include "btu.h"
     39 #include "btm_api.h"
     40 #include "btm_int.h"
     41 #include "l2c_int.h"
     42 #include "hcidefs.h"
     43 #include "bt_utils.h"
     44 
     45 #if BTM_PWR_MGR_INCLUDED == TRUE
     46 
     47 /* This compile option is only useful when the FW has a bug
     48  * it automatically uses single slot when entering SNIFF mode, but does not restore the setting
     49  * This issue was found when A2DP link goes into sniff and existing sniff still has choppy audio.
     50  * If this issue is seen, look for FW solution first.
     51  * This work around code will be removed later. */
     52 #ifndef BTM_PM_SNIFF_SLOT_WORK_AROUND
     53 #define BTM_PM_SNIFF_SLOT_WORK_AROUND       FALSE
     54 #endif
     55 
     56 /*****************************************************************************/
     57 /*      to handle different modes                                            */
     58 /*****************************************************************************/
     59 #define BTM_PM_STORED_MASK      0x80 /* set this mask if the command is stored */
     60 #define BTM_PM_NUM_SET_MODES    3 /* only hold, sniff & park */
     61 
     62 /* Usage:  (ptr_features[ offset ] & mask )?TRUE:FALSE */
     63 /* offset to supported feature */
     64 const UINT8 btm_pm_mode_off[BTM_PM_NUM_SET_MODES] = {0,    0,    1};
     65 /* mask to supported feature */
     66 const UINT8 btm_pm_mode_msk[BTM_PM_NUM_SET_MODES] = {0x40, 0x80, 0x01};
     67 
     68 #define BTM_PM_GET_MD1      1
     69 #define BTM_PM_GET_MD2      2
     70 #define BTM_PM_GET_COMP     3
     71 
     72 const UINT8 btm_pm_md_comp_matrix[BTM_PM_NUM_SET_MODES*BTM_PM_NUM_SET_MODES] =
     73 {
     74     BTM_PM_GET_COMP,
     75     BTM_PM_GET_MD2,
     76     BTM_PM_GET_MD2,
     77 
     78     BTM_PM_GET_MD1,
     79     BTM_PM_GET_COMP,
     80     BTM_PM_GET_MD1,
     81 
     82     BTM_PM_GET_MD1,
     83     BTM_PM_GET_MD2,
     84     BTM_PM_GET_COMP
     85 };
     86 
     87 /* function prototype */
     88 static int btm_pm_find_acl_ind(BD_ADDR remote_bda);
     89 static tBTM_STATUS btm_pm_snd_md_req( UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode );
     90 
     91 /*
     92 #ifdef BTM_PM_DEBUG
     93 #undef BTM_PM_DEBUG
     94 #define BTM_PM_DEBUG    TRUE
     95 #endif
     96 */
     97 
     98 #if BTM_PM_DEBUG == TRUE
     99 const char * btm_pm_state_str[] =
    100 {
    101     "pm_active_state",
    102     "pm_hold_state",
    103     "pm_sniff_state",
    104     "pm_park_state",
    105     "pm_pend_state"
    106 };
    107 
    108 const char * btm_pm_event_str[] =
    109 {
    110     "pm_set_mode_event",
    111     "pm_hci_sts_event",
    112     "pm_mod_chg_event",
    113     "pm_update_event"
    114 };
    115 
    116 const char * btm_pm_action_str[] =
    117 {
    118     "pm_set_mode_action",
    119     "pm_update_db_action",
    120     "pm_mod_chg_action",
    121     "pm_hci_sts_action",
    122     "pm_update_action"
    123 };
    124 #endif
    125 
    126 /*****************************************************************************/
    127 /*                     P U B L I C  F U N C T I O N S                        */
    128 /*****************************************************************************/
    129 /*******************************************************************************
    130 **
    131 ** Function         BTM_PmRegister
    132 **
    133 ** Description      register or deregister with power manager
    134 **
    135 ** Returns          BTM_SUCCESS if successful,
    136 **                  BTM_NO_RESOURCES if no room to hold registration
    137 **                  BTM_ILLEGAL_VALUE
    138 **
    139 *******************************************************************************/
    140 tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
    141 {
    142     int xx;
    143 
    144     /* de-register */
    145     if(mask & BTM_PM_DEREG)
    146     {
    147         if(*p_pm_id >= BTM_MAX_PM_RECORDS)
    148             return BTM_ILLEGAL_VALUE;
    149         btm_cb.pm_reg_db[*p_pm_id].mask = BTM_PM_REC_NOT_USED;
    150         return BTM_SUCCESS;
    151     }
    152 
    153     for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
    154     {
    155         /* find an unused entry */
    156         if(btm_cb.pm_reg_db[xx].mask == BTM_PM_REC_NOT_USED)
    157         {
    158             /* if register for notification, should provide callback routine */
    159             if(mask & BTM_PM_REG_NOTIF)
    160             {
    161                 if(p_cb == NULL)
    162                     return BTM_ILLEGAL_VALUE;
    163                 btm_cb.pm_reg_db[xx].cback = p_cb;
    164             }
    165             btm_cb.pm_reg_db[xx].mask = mask;
    166             *p_pm_id = xx;
    167             return BTM_SUCCESS;
    168         }
    169     }
    170 
    171     return BTM_NO_RESOURCES;
    172 }
    173 
    174 /*******************************************************************************
    175 **
    176 ** Function         BTM_SetPowerMode
    177 **
    178 ** Description      store the mode in control block or
    179 **                  alter ACL connection behavior.
    180 **
    181 ** Returns          BTM_SUCCESS if successful,
    182 **                  BTM_UNKNOWN_ADDR if bd addr is not active or bad
    183 **
    184 *******************************************************************************/
    185 tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
    186 {
    187     UINT8               *p_features;
    188     int               ind, acl_ind;
    189     tBTM_PM_MCB *p_cb = NULL;   /* per ACL link */
    190     tBTM_PM_MODE        mode;
    191     int                 temp_pm_id;
    192 
    193 
    194     if(pm_id >= BTM_MAX_PM_RECORDS)
    195         pm_id = BTM_PM_SET_ONLY_ID;
    196 
    197     if(p_mode == NULL)
    198         return BTM_ILLEGAL_VALUE;
    199 
    200     BTM_TRACE_API( "BTM_SetPowerMode: pm_id %d BDA: %08x mode:0x%x", pm_id,
    201                    (remote_bda[2]<<24)+(remote_bda[3]<<16)+(remote_bda[4]<<8)+remote_bda[5], p_mode->mode);
    202 
    203     /* take out the force bit */
    204     mode = p_mode->mode & ~BTM_PM_MD_FORCE;
    205 
    206     acl_ind = btm_pm_find_acl_ind(remote_bda);
    207     if(acl_ind == MAX_L2CAP_LINKS)
    208         return (BTM_UNKNOWN_ADDR);
    209 
    210     p_cb = &(btm_cb.pm_mode_db[acl_ind]);
    211 
    212     if(mode != BTM_PM_MD_ACTIVE)
    213     {
    214         /* check if the requested mode is supported */
    215         ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
    216         p_features = BTM_ReadLocalFeatures();
    217         if( !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) )
    218             return BTM_MODE_UNSUPPORTED;
    219     }
    220 
    221     if(mode == p_cb->state) /* the requested mode is current mode */
    222     {
    223         /* already in the requested mode and the current interval has less latency than the max */
    224         if( (mode == BTM_PM_MD_ACTIVE) ||
    225             ((p_mode->mode & BTM_PM_MD_FORCE) && (p_mode->max >= p_cb->interval) && (p_mode->min <= p_cb->interval)) ||
    226             ((p_mode->mode & BTM_PM_MD_FORCE)==0 && (p_mode->max >= p_cb->interval)) )
    227         {
    228             BTM_TRACE_DEBUG( "BTM_SetPowerMode: mode:0x%x interval %d max:%d, min:%d", p_mode->mode, p_cb->interval, p_mode->max, p_mode->min);
    229             return BTM_SUCCESS;
    230         }
    231     }
    232 
    233     temp_pm_id = pm_id;
    234     if(pm_id == BTM_PM_SET_ONLY_ID)
    235         temp_pm_id = BTM_MAX_PM_RECORDS;
    236 
    237     /* update mode database */
    238     if( ((pm_id != BTM_PM_SET_ONLY_ID) &&
    239          (btm_cb.pm_reg_db[pm_id].mask & BTM_PM_REG_SET))
    240        || ((pm_id == BTM_PM_SET_ONLY_ID) && (btm_cb.pm_pend_link != MAX_L2CAP_LINKS)) )
    241     {
    242 #if BTM_PM_DEBUG == TRUE
    243     BTM_TRACE_DEBUG( "BTM_SetPowerMode: Saving cmd acl_ind %d temp_pm_id %d", acl_ind,temp_pm_id);
    244 #endif
    245         /* Make sure mask is set to BTM_PM_REG_SET */
    246         btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET;
    247         *(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD *)p_mode);
    248         p_cb->chg_ind = TRUE;
    249     }
    250 
    251 #if BTM_PM_DEBUG == TRUE
    252     BTM_TRACE_DEBUG( "btm_pm state:0x%x, pm_pend_link: %d", p_cb->state, btm_cb.pm_pend_link);
    253 #endif
    254     /* if mode == hold or pending, return */
    255     if( (p_cb->state == BTM_PM_STS_HOLD) ||
    256         (p_cb->state ==  BTM_PM_STS_PENDING) ||
    257         (btm_cb.pm_pend_link != MAX_L2CAP_LINKS) ) /* command pending */
    258     {
    259         if(acl_ind != btm_cb.pm_pend_link)
    260         {
    261             /* set the stored mask */
    262             p_cb->state |= BTM_PM_STORED_MASK;
    263             BTM_TRACE_DEBUG( "btm_pm state stored:%d",acl_ind);
    264         }
    265         return BTM_CMD_STORED;
    266     }
    267 
    268 
    269 
    270     return btm_pm_snd_md_req(pm_id, acl_ind, p_mode);
    271 }
    272 
    273 /*******************************************************************************
    274 **
    275 ** Function         BTM_ReadPowerMode
    276 **
    277 ** Description      This returns the current mode for a specific
    278 **                  ACL connection.
    279 **
    280 ** Input Param      remote_bda - device address of desired ACL connection
    281 **
    282 ** Output Param     p_mode - address where the current mode is copied into.
    283 **                          BTM_ACL_MODE_NORMAL
    284 **                          BTM_ACL_MODE_HOLD
    285 **                          BTM_ACL_MODE_SNIFF
    286 **                          BTM_ACL_MODE_PARK
    287 **                          (valid only if return code is BTM_SUCCESS)
    288 **
    289 ** Returns          BTM_SUCCESS if successful,
    290 **                  BTM_UNKNOWN_ADDR if bd addr is not active or bad
    291 **
    292 *******************************************************************************/
    293 tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
    294 {
    295     int acl_ind;
    296 
    297     if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
    298         return (BTM_UNKNOWN_ADDR);
    299 
    300     *p_mode = btm_cb.pm_mode_db[acl_ind].state;
    301     return BTM_SUCCESS;
    302 }
    303 
    304 /*******************************************************************************
    305 **
    306 ** Function         BTM_SetSsrParams
    307 **
    308 ** Description      This sends the given SSR parameters for the given ACL
    309 **                  connection if it is in ACTIVE mode.
    310 **
    311 ** Input Param      remote_bda - device address of desired ACL connection
    312 **                  max_lat    - maximum latency (in 0.625ms)(0-0xFFFE)
    313 **                  min_rmt_to - minimum remote timeout
    314 **                  min_loc_to - minimum local timeout
    315 **
    316 **
    317 ** Returns          BTM_SUCCESS if the HCI command is issued successful,
    318 **                  BTM_UNKNOWN_ADDR if bd addr is not active or bad
    319 **                  BTM_CMD_STORED if the command is stored
    320 **
    321 *******************************************************************************/
    322 tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat,
    323                               UINT16 min_rmt_to, UINT16 min_loc_to)
    324 {
    325 #if (BTM_SSR_INCLUDED == TRUE)
    326     int acl_ind;
    327     tBTM_PM_MCB *p_cb;
    328 
    329     if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
    330         return (BTM_UNKNOWN_ADDR);
    331 
    332     if(BTM_PM_STS_ACTIVE == btm_cb.pm_mode_db[acl_ind].state ||
    333         BTM_PM_STS_SNIFF == btm_cb.pm_mode_db[acl_ind].state)
    334     {
    335         if (btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[acl_ind].hci_handle, max_lat,
    336                                       min_rmt_to, min_loc_to))
    337             return BTM_SUCCESS;
    338         else
    339             return BTM_NO_RESOURCES;
    340     }
    341     p_cb = &btm_cb.pm_mode_db[acl_ind];
    342     p_cb->max_lat       = max_lat;
    343     p_cb->min_rmt_to    = min_rmt_to;
    344     p_cb->min_loc_to    = min_loc_to;
    345     return BTM_CMD_STORED;
    346 #else
    347     return BTM_ILLEGAL_ACTION;
    348 #endif
    349 }
    350 
    351 /*******************************************************************************
    352 **
    353 ** Function         btm_pm_reset
    354 **
    355 ** Description      as a part of the BTM reset process.
    356 **
    357 ** Returns          void
    358 **
    359 *******************************************************************************/
    360 void btm_pm_reset(void)
    361 {
    362     int xx;
    363     tBTM_PM_STATUS_CBACK *cb = NULL;
    364 
    365     /* clear the pending request for application */
    366     if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
    367         (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
    368     {
    369         cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
    370     }
    371 
    372 
    373     /* clear the register record */
    374     for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
    375     {
    376         btm_cb.pm_reg_db[xx].mask = BTM_PM_REC_NOT_USED;
    377     }
    378 
    379     if(cb != NULL && btm_cb.pm_pend_link < MAX_L2CAP_LINKS)
    380         (*cb)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, BTM_PM_STS_ERROR, BTM_DEV_RESET, 0);
    381 
    382     /* no command pending */
    383     btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
    384 }
    385 
    386 /*******************************************************************************
    387 **
    388 ** Function         btm_pm_sm_alloc
    389 **
    390 ** Description      This function initializes the control block of an ACL link.
    391 **                  It is called when an ACL connection is created.
    392 **
    393 ** Returns          void
    394 **
    395 *******************************************************************************/
    396 void btm_pm_sm_alloc(UINT8 ind)
    397 {
    398     tBTM_PM_MCB *p_db = &btm_cb.pm_mode_db[ind];   /* per ACL link */
    399     memset (p_db, 0, sizeof(tBTM_PM_MCB));
    400     p_db->state = BTM_PM_ST_ACTIVE;
    401 #if BTM_PM_DEBUG == TRUE
    402     BTM_TRACE_DEBUG( "btm_pm_sm_alloc ind:%d st:%d", ind, p_db->state);
    403 #endif
    404 }
    405 
    406 /*******************************************************************************
    407 **
    408 ** Function         btm_pm_find_acl_ind
    409 **
    410 ** Description      This function initializes the control block of an ACL link.
    411 **                  It is called when an ACL connection is created.
    412 **
    413 ** Returns          void
    414 **
    415 *******************************************************************************/
    416 static int btm_pm_find_acl_ind(BD_ADDR remote_bda)
    417 {
    418     tACL_CONN   *p = &btm_cb.acl_db[0];
    419     UINT8 xx;
    420 
    421     for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
    422     {
    423         if ((p->in_use) && (!memcmp (p->remote_addr, remote_bda, BD_ADDR_LEN))
    424 #if (BLE_INCLUDED == TRUE)
    425             && p->transport == BT_TRANSPORT_BR_EDR
    426 #endif
    427             )
    428         {
    429 #if BTM_PM_DEBUG == TRUE
    430             BTM_TRACE_DEBUG( "btm_pm_find_acl_ind ind:%d, st:%d", xx, btm_cb.pm_mode_db[xx].state);
    431 #endif
    432             break;
    433         }
    434     }
    435     return xx;
    436 }
    437 
    438 /*******************************************************************************
    439 **
    440 ** Function     btm_pm_compare_modes
    441 ** Description  get the "more active" mode of the 2
    442 ** Returns      void
    443 **
    444 *******************************************************************************/
    445 static tBTM_PM_PWR_MD * btm_pm_compare_modes(tBTM_PM_PWR_MD *p_md1, tBTM_PM_PWR_MD *p_md2, tBTM_PM_PWR_MD *p_res)
    446 {
    447     UINT8 res;
    448 
    449     if(p_md1 == NULL)
    450     {
    451         *p_res = *p_md2;
    452         p_res->mode &= ~BTM_PM_MD_FORCE;
    453 
    454         return p_md2;
    455     }
    456 
    457     if(p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE)
    458     {
    459         return NULL;
    460     }
    461 
    462     /* check if force bit is involved */
    463     if(p_md1->mode & BTM_PM_MD_FORCE)
    464     {
    465         *p_res = *p_md1;
    466         p_res->mode &= ~BTM_PM_MD_FORCE;
    467         return p_res;
    468     }
    469 
    470     if(p_md2->mode & BTM_PM_MD_FORCE)
    471     {
    472         *p_res = *p_md2;
    473         p_res->mode &= ~BTM_PM_MD_FORCE;
    474         return p_res;
    475     }
    476 
    477     res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1);
    478     res = btm_pm_md_comp_matrix[res];
    479     switch(res)
    480     {
    481     case BTM_PM_GET_MD1:
    482         *p_res = *p_md1;
    483         return p_md1;
    484 
    485     case BTM_PM_GET_MD2:
    486         *p_res = *p_md2;
    487         return p_md2;
    488 
    489     case BTM_PM_GET_COMP:
    490         p_res->mode = p_md1->mode;
    491         /* min of the two */
    492         p_res->max  = (p_md1->max < p_md2->max)? (p_md1->max) : (p_md2->max);
    493         /* max of the two */
    494         p_res->min  = (p_md1->min > p_md2->min)? (p_md1->min) : (p_md2->min);
    495 
    496         /* the intersection is NULL */
    497         if( p_res->max < p_res->min)
    498             return NULL;
    499 
    500         if(p_res->mode == BTM_PM_MD_SNIFF)
    501         {
    502             /* max of the two */
    503             p_res->attempt  = (p_md1->attempt > p_md2->attempt)? (p_md1->attempt) : (p_md2->attempt);
    504             p_res->timeout  = (p_md1->timeout > p_md2->timeout)? (p_md1->timeout) : (p_md2->timeout);
    505         }
    506         return p_res;
    507     }
    508     return NULL;
    509 }
    510 
    511 /*******************************************************************************
    512 **
    513 ** Function     btm_pm_get_set_mode
    514 ** Description  get the resulting mode from the registered parties, then compare it
    515 **              with the requested mode, if the command is from an unregistered party.
    516 ** Returns      void
    517 **
    518 *******************************************************************************/
    519 static tBTM_PM_MODE btm_pm_get_set_mode(UINT8 pm_id, tBTM_PM_MCB *p_cb, tBTM_PM_PWR_MD *p_mode, tBTM_PM_PWR_MD *p_res)
    520 {
    521     int   xx, loop_max;
    522     tBTM_PM_PWR_MD *p_md = NULL;
    523 
    524     if(p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE)
    525     {
    526         *p_res = *p_mode;
    527         p_res->mode &= ~BTM_PM_MD_FORCE;
    528         return p_res->mode;
    529     }
    530 
    531     if(!p_mode)
    532         loop_max = BTM_MAX_PM_RECORDS+1;
    533     else
    534         loop_max = BTM_MAX_PM_RECORDS;
    535 
    536     for( xx=0; xx<loop_max; xx++)
    537     {
    538         /* g through all the registered "set" parties */
    539         if(btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_SET)
    540         {
    541             if(p_cb->req_mode[xx].mode == BTM_PM_MD_ACTIVE)
    542             {
    543                 /* if at least one registered (SET) party says ACTIVE, stay active */
    544                 return BTM_PM_MD_ACTIVE;
    545             }
    546             else
    547             {
    548                 /* if registered parties give conflicting information, stay active */
    549                 if( (btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL)
    550                     return BTM_PM_MD_ACTIVE;
    551                 p_md = p_res;
    552             }
    553         }
    554     }
    555 
    556     /* if the resulting mode is NULL(nobody registers SET), use the requested mode */
    557     if(p_md == NULL)
    558     {
    559         if(p_mode)
    560             *p_res = *((tBTM_PM_PWR_MD *)p_mode);
    561         else /* p_mode is NULL when btm_pm_snd_md_req is called from btm_pm_proc_mode_change */
    562             return BTM_PM_MD_ACTIVE;
    563     }
    564     else
    565     {
    566         /* if the command is from unregistered party,
    567            compare the resulting mode from registered party*/
    568         if( (pm_id == BTM_PM_SET_ONLY_ID) &&
    569             ((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL) )
    570             return BTM_PM_MD_ACTIVE;
    571     }
    572 
    573     return p_res->mode;
    574 }
    575 
    576 /*******************************************************************************
    577 **
    578 ** Function     btm_pm_snd_md_req
    579 ** Description  get the resulting mode and send the resuest to host controller
    580 ** Returns      tBTM_STATUS
    581 **, BOOLEAN *p_chg_ind
    582 *******************************************************************************/
    583 static tBTM_STATUS btm_pm_snd_md_req(UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode)
    584 {
    585     tBTM_PM_PWR_MD  md_res;
    586     tBTM_PM_MODE    mode;
    587     tBTM_PM_MCB *p_cb = &btm_cb.pm_mode_db[link_ind];
    588     BOOLEAN      chg_ind = FALSE;
    589 
    590     mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res);
    591     md_res.mode = mode;
    592 
    593 #if BTM_PM_DEBUG == TRUE
    594     BTM_TRACE_DEBUG( "btm_pm_snd_md_req link_ind:%d, mode: %d",
    595         link_ind, mode);
    596 #endif
    597 
    598     if( p_cb->state == mode)
    599     {
    600         /* already in the resulting mode */
    601         if( (mode == BTM_PM_MD_ACTIVE) ||
    602             ((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)) )
    603             return BTM_CMD_STORED;
    604         /* Otherwise, needs to wake, then sleep */
    605         chg_ind = TRUE;
    606     }
    607     p_cb->chg_ind = chg_ind;
    608 
    609      /* cannot go directly from current mode to resulting mode. */
    610     if( mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE)
    611         p_cb->chg_ind = TRUE; /* needs to wake, then sleep */
    612 
    613     if(p_cb->chg_ind == TRUE) /* needs to wake first */
    614         md_res.mode = BTM_PM_MD_ACTIVE;
    615 #if (BTM_SSR_INCLUDED == TRUE)
    616     else if(BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat)
    617     {
    618         btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[link_ind].hci_handle, p_cb->max_lat,
    619                                   p_cb->min_rmt_to, p_cb->min_loc_to);
    620         p_cb->max_lat = 0;
    621     }
    622 #endif
    623     /* Default is failure */
    624     btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
    625 
    626     /* send the appropriate HCI command */
    627     btm_cb.pm_pend_id   = pm_id;
    628 
    629 #if BTM_PM_DEBUG == TRUE
    630     BTM_TRACE_DEBUG("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state, link_ind);
    631 #endif
    632     switch(md_res.mode)
    633     {
    634     case BTM_PM_MD_ACTIVE:
    635         switch(p_cb->state)
    636         {
    637         case BTM_PM_MD_SNIFF:
    638             if (btsnd_hcic_exit_sniff_mode(btm_cb.acl_db[link_ind].hci_handle))
    639             {
    640                 btm_cb.pm_pend_link = link_ind;
    641             }
    642             break;
    643         case BTM_PM_MD_PARK:
    644             if (btsnd_hcic_exit_park_mode(btm_cb.acl_db[link_ind].hci_handle))
    645             {
    646                 btm_cb.pm_pend_link = link_ind;
    647             }
    648             break;
    649         default:
    650             /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
    651             break;
    652         }
    653         break;
    654 
    655     case BTM_PM_MD_HOLD:
    656         if (btsnd_hcic_hold_mode (btm_cb.acl_db[link_ind].hci_handle,
    657                                   md_res.max, md_res.min))
    658         {
    659             btm_cb.pm_pend_link = link_ind;
    660         }
    661         break;
    662 
    663     case BTM_PM_MD_SNIFF:
    664         if (btsnd_hcic_sniff_mode (btm_cb.acl_db[link_ind].hci_handle,
    665                                    md_res.max, md_res.min, md_res.attempt,
    666                                    md_res.timeout))
    667         {
    668             btm_cb.pm_pend_link = link_ind;
    669         }
    670         break;
    671 
    672     case BTM_PM_MD_PARK:
    673         if (btsnd_hcic_park_mode (btm_cb.acl_db[link_ind].hci_handle,
    674                                   md_res.max, md_res.min))
    675         {
    676             btm_cb.pm_pend_link = link_ind;
    677         }
    678         break;
    679     default:
    680         /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
    681         break;
    682     }
    683 
    684     if(btm_cb.pm_pend_link == MAX_L2CAP_LINKS)
    685     {
    686         /* the command was not sent */
    687 #if BTM_PM_DEBUG == TRUE
    688         BTM_TRACE_DEBUG( "pm_pend_link: %d",btm_cb.pm_pend_link);
    689 #endif
    690         return (BTM_NO_RESOURCES);
    691     }
    692 
    693     return BTM_CMD_STARTED;
    694 }
    695 
    696 /*******************************************************************************
    697 **
    698 ** Function         btm_pm_check_stored
    699 **
    700 ** Description      This function is called when an HCI command status event occurs
    701 **                  to check if there's any PM command issued while waiting for
    702 **                  HCI command status.
    703 **
    704 ** Returns          none.
    705 **
    706 *******************************************************************************/
    707 static void btm_pm_check_stored(void)
    708 {
    709     int     xx;
    710     for(xx=0; xx<MAX_L2CAP_LINKS; xx++)
    711     {
    712         if(btm_cb.pm_mode_db[xx].state & BTM_PM_STORED_MASK)
    713         {
    714             btm_cb.pm_mode_db[xx].state &= ~BTM_PM_STORED_MASK;
    715             BTM_TRACE_DEBUG( "btm_pm_check_stored :%d", xx);
    716             btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
    717             break;
    718         }
    719     }
    720 }
    721 
    722 
    723 /*******************************************************************************
    724 **
    725 ** Function         btm_pm_proc_cmd_status
    726 **
    727 ** Description      This function is called when an HCI command status event occurs
    728 **                  for power manager related commands.
    729 **
    730 ** Input Parms      status - status of the event (HCI_SUCCESS if no errors)
    731 **
    732 ** Returns          none.
    733 **
    734 *******************************************************************************/
    735 void btm_pm_proc_cmd_status(UINT8 status)
    736 {
    737     tBTM_PM_MCB     *p_cb;
    738     tBTM_PM_STATUS  pm_status;
    739 
    740     if(btm_cb.pm_pend_link >= MAX_L2CAP_LINKS)
    741         return;
    742 
    743     p_cb = &btm_cb.pm_mode_db[btm_cb.pm_pend_link];
    744 
    745     if(status == HCI_SUCCESS)
    746     {
    747         p_cb->state = BTM_PM_ST_PENDING;
    748         pm_status = BTM_PM_STS_PENDING;
    749 #if BTM_PM_DEBUG == TRUE
    750         BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
    751 #endif
    752     }
    753     else /* the command was not successfull. Stay in the same state */
    754     {
    755         pm_status = BTM_PM_STS_ERROR;
    756     }
    757 
    758     /* notify the caller is appropriate */
    759     if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
    760         (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
    761     {
    762         (*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, pm_status, 0, status);
    763     }
    764 
    765     /* no pending cmd now */
    766 #if BTM_PM_DEBUG == TRUE
    767     BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
    768         p_cb->state, btm_cb.pm_pend_link, MAX_L2CAP_LINKS);
    769 #endif
    770     btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
    771 
    772     btm_pm_check_stored();
    773 }
    774 
    775 /*******************************************************************************
    776 **
    777 ** Function         btm_process_mode_change
    778 **
    779 ** Description      This function is called when an HCI mode change event occurs.
    780 **
    781 ** Input Parms      hci_status - status of the event (HCI_SUCCESS if no errors)
    782 **                  hci_handle - connection handle associated with the change
    783 **                  mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK
    784 **                  interval - number of baseband slots (meaning depends on mode)
    785 **
    786 ** Returns          none.
    787 **
    788 *******************************************************************************/
    789 void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval)
    790 {
    791     tACL_CONN   *p;
    792     tBTM_PM_MCB *p_cb = NULL;
    793     int xx, yy, zz;
    794     tBTM_PM_STATE  old_state;
    795     tL2C_LCB        *p_lcb;
    796 
    797     /* get the index to acl_db */
    798     if ((xx = btm_handle_to_acl_index(hci_handle)) >= MAX_L2CAP_LINKS)
    799         return;
    800 
    801     p = &btm_cb.acl_db[xx];
    802 
    803     /*** 2035 and 2045 work around:  If mode is active and coming out of a SCO disconnect, restore packet types ***/
    804     if (mode == HCI_MODE_ACTIVE)
    805     {
    806         if(BTM_GetNumScoLinks() == 0)
    807         {
    808             if(p->restore_pkt_types)
    809     {
    810         BTM_TRACE_DEBUG("btm mode change AFTER unsniffing; hci hdl 0x%x, types 0x%02x/0x%02x",
    811                             hci_handle, p->pkt_types_mask, p->restore_pkt_types);
    812         p->pkt_types_mask = p->restore_pkt_types;
    813         p->restore_pkt_types = 0;   /* Only exists while SCO is active */
    814         btsnd_hcic_change_conn_type (p->hci_handle, p->pkt_types_mask);
    815     }
    816 #if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
    817             else
    818             {
    819                 BTM_TRACE_DEBUG("btm mode change AFTER unsniffing; hci hdl 0x%x, types 0x%02x",
    820                                     hci_handle, btm_cb.btm_acl_pkt_types_supported);
    821                 btm_set_packet_types (p, btm_cb.btm_acl_pkt_types_supported);
    822             }
    823 #endif
    824         }
    825 #if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
    826         else
    827         {
    828             /* Mode changed from Sniff to Active while SCO is open. */
    829             /* Packet types of active mode, not sniff mode, should be used for ACL when SCO is closed. */
    830             p->restore_pkt_types = btm_cb.btm_acl_pkt_types_supported;
    831 
    832             /* Exclude packet types not supported by the peer */
    833             btm_acl_chk_peer_pkt_type_support (p, &p->restore_pkt_types);
    834         }
    835 #endif
    836     }
    837 #if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
    838     else if (mode == HCI_MODE_SNIFF)
    839     {
    840         BTM_TRACE_DEBUG("btm mode change to sniff; hci hdl 0x%x use single slot",
    841                             hci_handle);
    842         btm_set_packet_types (p, (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1));
    843     }
    844 #endif
    845 
    846     /* update control block */
    847     p_cb = &(btm_cb.pm_mode_db[xx]);
    848     old_state       = p_cb->state;
    849     p_cb->state     = mode;
    850     p_cb->interval  = interval;
    851 #if BTM_PM_DEBUG == TRUE
    852     BTM_TRACE_DEBUG( "btm_pm_proc_mode_change new state:0x%x (old:0x%x)", p_cb->state, old_state);
    853 #endif
    854 
    855     if ((p_lcb = l2cu_find_lcb_by_bd_addr(p->remote_addr, BT_TRANSPORT_BR_EDR)) != NULL)
    856     {
    857         if ((p_cb->state == BTM_PM_ST_ACTIVE) || (p_cb->state == BTM_PM_ST_SNIFF))
    858         {
    859             /* There might be any pending packets due to SNIFF or PENDING state */
    860             /* Trigger L2C to start transmission of the pending packets. */
    861             BTM_TRACE_DEBUG("btm mode change to active; check l2c_link for outgoing packets");
    862             l2c_link_check_send_pkts(p_lcb, NULL, NULL);
    863         }
    864     }
    865 
    866     /* notify registered parties */
    867     for(yy=0; yy<=BTM_MAX_PM_RECORDS; yy++)
    868     {
    869         /* set req_mode  HOLD mode->ACTIVE */
    870         if( (mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD) )
    871             p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE;
    872     }
    873 
    874     /* new request has been made. - post a message to BTU task */
    875     if(old_state & BTM_PM_STORED_MASK)
    876     {
    877 #if BTM_PM_DEBUG == TRUE
    878         BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending stored req:%d", xx);
    879 #endif
    880         btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
    881     }
    882     else
    883     {
    884         for(zz=0; zz<MAX_L2CAP_LINKS; zz++)
    885         {
    886             if(btm_cb.pm_mode_db[zz].chg_ind == TRUE)
    887             {
    888 #if BTM_PM_DEBUG == TRUE
    889                 BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending PM req :%d", zz);
    890 #endif
    891                 btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, zz, NULL);
    892                 break;
    893             }
    894         }
    895     }
    896 
    897 
    898     /* notify registered parties */
    899     for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
    900     {
    901         if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
    902         {
    903             (*btm_cb.pm_reg_db[yy].cback)( p->remote_addr, mode, interval, hci_status);
    904         }
    905     }
    906 
    907     /* If mode change was because of an active role switch or change link key */
    908     btm_cont_rswitch_or_chglinkkey(p, btm_find_dev(p->remote_addr), hci_status);
    909 }
    910 
    911 /*******************************************************************************
    912 **
    913 ** Function         btm_pm_proc_ssr_evt
    914 **
    915 ** Description      This function is called when an HCI sniff subrating event occurs.
    916 **
    917 ** Returns          none.
    918 **
    919 *******************************************************************************/
    920 #if (BTM_SSR_INCLUDED == TRUE)
    921 void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len)
    922 {
    923     UINT8       status;
    924     UINT16      handle;
    925     UINT16      max_tx_lat, max_rx_lat;
    926     int         xx, yy;
    927     tBTM_PM_MCB *p_cb;
    928     tACL_CONN   *p_acl=NULL;
    929     UINT16      use_ssr = TRUE;
    930     UNUSED(evt_len);
    931 
    932     STREAM_TO_UINT8 (status, p);
    933 
    934     STREAM_TO_UINT16 (handle, p);
    935     /* get the index to acl_db */
    936     if ((xx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
    937         return;
    938 
    939     STREAM_TO_UINT16 (max_tx_lat, p);
    940     STREAM_TO_UINT16 (max_rx_lat, p);
    941     p_cb = &(btm_cb.pm_mode_db[xx]);
    942 
    943     p_acl = &btm_cb.acl_db[xx];
    944     if(p_cb->interval == max_rx_lat)
    945     {
    946         /* using legacy sniff */
    947         use_ssr = FALSE;
    948     }
    949 
    950     /* notify registered parties */
    951     for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
    952     {
    953         if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
    954         {
    955             if( p_acl)
    956             {
    957                 (*btm_cb.pm_reg_db[yy].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status);
    958             }
    959         }
    960     }
    961 }
    962 
    963 #endif
    964 
    965 #else /* BTM_PWR_MGR_INCLUDED == TRUE */
    966 
    967 /*******************************************************************************
    968 **
    969 ** Functions        BTM_PmRegister, BTM_SetPowerMode, and BTM_ReadPowerMode
    970 **
    971 ** Description      Stubbed versions for BTM_PWR_MGR_INCLUDED = FALSE
    972 **
    973 ** Returns          BTM_MODE_UNSUPPORTED.
    974 **
    975 *******************************************************************************/
    976 tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
    977 {
    978     return BTM_MODE_UNSUPPORTED;
    979 }
    980 
    981 tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
    982 {
    983     return BTM_MODE_UNSUPPORTED;
    984 }
    985 
    986 tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
    987 {
    988     return BTM_MODE_UNSUPPORTED;
    989 }
    990 
    991 #endif
    992 
    993 
    994 /*******************************************************************************
    995 **
    996 ** Function         BTM_IsPowerManagerOn
    997 **
    998 ** Description      This function is called to check if power manager is included.
    999 **                  in the BTE version.
   1000 **
   1001 ** Returns          BTM_PWR_MGR_INCLUDED.
   1002 **
   1003 *******************************************************************************/
   1004 BOOLEAN BTM_IsPowerManagerOn (void)
   1005 {
   1006     return BTM_PWR_MGR_INCLUDED;
   1007 }
   1008 
   1009 /*******************************************************************************
   1010 **
   1011 ** Function         btm_pm_device_in_active_or_sniff_mode
   1012 **
   1013 ** Description      This function is called to check if in active or sniff mode
   1014 **
   1015 ** Returns          TRUE, if in active or sniff mode
   1016 **
   1017 *******************************************************************************/
   1018 BOOLEAN btm_pm_device_in_active_or_sniff_mode(void)
   1019 {
   1020     /* The active state is the highest state-includes connected device and sniff mode*/
   1021 
   1022     /* Covers active and sniff modes */
   1023     if (btm_cb.num_acl > 0)
   1024     {
   1025         BTM_TRACE_DEBUG("btm_pm_device_in_active_or_sniff_mode-acl:%d", btm_cb.num_acl);
   1026         return TRUE;
   1027     }
   1028 
   1029 #if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
   1030     /* Check BLE states */
   1031     if (btm_ble_get_conn_st() != BLE_CONN_IDLE)
   1032     {
   1033         BTM_TRACE_DEBUG("btm_pm_device_in_active_or_sniff_mode- BLE state: %x",
   1034                         btm_ble_get_conn_st());
   1035         return TRUE;
   1036     }
   1037 #endif
   1038 
   1039     return FALSE;
   1040 }
   1041 
   1042 /*******************************************************************************
   1043 **
   1044 ** Function         btm_pm_device_in_scan_state
   1045 **
   1046 ** Description      This function is called to check if in paging, inquiry or connecting mode
   1047 **
   1048 ** Returns          TRUE, if in paging, inquiry or connecting mode
   1049 **
   1050 *******************************************************************************/
   1051 BOOLEAN btm_pm_device_in_scan_state(void)
   1052 {
   1053     /* Scan state-paging, inquiry, and trying to connect */
   1054 
   1055     /* Check for paging */
   1056     if (btm_cb.is_paging || btm_cb.page_queue.count > 0 ||
   1057        BTM_BL_PAGING_STARTED == btm_cb.busy_level)
   1058     {
   1059        BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- paging");
   1060        return TRUE;
   1061     }
   1062 
   1063     /* Check for inquiry */
   1064     if ((btm_cb.btm_inq_vars.inq_active & (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)) != 0)
   1065     {
   1066         BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- Inq active");
   1067         return TRUE;
   1068     }
   1069 
   1070     return FALSE;
   1071 }
   1072 
   1073 /*******************************************************************************
   1074 **
   1075 ** Function         BTM_PM_ReadControllerState
   1076 **
   1077 ** Description      This function is called to obtain the controller state
   1078 **
   1079 ** Returns          Controller State-BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and BTM_CONTRL_IDLE
   1080 **
   1081 *******************************************************************************/
   1082 tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void)
   1083 {
   1084     if (TRUE == btm_pm_device_in_active_or_sniff_mode())
   1085        return BTM_CONTRL_ACTIVE;
   1086     else
   1087     if (TRUE == btm_pm_device_in_scan_state())
   1088        return BTM_CONTRL_SCAN;
   1089     else
   1090        return BTM_CONTRL_IDLE;
   1091 }
   1092 
   1093