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