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