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