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