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