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