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