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 
     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_API3( "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_DEBUG4( "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_DEBUG2( "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_DEBUG2( "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_DEBUG1( "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     /* no command pending */
    373     btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
    374 
    375     /* clear the register record */
    376     for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
    377     {
    378         btm_cb.pm_reg_db[xx].mask = BTM_PM_REC_NOT_USED;
    379     }
    380 
    381     if(cb != NULL)
    382         (*cb)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, BTM_PM_STS_ERROR, BTM_DEV_RESET, 0);
    383 }
    384 
    385 /*******************************************************************************
    386 **
    387 ** Function         btm_pm_sm_alloc
    388 **
    389 ** Description      This function initializes the control block of an ACL link.
    390 **                  It is called when an ACL connection is created.
    391 **
    392 ** Returns          void
    393 **
    394 *******************************************************************************/
    395 void btm_pm_sm_alloc(UINT8 ind)
    396 {
    397     tBTM_PM_MCB *p_db = &btm_cb.pm_mode_db[ind];   /* per ACL link */
    398     memset (p_db, 0, sizeof(tBTM_PM_MCB));
    399     p_db->state = BTM_PM_ST_ACTIVE;
    400 #if BTM_PM_DEBUG == TRUE
    401     BTM_TRACE_DEBUG2( "btm_pm_sm_alloc ind:%d st:%d", ind, p_db->state);
    402 #endif
    403 }
    404 
    405 /*******************************************************************************
    406 **
    407 ** Function         btm_pm_find_acl_ind
    408 **
    409 ** Description      This function initializes the control block of an ACL link.
    410 **                  It is called when an ACL connection is created.
    411 **
    412 ** Returns          void
    413 **
    414 *******************************************************************************/
    415 static int btm_pm_find_acl_ind(BD_ADDR remote_bda)
    416 {
    417     tACL_CONN   *p = &btm_cb.acl_db[0];
    418     UINT8 xx;
    419 
    420     for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
    421     {
    422         if ((p->in_use) && (!memcmp (p->remote_addr, remote_bda, BD_ADDR_LEN)))
    423         {
    424 #if BTM_PM_DEBUG == TRUE
    425             BTM_TRACE_DEBUG2( "btm_pm_find_acl_ind ind:%d, st:%d", xx, btm_cb.pm_mode_db[xx].state);
    426 #endif
    427             break;
    428         }
    429     }
    430     return xx;
    431 }
    432 
    433 /*******************************************************************************
    434 **
    435 ** Function     btm_pm_compare_modes
    436 ** Description  get the "more active" mode of the 2
    437 ** Returns      void
    438 **
    439 *******************************************************************************/
    440 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)
    441 {
    442     UINT8 res;
    443 
    444     if(p_md1 == NULL)
    445     {
    446         *p_res = *p_md2;
    447         p_res->mode &= ~BTM_PM_MD_FORCE;
    448 
    449         return p_md2;
    450     }
    451 
    452     if(p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE)
    453     {
    454         return NULL;
    455     }
    456 
    457     /* check if force bit is involved */
    458     if(p_md1->mode & BTM_PM_MD_FORCE)
    459     {
    460         *p_res = *p_md1;
    461         p_res->mode &= ~BTM_PM_MD_FORCE;
    462         return p_res;
    463     }
    464 
    465     if(p_md2->mode & BTM_PM_MD_FORCE)
    466     {
    467         *p_res = *p_md2;
    468         p_res->mode &= ~BTM_PM_MD_FORCE;
    469         return p_res;
    470     }
    471 
    472     res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1);
    473     res = btm_pm_md_comp_matrix[res];
    474     switch(res)
    475     {
    476     case BTM_PM_GET_MD1:
    477         *p_res = *p_md1;
    478         return p_md1;
    479 
    480     case BTM_PM_GET_MD2:
    481         *p_res = *p_md2;
    482         return p_md2;
    483 
    484     case BTM_PM_GET_COMP:
    485         p_res->mode = p_md1->mode;
    486         /* min of the two */
    487         p_res->max  = (p_md1->max < p_md2->max)? (p_md1->max) : (p_md2->max);
    488         /* max of the two */
    489         p_res->min  = (p_md1->min > p_md2->min)? (p_md1->min) : (p_md2->min);
    490 
    491         /* the intersection is NULL */
    492         if( p_res->max < p_res->min)
    493             return NULL;
    494 
    495         if(p_res->mode == BTM_PM_MD_SNIFF)
    496         {
    497             /* max of the two */
    498             p_res->attempt  = (p_md1->attempt > p_md2->attempt)? (p_md1->attempt) : (p_md2->attempt);
    499             p_res->timeout  = (p_md1->timeout > p_md2->timeout)? (p_md1->timeout) : (p_md2->timeout);
    500         }
    501         return p_res;
    502     }
    503     return NULL;
    504 }
    505 
    506 /*******************************************************************************
    507 **
    508 ** Function     btm_pm_get_set_mode
    509 ** Description  get the resulting mode from the registered parties, then compare it
    510 **              with the requested mode, if the command is from an unregistered party.
    511 ** Returns      void
    512 **
    513 *******************************************************************************/
    514 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)
    515 {
    516     int   xx, loop_max;
    517     tBTM_PM_PWR_MD *p_md = NULL;
    518 
    519     if(p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE)
    520     {
    521         *p_res = *p_mode;
    522         p_res->mode &= ~BTM_PM_MD_FORCE;
    523         return p_res->mode;
    524     }
    525 
    526     if(!p_mode)
    527         loop_max = BTM_MAX_PM_RECORDS+1;
    528     else
    529         loop_max = BTM_MAX_PM_RECORDS;
    530 
    531     for( xx=0; xx<loop_max; xx++)
    532     {
    533         /* g through all the registered "set" parties */
    534         if(btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_SET)
    535         {
    536             if(p_cb->req_mode[xx].mode == BTM_PM_MD_ACTIVE)
    537             {
    538                 /* if at least one registered (SET) party says ACTIVE, stay active */
    539                 return BTM_PM_MD_ACTIVE;
    540             }
    541             else
    542             {
    543                 /* if registered parties give conflicting information, stay active */
    544                 if( (btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL)
    545                     return BTM_PM_MD_ACTIVE;
    546                 p_md = p_res;
    547             }
    548         }
    549     }
    550 
    551     /* if the resulting mode is NULL(nobody registers SET), use the requested mode */
    552     if(p_md == NULL)
    553     {
    554         if(p_mode)
    555             *p_res = *((tBTM_PM_PWR_MD *)p_mode);
    556         else /* p_mode is NULL when btm_pm_snd_md_req is called from btm_pm_proc_mode_change */
    557             return BTM_PM_MD_ACTIVE;
    558     }
    559     else
    560     {
    561         /* if the command is from unregistered party,
    562            compare the resulting mode from registered party*/
    563         if( (pm_id == BTM_PM_SET_ONLY_ID) &&
    564             ((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL) )
    565             return BTM_PM_MD_ACTIVE;
    566     }
    567 
    568     return p_res->mode;
    569 }
    570 
    571 /*******************************************************************************
    572 **
    573 ** Function     btm_pm_snd_md_req
    574 ** Description  get the resulting mode and send the resuest to host controller
    575 ** Returns      tBTM_STATUS
    576 **, BOOLEAN *p_chg_ind
    577 *******************************************************************************/
    578 static tBTM_STATUS btm_pm_snd_md_req(UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode)
    579 {
    580     tBTM_PM_PWR_MD  md_res;
    581     tBTM_PM_MODE    mode;
    582     tBTM_PM_MCB *p_cb = &btm_cb.pm_mode_db[link_ind];
    583     BOOLEAN      chg_ind = FALSE;
    584 
    585     mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res);
    586     md_res.mode = mode;
    587 
    588 #if BTM_PM_DEBUG == TRUE
    589     BTM_TRACE_DEBUG2( "btm_pm_snd_md_req link_ind:%d, mode: %d",
    590         link_ind, mode);
    591 #endif
    592 
    593     if( p_cb->state == mode)
    594     {
    595         /* already in the resulting mode */
    596         if( (mode == BTM_PM_MD_ACTIVE) ||
    597             ((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)) )
    598             return BTM_CMD_STORED;
    599         /* Otherwise, needs to wake, then sleep */
    600         chg_ind = TRUE;
    601     }
    602     p_cb->chg_ind = chg_ind;
    603 
    604      /* cannot go directly from current mode to resulting mode. */
    605     if( mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE)
    606         p_cb->chg_ind = TRUE; /* needs to wake, then sleep */
    607 
    608     if(p_cb->chg_ind == TRUE) /* needs to wake first */
    609         md_res.mode = BTM_PM_MD_ACTIVE;
    610 #if (BTM_SSR_INCLUDED == TRUE)
    611     else if(BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat)
    612     {
    613         btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[link_ind].hci_handle, p_cb->max_lat,
    614                                   p_cb->min_rmt_to, p_cb->min_loc_to);
    615         p_cb->max_lat = 0;
    616     }
    617 #endif
    618     /* Default is failure */
    619     btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
    620 
    621     /* send the appropriate HCI command */
    622     btm_cb.pm_pend_id   = pm_id;
    623 
    624 #if BTM_PM_DEBUG == TRUE
    625     BTM_TRACE_DEBUG2("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state, link_ind);
    626 #endif
    627     switch(md_res.mode)
    628     {
    629     case BTM_PM_MD_ACTIVE:
    630         switch(p_cb->state)
    631         {
    632         case BTM_PM_MD_SNIFF:
    633             if (btsnd_hcic_exit_sniff_mode(btm_cb.acl_db[link_ind].hci_handle))
    634             {
    635                 btm_cb.pm_pend_link = link_ind;
    636             }
    637             break;
    638         case BTM_PM_MD_PARK:
    639             if (btsnd_hcic_exit_park_mode(btm_cb.acl_db[link_ind].hci_handle))
    640             {
    641                 btm_cb.pm_pend_link = link_ind;
    642             }
    643             break;
    644         default:
    645             /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
    646             break;
    647         }
    648         break;
    649 
    650     case BTM_PM_MD_HOLD:
    651         if (btsnd_hcic_hold_mode (btm_cb.acl_db[link_ind].hci_handle,
    652                                   md_res.max, md_res.min))
    653         {
    654             btm_cb.pm_pend_link = link_ind;
    655         }
    656         break;
    657 
    658     case BTM_PM_MD_SNIFF:
    659         if (btsnd_hcic_sniff_mode (btm_cb.acl_db[link_ind].hci_handle,
    660                                    md_res.max, md_res.min, md_res.attempt,
    661                                    md_res.timeout))
    662         {
    663             btm_cb.pm_pend_link = link_ind;
    664         }
    665         break;
    666 
    667     case BTM_PM_MD_PARK:
    668         if (btsnd_hcic_park_mode (btm_cb.acl_db[link_ind].hci_handle,
    669                                   md_res.max, md_res.min))
    670         {
    671             btm_cb.pm_pend_link = link_ind;
    672         }
    673         break;
    674     default:
    675         /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
    676         break;
    677     }
    678 
    679     if(btm_cb.pm_pend_link == MAX_L2CAP_LINKS)
    680     {
    681         /* the command was not sent */
    682 #if BTM_PM_DEBUG == TRUE
    683         BTM_TRACE_DEBUG1( "pm_pend_link: %d",btm_cb.pm_pend_link);
    684 #endif
    685         return (BTM_NO_RESOURCES);
    686     }
    687 
    688     return BTM_CMD_STARTED;
    689 }
    690 
    691 /*******************************************************************************
    692 **
    693 ** Function         btm_pm_check_stored
    694 **
    695 ** Description      This function is called when an HCI command status event occurs
    696 **                  to check if there's any PM command issued while waiting for
    697 **                  HCI command status.
    698 **
    699 ** Returns          none.
    700 **
    701 *******************************************************************************/
    702 static void btm_pm_check_stored(void)
    703 {
    704     int     xx;
    705     for(xx=0; xx<MAX_L2CAP_LINKS; xx++)
    706     {
    707         if(btm_cb.pm_mode_db[xx].state & BTM_PM_STORED_MASK)
    708         {
    709             btm_cb.pm_mode_db[xx].state &= ~BTM_PM_STORED_MASK;
    710             BTM_TRACE_DEBUG1( "btm_pm_check_stored :%d", xx);
    711             btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
    712             break;
    713         }
    714     }
    715 }
    716 
    717 
    718 /*******************************************************************************
    719 **
    720 ** Function         btm_pm_proc_cmd_status
    721 **
    722 ** Description      This function is called when an HCI command status event occurs
    723 **                  for power manager related commands.
    724 **
    725 ** Input Parms      status - status of the event (HCI_SUCCESS if no errors)
    726 **
    727 ** Returns          none.
    728 **
    729 *******************************************************************************/
    730 void btm_pm_proc_cmd_status(UINT8 status)
    731 {
    732     tBTM_PM_MCB     *p_cb;
    733     tBTM_PM_STATUS  pm_status;
    734 
    735     if(btm_cb.pm_pend_link >= MAX_L2CAP_LINKS)
    736         return;
    737 
    738     p_cb = &btm_cb.pm_mode_db[btm_cb.pm_pend_link];
    739 
    740     if(status == HCI_SUCCESS)
    741     {
    742         p_cb->state = BTM_PM_ST_PENDING;
    743         pm_status = BTM_PM_STS_PENDING;
    744 #if BTM_PM_DEBUG == TRUE
    745         BTM_TRACE_DEBUG1( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
    746 #endif
    747     }
    748     else /* the command was not successfull. Stay in the same state */
    749     {
    750         pm_status = BTM_PM_STS_ERROR;
    751     }
    752 
    753     /* notify the caller is appropriate */
    754     if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
    755         (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
    756     {
    757         (*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);
    758     }
    759 
    760     /* no pending cmd now */
    761 #if BTM_PM_DEBUG == TRUE
    762     BTM_TRACE_DEBUG3( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
    763         p_cb->state, btm_cb.pm_pend_link, MAX_L2CAP_LINKS);
    764 #endif
    765     btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
    766 
    767     btm_pm_check_stored();
    768 }
    769 
    770 /*******************************************************************************
    771 **
    772 ** Function         btm_process_mode_change
    773 **
    774 ** Description      This function is called when an HCI mode change event occurs.
    775 **
    776 ** Input Parms      hci_status - status of the event (HCI_SUCCESS if no errors)
    777 **                  hci_handle - connection handle associated with the change
    778 **                  mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK
    779 **                  interval - number of baseband slots (meaning depends on mode)
    780 **
    781 ** Returns          none.
    782 **
    783 *******************************************************************************/
    784 void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval)
    785 {
    786     tACL_CONN   *p;
    787     tBTM_PM_MCB *p_cb = NULL;
    788     int xx, yy, zz;
    789     tBTM_PM_STATE  old_state;
    790     tL2C_LCB        *p_lcb;
    791 
    792     /* get the index to acl_db */
    793     if ((xx = btm_handle_to_acl_index(hci_handle)) >= MAX_L2CAP_LINKS)
    794         return;
    795 
    796     p = &btm_cb.acl_db[xx];
    797 
    798     /*** 2035 and 2045 work around:  If mode is active and coming out of a SCO disconnect, restore packet types ***/
    799     if (mode == HCI_MODE_ACTIVE)
    800     {
    801         if(BTM_GetNumScoLinks() == 0)
    802         {
    803             if(p->restore_pkt_types)
    804     {
    805         BTM_TRACE_DEBUG3("btm mode change AFTER unsniffing; hci hdl 0x%x, types 0x%02x/0x%02x",
    806                             hci_handle, p->pkt_types_mask, p->restore_pkt_types);
    807         p->pkt_types_mask = p->restore_pkt_types;
    808         p->restore_pkt_types = 0;   /* Only exists while SCO is active */
    809         btsnd_hcic_change_conn_type (p->hci_handle, p->pkt_types_mask);
    810     }
    811 #if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
    812             else
    813             {
    814                 BTM_TRACE_DEBUG2("btm mode change AFTER unsniffing; hci hdl 0x%x, types 0x%02x",
    815                                     hci_handle, btm_cb.btm_acl_pkt_types_supported);
    816                 btm_set_packet_types (p, btm_cb.btm_acl_pkt_types_supported);
    817             }
    818 #endif
    819         }
    820 #if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
    821         else
    822         {
    823             /* Mode changed from Sniff to Active while SCO is open. */
    824             /* Packet types of active mode, not sniff mode, should be used for ACL when SCO is closed. */
    825             p->restore_pkt_types = btm_cb.btm_acl_pkt_types_supported;
    826 
    827             /* Exclude packet types not supported by the peer */
    828             btm_acl_chk_peer_pkt_type_support (p, &p->restore_pkt_types);
    829         }
    830 #endif
    831     }
    832 #if (BTM_PM_SNIFF_SLOT_WORK_AROUND == TRUE)
    833     else if (mode == HCI_MODE_SNIFF)
    834     {
    835         BTM_TRACE_DEBUG1("btm mode change to sniff; hci hdl 0x%x use single slot",
    836                             hci_handle);
    837         btm_set_packet_types (p, (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1));
    838     }
    839 #endif
    840 
    841     /* update control block */
    842     p_cb = &(btm_cb.pm_mode_db[xx]);
    843     old_state       = p_cb->state;
    844     p_cb->state     = mode;
    845     p_cb->interval  = interval;
    846 #if BTM_PM_DEBUG == TRUE
    847     BTM_TRACE_DEBUG2( "btm_pm_proc_mode_change new state:0x%x (old:0x%x)", p_cb->state, old_state);
    848 #endif
    849 
    850     if ((p_cb->state == HCI_MODE_ACTIVE) &&
    851         ((p_lcb = l2cu_find_lcb_by_bd_addr (p->remote_addr)) != NULL))
    852     {
    853         /* There might be any pending packets due to SNIFF or PENDING state */
    854         /* Trigger L2C to start transmission of the pending packets.        */
    855         BTM_TRACE_DEBUG0 ("btm mode change to active; check l2c_link for outgoing packets");
    856         l2c_link_check_send_pkts (p_lcb, NULL, NULL);
    857 
    858         //btu_stop_timer (&p_lcb->timer_entry);
    859     }
    860 
    861     /* notify registered parties */
    862     for(yy=0; yy<=BTM_MAX_PM_RECORDS; yy++)
    863     {
    864         /* set req_mode  HOLD mode->ACTIVE */
    865         if( (mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD) )
    866             p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE;
    867     }
    868 
    869     /* new request has been made. - post a message to BTU task */
    870     if(old_state & BTM_PM_STORED_MASK)
    871     {
    872 #if BTM_PM_DEBUG == TRUE
    873         BTM_TRACE_DEBUG1( "btm_pm_proc_mode_change: Sending stored req:%d", xx);
    874 #endif
    875         btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
    876     }
    877     else
    878     {
    879         for(zz=0; zz<MAX_L2CAP_LINKS; zz++)
    880         {
    881             if(btm_cb.pm_mode_db[zz].chg_ind == TRUE)
    882             {
    883 #if BTM_PM_DEBUG == TRUE
    884                 BTM_TRACE_DEBUG1( "btm_pm_proc_mode_change: Sending PM req :%d", zz);
    885 #endif
    886                 btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, zz, NULL);
    887                 break;
    888             }
    889         }
    890     }
    891 
    892 
    893     /* notify registered parties */
    894     for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
    895     {
    896         if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
    897         {
    898             (*btm_cb.pm_reg_db[yy].cback)( p->remote_addr, mode, interval, hci_status);
    899         }
    900     }
    901 
    902     /* If mode change was because of an active role switch or change link key */
    903     btm_cont_rswitch_or_chglinkkey(p, btm_find_dev(p->remote_addr), hci_status);
    904 }
    905 
    906 /*******************************************************************************
    907 **
    908 ** Function         btm_pm_proc_ssr_evt
    909 **
    910 ** Description      This function is called when an HCI sniff subrating event occurs.
    911 **
    912 ** Returns          none.
    913 **
    914 *******************************************************************************/
    915 #if (BTM_SSR_INCLUDED == TRUE)
    916 void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len)
    917 {
    918     UINT8       status;
    919     UINT16      handle;
    920     UINT16      max_tx_lat, max_rx_lat;
    921     int         xx, yy;
    922     tBTM_PM_MCB *p_cb;
    923     tACL_CONN   *p_acl=NULL;
    924     UINT16      use_ssr = TRUE;
    925 
    926     STREAM_TO_UINT8 (status, p);
    927 
    928     STREAM_TO_UINT16 (handle, p);
    929     /* get the index to acl_db */
    930     if ((xx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
    931         return;
    932 
    933     STREAM_TO_UINT16 (max_tx_lat, p);
    934     STREAM_TO_UINT16 (max_rx_lat, p);
    935     p_cb = &(btm_cb.pm_mode_db[xx]);
    936 
    937     p_acl = &btm_cb.acl_db[xx];
    938     if(p_cb->interval == max_rx_lat)
    939     {
    940         /* using legacy sniff */
    941         use_ssr = FALSE;
    942     }
    943 
    944     /* notify registered parties */
    945     for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
    946     {
    947         if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
    948         {
    949             if( p_acl)
    950             {
    951                 (*btm_cb.pm_reg_db[yy].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status);
    952             }
    953         }
    954     }
    955 }
    956 #endif
    957 #else /* BTM_PWR_MGR_INCLUDED == TRUE */
    958 
    959 /*******************************************************************************
    960 **
    961 ** Functions        BTM_PmRegister, BTM_SetPowerMode, and BTM_ReadPowerMode
    962 **
    963 ** Description      Stubbed versions for BTM_PWR_MGR_INCLUDED = FALSE
    964 **
    965 ** Returns          BTM_MODE_UNSUPPORTED.
    966 **
    967 *******************************************************************************/
    968 tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
    969 {
    970     return BTM_MODE_UNSUPPORTED;
    971 }
    972 
    973 tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
    974 {
    975     return BTM_MODE_UNSUPPORTED;
    976 }
    977 
    978 tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
    979 {
    980     return BTM_MODE_UNSUPPORTED;
    981 }
    982 
    983 #endif
    984 
    985 /*******************************************************************************
    986 **
    987 ** Function         BTM_IsPowerManagerOn
    988 **
    989 ** Description      This function is called to check if power manager is included.
    990 **                  in the BTE version.
    991 **
    992 ** Returns          BTM_PWR_MGR_INCLUDED.
    993 **
    994 *******************************************************************************/
    995 BOOLEAN BTM_IsPowerManagerOn (void)
    996 {
    997     return BTM_PWR_MGR_INCLUDED;
    998 }
    999