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