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