blob: 6a24ad8cbfbcdf41a261db7f3b3db94bf10a9ff2 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
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
Chris Mantonf8027002015-03-12 09:22:48 -070031#define LOG_TAG "bt_btm_pm"
Sharvil Nanavati5cf03362014-11-14 17:04:46 -080032
Marie Janssen49a86702015-07-08 11:48:57 -070033#include <stddef.h>
34#include <stdio.h>
The Android Open Source Project5738f832012-12-12 16:00:35 -080035#include <stdlib.h>
36#include <string.h>
Sharvil Nanavati44802762014-12-23 23:08:58 -080037
The Android Open Source Project5738f832012-12-12 16:00:35 -080038#include "bt_types.h"
Marie Janssen49a86702015-07-08 11:48:57 -070039#include "bt_utils.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080040#include "btm_api.h"
41#include "btm_int.h"
Marie Janssen49a86702015-07-08 11:48:57 -070042#include "btu.h"
43#include "gki.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080044#include "hcidefs.h"
Marie Janssen49a86702015-07-08 11:48:57 -070045#include "hcimsgs.h"
46#include "l2c_int.h"
Sharvil Nanavati44802762014-12-23 23:08:58 -080047#include "osi/include/log.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080048
The Android Open Source Project5738f832012-12-12 16:00:35 -080049/*****************************************************************************/
50/* to handle different modes */
51/*****************************************************************************/
52#define BTM_PM_STORED_MASK 0x80 /* set this mask if the command is stored */
53#define BTM_PM_NUM_SET_MODES 3 /* only hold, sniff & park */
54
55/* Usage: (ptr_features[ offset ] & mask )?TRUE:FALSE */
56/* offset to supported feature */
57const UINT8 btm_pm_mode_off[BTM_PM_NUM_SET_MODES] = {0, 0, 1};
58/* mask to supported feature */
59const UINT8 btm_pm_mode_msk[BTM_PM_NUM_SET_MODES] = {0x40, 0x80, 0x01};
60
61#define BTM_PM_GET_MD1 1
62#define BTM_PM_GET_MD2 2
63#define BTM_PM_GET_COMP 3
64
65const UINT8 btm_pm_md_comp_matrix[BTM_PM_NUM_SET_MODES*BTM_PM_NUM_SET_MODES] =
66{
67 BTM_PM_GET_COMP,
68 BTM_PM_GET_MD2,
69 BTM_PM_GET_MD2,
70
71 BTM_PM_GET_MD1,
72 BTM_PM_GET_COMP,
73 BTM_PM_GET_MD1,
74
75 BTM_PM_GET_MD1,
76 BTM_PM_GET_MD2,
77 BTM_PM_GET_COMP
78};
79
80/* function prototype */
81static int btm_pm_find_acl_ind(BD_ADDR remote_bda);
82static tBTM_STATUS btm_pm_snd_md_req( UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode );
Sharvil Nanavati5cf03362014-11-14 17:04:46 -080083static const char *mode_to_string(tBTM_PM_MODE mode);
The Android Open Source Project5738f832012-12-12 16:00:35 -080084
85/*
86#ifdef BTM_PM_DEBUG
87#undef BTM_PM_DEBUG
88#define BTM_PM_DEBUG TRUE
89#endif
90*/
91
92#if BTM_PM_DEBUG == TRUE
93const char * btm_pm_state_str[] =
94{
95 "pm_active_state",
96 "pm_hold_state",
97 "pm_sniff_state",
98 "pm_park_state",
99 "pm_pend_state"
100};
101
102const char * btm_pm_event_str[] =
103{
104 "pm_set_mode_event",
105 "pm_hci_sts_event",
106 "pm_mod_chg_event",
107 "pm_update_event"
108};
109
110const char * btm_pm_action_str[] =
111{
112 "pm_set_mode_action",
113 "pm_update_db_action",
114 "pm_mod_chg_action",
115 "pm_hci_sts_action",
116 "pm_update_action"
117};
Chris Mantone7ef4652014-10-15 16:31:49 -0700118#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800119
120/*****************************************************************************/
121/* P U B L I C F U N C T I O N S */
122/*****************************************************************************/
123/*******************************************************************************
124**
125** Function BTM_PmRegister
126**
127** Description register or deregister with power manager
128**
129** Returns BTM_SUCCESS if successful,
130** BTM_NO_RESOURCES if no room to hold registration
131** BTM_ILLEGAL_VALUE
132**
133*******************************************************************************/
134tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
135{
136 int xx;
137
138 /* de-register */
139 if(mask & BTM_PM_DEREG)
140 {
141 if(*p_pm_id >= BTM_MAX_PM_RECORDS)
142 return BTM_ILLEGAL_VALUE;
143 btm_cb.pm_reg_db[*p_pm_id].mask = BTM_PM_REC_NOT_USED;
144 return BTM_SUCCESS;
145 }
146
147 for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
148 {
149 /* find an unused entry */
150 if(btm_cb.pm_reg_db[xx].mask == BTM_PM_REC_NOT_USED)
151 {
152 /* if register for notification, should provide callback routine */
153 if(mask & BTM_PM_REG_NOTIF)
154 {
155 if(p_cb == NULL)
156 return BTM_ILLEGAL_VALUE;
157 btm_cb.pm_reg_db[xx].cback = p_cb;
158 }
159 btm_cb.pm_reg_db[xx].mask = mask;
160 *p_pm_id = xx;
161 return BTM_SUCCESS;
162 }
163 }
164
165 return BTM_NO_RESOURCES;
166}
167
168/*******************************************************************************
169**
170** Function BTM_SetPowerMode
171**
172** Description store the mode in control block or
173** alter ACL connection behavior.
174**
175** Returns BTM_SUCCESS if successful,
176** BTM_UNKNOWN_ADDR if bd addr is not active or bad
177**
178*******************************************************************************/
179tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
180{
181 UINT8 *p_features;
182 int ind, acl_ind;
183 tBTM_PM_MCB *p_cb = NULL; /* per ACL link */
184 tBTM_PM_MODE mode;
185 int temp_pm_id;
186
The Android Open Source Project5738f832012-12-12 16:00:35 -0800187 if(pm_id >= BTM_MAX_PM_RECORDS)
188 pm_id = BTM_PM_SET_ONLY_ID;
189
190 if(p_mode == NULL)
191 return BTM_ILLEGAL_VALUE;
192
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700193 BTM_TRACE_API( "BTM_SetPowerMode: pm_id %d BDA: %08x mode:0x%x", pm_id,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800194 (remote_bda[2]<<24)+(remote_bda[3]<<16)+(remote_bda[4]<<8)+remote_bda[5], p_mode->mode);
195
196 /* take out the force bit */
197 mode = p_mode->mode & ~BTM_PM_MD_FORCE;
198
199 acl_ind = btm_pm_find_acl_ind(remote_bda);
200 if(acl_ind == MAX_L2CAP_LINKS)
201 return (BTM_UNKNOWN_ADDR);
202
203 p_cb = &(btm_cb.pm_mode_db[acl_ind]);
204
205 if(mode != BTM_PM_MD_ACTIVE)
206 {
207 /* check if the requested mode is supported */
208 ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
209 p_features = BTM_ReadLocalFeatures();
210 if( !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) )
211 return BTM_MODE_UNSUPPORTED;
212 }
213
214 if(mode == p_cb->state) /* the requested mode is current mode */
215 {
216 /* already in the requested mode and the current interval has less latency than the max */
217 if( (mode == BTM_PM_MD_ACTIVE) ||
218 ((p_mode->mode & BTM_PM_MD_FORCE) && (p_mode->max >= p_cb->interval) && (p_mode->min <= p_cb->interval)) ||
219 ((p_mode->mode & BTM_PM_MD_FORCE)==0 && (p_mode->max >= p_cb->interval)) )
220 {
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700221 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);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800222 return BTM_SUCCESS;
223 }
224 }
225
226 temp_pm_id = pm_id;
227 if(pm_id == BTM_PM_SET_ONLY_ID)
228 temp_pm_id = BTM_MAX_PM_RECORDS;
229
230 /* update mode database */
231 if( ((pm_id != BTM_PM_SET_ONLY_ID) &&
232 (btm_cb.pm_reg_db[pm_id].mask & BTM_PM_REG_SET))
233 || ((pm_id == BTM_PM_SET_ONLY_ID) && (btm_cb.pm_pend_link != MAX_L2CAP_LINKS)) )
234 {
235#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700236 BTM_TRACE_DEBUG( "BTM_SetPowerMode: Saving cmd acl_ind %d temp_pm_id %d", acl_ind,temp_pm_id);
Chris Mantone7ef4652014-10-15 16:31:49 -0700237#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800238 /* Make sure mask is set to BTM_PM_REG_SET */
239 btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET;
240 *(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD *)p_mode);
241 p_cb->chg_ind = TRUE;
242 }
243
244#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700245 BTM_TRACE_DEBUG( "btm_pm state:0x%x, pm_pend_link: %d", p_cb->state, btm_cb.pm_pend_link);
Chris Mantone7ef4652014-10-15 16:31:49 -0700246#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800247 /* if mode == hold or pending, return */
248 if( (p_cb->state == BTM_PM_STS_HOLD) ||
249 (p_cb->state == BTM_PM_STS_PENDING) ||
250 (btm_cb.pm_pend_link != MAX_L2CAP_LINKS) ) /* command pending */
251 {
252 if(acl_ind != btm_cb.pm_pend_link)
253 {
254 /* set the stored mask */
255 p_cb->state |= BTM_PM_STORED_MASK;
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700256 BTM_TRACE_DEBUG( "btm_pm state stored:%d",acl_ind);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800257 }
258 return BTM_CMD_STORED;
259 }
260
The Android Open Source Project5738f832012-12-12 16:00:35 -0800261 return btm_pm_snd_md_req(pm_id, acl_ind, p_mode);
262}
263
264/*******************************************************************************
265**
266** Function BTM_ReadPowerMode
267**
268** Description This returns the current mode for a specific
269** ACL connection.
270**
271** Input Param remote_bda - device address of desired ACL connection
272**
273** Output Param p_mode - address where the current mode is copied into.
274** BTM_ACL_MODE_NORMAL
275** BTM_ACL_MODE_HOLD
276** BTM_ACL_MODE_SNIFF
277** BTM_ACL_MODE_PARK
278** (valid only if return code is BTM_SUCCESS)
279**
280** Returns BTM_SUCCESS if successful,
281** BTM_UNKNOWN_ADDR if bd addr is not active or bad
282**
283*******************************************************************************/
284tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
285{
286 int acl_ind;
287
288 if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
289 return (BTM_UNKNOWN_ADDR);
290
291 *p_mode = btm_cb.pm_mode_db[acl_ind].state;
292 return BTM_SUCCESS;
293}
294
295/*******************************************************************************
296**
297** Function BTM_SetSsrParams
298**
299** Description This sends the given SSR parameters for the given ACL
300** connection if it is in ACTIVE mode.
301**
302** Input Param remote_bda - device address of desired ACL connection
303** max_lat - maximum latency (in 0.625ms)(0-0xFFFE)
304** min_rmt_to - minimum remote timeout
305** min_loc_to - minimum local timeout
306**
307**
308** Returns BTM_SUCCESS if the HCI command is issued successful,
309** BTM_UNKNOWN_ADDR if bd addr is not active or bad
310** BTM_CMD_STORED if the command is stored
311**
312*******************************************************************************/
313tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat,
314 UINT16 min_rmt_to, UINT16 min_loc_to)
315{
316#if (BTM_SSR_INCLUDED == TRUE)
317 int acl_ind;
318 tBTM_PM_MCB *p_cb;
319
320 if( (acl_ind = btm_pm_find_acl_ind(remote_bda)) == MAX_L2CAP_LINKS)
321 return (BTM_UNKNOWN_ADDR);
322
323 if(BTM_PM_STS_ACTIVE == btm_cb.pm_mode_db[acl_ind].state ||
324 BTM_PM_STS_SNIFF == btm_cb.pm_mode_db[acl_ind].state)
325 {
326 if (btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[acl_ind].hci_handle, max_lat,
327 min_rmt_to, min_loc_to))
328 return BTM_SUCCESS;
329 else
330 return BTM_NO_RESOURCES;
331 }
332 p_cb = &btm_cb.pm_mode_db[acl_ind];
333 p_cb->max_lat = max_lat;
334 p_cb->min_rmt_to = min_rmt_to;
335 p_cb->min_loc_to = min_loc_to;
336 return BTM_CMD_STORED;
337#else
338 return BTM_ILLEGAL_ACTION;
Chris Mantone7ef4652014-10-15 16:31:49 -0700339#endif // BTM_SSR_INCLUDED
The Android Open Source Project5738f832012-12-12 16:00:35 -0800340}
341
342/*******************************************************************************
343**
344** Function btm_pm_reset
345**
346** Description as a part of the BTM reset process.
347**
348** Returns void
349**
350*******************************************************************************/
351void btm_pm_reset(void)
352{
353 int xx;
354 tBTM_PM_STATUS_CBACK *cb = NULL;
355
356 /* clear the pending request for application */
357 if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
358 (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
359 {
360 cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
361 }
362
The Android Open Source Project5738f832012-12-12 16:00:35 -0800363 /* clear the register record */
364 for(xx=0; xx<BTM_MAX_PM_RECORDS; xx++)
365 {
366 btm_cb.pm_reg_db[xx].mask = BTM_PM_REC_NOT_USED;
367 }
368
Kim Schulz2a2701c2013-09-16 15:59:33 +0200369 if(cb != NULL && btm_cb.pm_pend_link < MAX_L2CAP_LINKS)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800370 (*cb)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, BTM_PM_STS_ERROR, BTM_DEV_RESET, 0);
Kim Schulz2a2701c2013-09-16 15:59:33 +0200371
372 /* no command pending */
373 btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800374}
375
376/*******************************************************************************
377**
378** Function btm_pm_sm_alloc
379**
380** Description This function initializes the control block of an ACL link.
381** It is called when an ACL connection is created.
382**
383** Returns void
384**
385*******************************************************************************/
386void btm_pm_sm_alloc(UINT8 ind)
387{
388 tBTM_PM_MCB *p_db = &btm_cb.pm_mode_db[ind]; /* per ACL link */
389 memset (p_db, 0, sizeof(tBTM_PM_MCB));
390 p_db->state = BTM_PM_ST_ACTIVE;
391#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700392 BTM_TRACE_DEBUG( "btm_pm_sm_alloc ind:%d st:%d", ind, p_db->state);
Chris Mantone7ef4652014-10-15 16:31:49 -0700393#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800394}
395
396/*******************************************************************************
397**
398** Function btm_pm_find_acl_ind
399**
400** Description This function initializes the control block of an ACL link.
401** It is called when an ACL connection is created.
402**
403** Returns void
404**
405*******************************************************************************/
406static int btm_pm_find_acl_ind(BD_ADDR remote_bda)
407{
408 tACL_CONN *p = &btm_cb.acl_db[0];
409 UINT8 xx;
410
411 for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++)
412 {
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700413 if ((p->in_use) && (!memcmp (p->remote_addr, remote_bda, BD_ADDR_LEN))
414#if (BLE_INCLUDED == TRUE)
415 && p->transport == BT_TRANSPORT_BR_EDR
Chris Mantone7ef4652014-10-15 16:31:49 -0700416#endif // BLE_INCLUDED
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700417 )
The Android Open Source Project5738f832012-12-12 16:00:35 -0800418 {
419#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700420 BTM_TRACE_DEBUG( "btm_pm_find_acl_ind ind:%d, st:%d", xx, btm_cb.pm_mode_db[xx].state);
Chris Mantone7ef4652014-10-15 16:31:49 -0700421#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800422 break;
423 }
424 }
425 return xx;
426}
427
428/*******************************************************************************
429**
430** Function btm_pm_compare_modes
431** Description get the "more active" mode of the 2
432** Returns void
433**
434*******************************************************************************/
435static 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)
436{
437 UINT8 res;
438
439 if(p_md1 == NULL)
440 {
441 *p_res = *p_md2;
442 p_res->mode &= ~BTM_PM_MD_FORCE;
443
444 return p_md2;
445 }
446
447 if(p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE)
448 {
449 return NULL;
450 }
451
452 /* check if force bit is involved */
453 if(p_md1->mode & BTM_PM_MD_FORCE)
454 {
455 *p_res = *p_md1;
456 p_res->mode &= ~BTM_PM_MD_FORCE;
457 return p_res;
458 }
459
460 if(p_md2->mode & BTM_PM_MD_FORCE)
461 {
462 *p_res = *p_md2;
463 p_res->mode &= ~BTM_PM_MD_FORCE;
464 return p_res;
465 }
466
467 res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1);
468 res = btm_pm_md_comp_matrix[res];
469 switch(res)
470 {
471 case BTM_PM_GET_MD1:
472 *p_res = *p_md1;
473 return p_md1;
474
475 case BTM_PM_GET_MD2:
476 *p_res = *p_md2;
477 return p_md2;
478
479 case BTM_PM_GET_COMP:
480 p_res->mode = p_md1->mode;
481 /* min of the two */
482 p_res->max = (p_md1->max < p_md2->max)? (p_md1->max) : (p_md2->max);
483 /* max of the two */
484 p_res->min = (p_md1->min > p_md2->min)? (p_md1->min) : (p_md2->min);
485
486 /* the intersection is NULL */
487 if( p_res->max < p_res->min)
488 return NULL;
489
490 if(p_res->mode == BTM_PM_MD_SNIFF)
491 {
492 /* max of the two */
493 p_res->attempt = (p_md1->attempt > p_md2->attempt)? (p_md1->attempt) : (p_md2->attempt);
494 p_res->timeout = (p_md1->timeout > p_md2->timeout)? (p_md1->timeout) : (p_md2->timeout);
495 }
496 return p_res;
497 }
498 return NULL;
499}
500
501/*******************************************************************************
502**
503** Function btm_pm_get_set_mode
504** Description get the resulting mode from the registered parties, then compare it
505** with the requested mode, if the command is from an unregistered party.
506** Returns void
507**
508*******************************************************************************/
509static 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)
510{
511 int xx, loop_max;
512 tBTM_PM_PWR_MD *p_md = NULL;
513
514 if(p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE)
515 {
516 *p_res = *p_mode;
517 p_res->mode &= ~BTM_PM_MD_FORCE;
518 return p_res->mode;
519 }
520
521 if(!p_mode)
522 loop_max = BTM_MAX_PM_RECORDS+1;
523 else
524 loop_max = BTM_MAX_PM_RECORDS;
525
526 for( xx=0; xx<loop_max; xx++)
527 {
528 /* g through all the registered "set" parties */
529 if(btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_SET)
530 {
531 if(p_cb->req_mode[xx].mode == BTM_PM_MD_ACTIVE)
532 {
533 /* if at least one registered (SET) party says ACTIVE, stay active */
534 return BTM_PM_MD_ACTIVE;
535 }
536 else
537 {
538 /* if registered parties give conflicting information, stay active */
539 if( (btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL)
540 return BTM_PM_MD_ACTIVE;
541 p_md = p_res;
542 }
543 }
544 }
545
546 /* if the resulting mode is NULL(nobody registers SET), use the requested mode */
547 if(p_md == NULL)
548 {
549 if(p_mode)
550 *p_res = *((tBTM_PM_PWR_MD *)p_mode);
551 else /* p_mode is NULL when btm_pm_snd_md_req is called from btm_pm_proc_mode_change */
552 return BTM_PM_MD_ACTIVE;
553 }
554 else
555 {
556 /* if the command is from unregistered party,
557 compare the resulting mode from registered party*/
558 if( (pm_id == BTM_PM_SET_ONLY_ID) &&
559 ((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL) )
560 return BTM_PM_MD_ACTIVE;
561 }
562
563 return p_res->mode;
564}
565
566/*******************************************************************************
567**
568** Function btm_pm_snd_md_req
569** Description get the resulting mode and send the resuest to host controller
570** Returns tBTM_STATUS
571**, BOOLEAN *p_chg_ind
572*******************************************************************************/
573static tBTM_STATUS btm_pm_snd_md_req(UINT8 pm_id, int link_ind, tBTM_PM_PWR_MD *p_mode)
574{
575 tBTM_PM_PWR_MD md_res;
576 tBTM_PM_MODE mode;
577 tBTM_PM_MCB *p_cb = &btm_cb.pm_mode_db[link_ind];
578 BOOLEAN chg_ind = FALSE;
579
580 mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res);
581 md_res.mode = mode;
582
583#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700584 BTM_TRACE_DEBUG( "btm_pm_snd_md_req link_ind:%d, mode: %d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800585 link_ind, mode);
Chris Mantone7ef4652014-10-15 16:31:49 -0700586#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800587
588 if( p_cb->state == mode)
589 {
590 /* already in the resulting mode */
591 if( (mode == BTM_PM_MD_ACTIVE) ||
592 ((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)) )
593 return BTM_CMD_STORED;
594 /* Otherwise, needs to wake, then sleep */
595 chg_ind = TRUE;
596 }
597 p_cb->chg_ind = chg_ind;
598
599 /* cannot go directly from current mode to resulting mode. */
600 if( mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE)
601 p_cb->chg_ind = TRUE; /* needs to wake, then sleep */
602
603 if(p_cb->chg_ind == TRUE) /* needs to wake first */
604 md_res.mode = BTM_PM_MD_ACTIVE;
605#if (BTM_SSR_INCLUDED == TRUE)
606 else if(BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat)
607 {
608 btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[link_ind].hci_handle, p_cb->max_lat,
609 p_cb->min_rmt_to, p_cb->min_loc_to);
610 p_cb->max_lat = 0;
611 }
Chris Mantone7ef4652014-10-15 16:31:49 -0700612#endif // BTM_SSR_INCLUDED
The Android Open Source Project5738f832012-12-12 16:00:35 -0800613 /* Default is failure */
614 btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
615
616 /* send the appropriate HCI command */
617 btm_cb.pm_pend_id = pm_id;
618
619#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700620 BTM_TRACE_DEBUG("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state, link_ind);
Chris Mantone7ef4652014-10-15 16:31:49 -0700621#endif // BTM_PM_DEBUG
Sharvil Nanavati5cf03362014-11-14 17:04:46 -0800622
Marie Janssendb554582015-06-26 14:53:46 -0700623 LOG_DEBUG(LOG_TAG, "%s switching from %s to %s.", __func__, mode_to_string(p_cb->state), mode_to_string(md_res.mode));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800624 switch(md_res.mode)
625 {
626 case BTM_PM_MD_ACTIVE:
627 switch(p_cb->state)
628 {
629 case BTM_PM_MD_SNIFF:
630 if (btsnd_hcic_exit_sniff_mode(btm_cb.acl_db[link_ind].hci_handle))
631 {
632 btm_cb.pm_pend_link = link_ind;
633 }
634 break;
635 case BTM_PM_MD_PARK:
636 if (btsnd_hcic_exit_park_mode(btm_cb.acl_db[link_ind].hci_handle))
637 {
638 btm_cb.pm_pend_link = link_ind;
639 }
640 break;
641 default:
642 /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
643 break;
644 }
645 break;
646
647 case BTM_PM_MD_HOLD:
648 if (btsnd_hcic_hold_mode (btm_cb.acl_db[link_ind].hci_handle,
649 md_res.max, md_res.min))
650 {
651 btm_cb.pm_pend_link = link_ind;
652 }
653 break;
654
655 case BTM_PM_MD_SNIFF:
656 if (btsnd_hcic_sniff_mode (btm_cb.acl_db[link_ind].hci_handle,
657 md_res.max, md_res.min, md_res.attempt,
658 md_res.timeout))
659 {
660 btm_cb.pm_pend_link = link_ind;
661 }
662 break;
663
664 case BTM_PM_MD_PARK:
665 if (btsnd_hcic_park_mode (btm_cb.acl_db[link_ind].hci_handle,
666 md_res.max, md_res.min))
667 {
668 btm_cb.pm_pend_link = link_ind;
669 }
670 break;
671 default:
672 /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
673 break;
674 }
675
676 if(btm_cb.pm_pend_link == MAX_L2CAP_LINKS)
677 {
678 /* the command was not sent */
679#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700680 BTM_TRACE_DEBUG( "pm_pend_link: %d",btm_cb.pm_pend_link);
Chris Mantone7ef4652014-10-15 16:31:49 -0700681#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800682 return (BTM_NO_RESOURCES);
683 }
684
685 return BTM_CMD_STARTED;
686}
687
688/*******************************************************************************
689**
690** Function btm_pm_check_stored
691**
692** Description This function is called when an HCI command status event occurs
693** to check if there's any PM command issued while waiting for
694** HCI command status.
695**
696** Returns none.
697**
698*******************************************************************************/
699static void btm_pm_check_stored(void)
700{
701 int xx;
702 for(xx=0; xx<MAX_L2CAP_LINKS; xx++)
703 {
704 if(btm_cb.pm_mode_db[xx].state & BTM_PM_STORED_MASK)
705 {
706 btm_cb.pm_mode_db[xx].state &= ~BTM_PM_STORED_MASK;
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700707 BTM_TRACE_DEBUG( "btm_pm_check_stored :%d", xx);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800708 btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
709 break;
710 }
711 }
712}
713
The Android Open Source Project5738f832012-12-12 16:00:35 -0800714/*******************************************************************************
715**
716** Function btm_pm_proc_cmd_status
717**
718** Description This function is called when an HCI command status event occurs
719** for power manager related commands.
720**
721** Input Parms status - status of the event (HCI_SUCCESS if no errors)
722**
723** Returns none.
724**
725*******************************************************************************/
726void btm_pm_proc_cmd_status(UINT8 status)
727{
728 tBTM_PM_MCB *p_cb;
729 tBTM_PM_STATUS pm_status;
730
731 if(btm_cb.pm_pend_link >= MAX_L2CAP_LINKS)
732 return;
733
734 p_cb = &btm_cb.pm_mode_db[btm_cb.pm_pend_link];
735
736 if(status == HCI_SUCCESS)
737 {
738 p_cb->state = BTM_PM_ST_PENDING;
739 pm_status = BTM_PM_STS_PENDING;
740#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700741 BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
Chris Mantone7ef4652014-10-15 16:31:49 -0700742#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800743 }
744 else /* the command was not successfull. Stay in the same state */
745 {
746 pm_status = BTM_PM_STS_ERROR;
747 }
748
749 /* notify the caller is appropriate */
750 if( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
751 (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) )
752 {
753 (*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, pm_status, 0, status);
754 }
755
756 /* no pending cmd now */
757#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700758 BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800759 p_cb->state, btm_cb.pm_pend_link, MAX_L2CAP_LINKS);
Chris Mantone7ef4652014-10-15 16:31:49 -0700760#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800761 btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
762
763 btm_pm_check_stored();
764}
765
766/*******************************************************************************
767**
768** Function btm_process_mode_change
769**
770** Description This function is called when an HCI mode change event occurs.
771**
772** Input Parms hci_status - status of the event (HCI_SUCCESS if no errors)
773** hci_handle - connection handle associated with the change
774** mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK
775** interval - number of baseband slots (meaning depends on mode)
776**
777** Returns none.
778**
779*******************************************************************************/
780void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval)
781{
782 tACL_CONN *p;
783 tBTM_PM_MCB *p_cb = NULL;
784 int xx, yy, zz;
785 tBTM_PM_STATE old_state;
786 tL2C_LCB *p_lcb;
787
788 /* get the index to acl_db */
789 if ((xx = btm_handle_to_acl_index(hci_handle)) >= MAX_L2CAP_LINKS)
790 return;
791
792 p = &btm_cb.acl_db[xx];
793
The Android Open Source Project5738f832012-12-12 16:00:35 -0800794 /* update control block */
795 p_cb = &(btm_cb.pm_mode_db[xx]);
796 old_state = p_cb->state;
797 p_cb->state = mode;
798 p_cb->interval = interval;
Zach Johnson90fe9b02015-01-28 11:16:15 -0800799
Marie Janssendb554582015-06-26 14:53:46 -0700800 LOG_DEBUG(LOG_TAG, "%s switched from %s to %s.", __func__, mode_to_string(old_state), mode_to_string(p_cb->state));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800801
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700802 if ((p_lcb = l2cu_find_lcb_by_bd_addr(p->remote_addr, BT_TRANSPORT_BR_EDR)) != NULL)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800803 {
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700804 if ((p_cb->state == BTM_PM_ST_ACTIVE) || (p_cb->state == BTM_PM_ST_SNIFF))
805 {
806 /* There might be any pending packets due to SNIFF or PENDING state */
807 /* Trigger L2C to start transmission of the pending packets. */
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700808 BTM_TRACE_DEBUG("btm mode change to active; check l2c_link for outgoing packets");
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700809 l2c_link_check_send_pkts(p_lcb, NULL, NULL);
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700810 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800811 }
812
813 /* notify registered parties */
814 for(yy=0; yy<=BTM_MAX_PM_RECORDS; yy++)
815 {
816 /* set req_mode HOLD mode->ACTIVE */
817 if( (mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD) )
818 p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE;
819 }
820
821 /* new request has been made. - post a message to BTU task */
822 if(old_state & BTM_PM_STORED_MASK)
823 {
824#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700825 BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending stored req:%d", xx);
Chris Mantone7ef4652014-10-15 16:31:49 -0700826#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800827 btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
828 }
829 else
830 {
831 for(zz=0; zz<MAX_L2CAP_LINKS; zz++)
832 {
833 if(btm_cb.pm_mode_db[zz].chg_ind == TRUE)
834 {
835#if BTM_PM_DEBUG == TRUE
Sharvil Nanavati5344d6d2014-05-04 00:46:57 -0700836 BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending PM req :%d", zz);
Chris Mantone7ef4652014-10-15 16:31:49 -0700837#endif // BTM_PM_DEBUG
The Android Open Source Project5738f832012-12-12 16:00:35 -0800838 btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, zz, NULL);
839 break;
840 }
841 }
842 }
843
The Android Open Source Project5738f832012-12-12 16:00:35 -0800844 /* notify registered parties */
845 for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
846 {
847 if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
848 {
849 (*btm_cb.pm_reg_db[yy].cback)( p->remote_addr, mode, interval, hci_status);
850 }
851 }
852
853 /* If mode change was because of an active role switch or change link key */
Zach Johnsone7faae62014-10-27 17:23:49 -0700854 btm_cont_rswitch(p, btm_find_dev(p->remote_addr), hci_status);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800855}
856
857/*******************************************************************************
858**
859** Function btm_pm_proc_ssr_evt
860**
861** Description This function is called when an HCI sniff subrating event occurs.
862**
863** Returns none.
864**
865*******************************************************************************/
866#if (BTM_SSR_INCLUDED == TRUE)
867void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len)
868{
869 UINT8 status;
870 UINT16 handle;
Sharvil Nanavatif1c764f2015-02-23 17:31:48 -0800871 UINT16 max_rx_lat;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800872 int xx, yy;
873 tBTM_PM_MCB *p_cb;
874 tACL_CONN *p_acl=NULL;
875 UINT16 use_ssr = TRUE;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800876 UNUSED(evt_len);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800877
878 STREAM_TO_UINT8 (status, p);
879
880 STREAM_TO_UINT16 (handle, p);
881 /* get the index to acl_db */
882 if ((xx = btm_handle_to_acl_index(handle)) >= MAX_L2CAP_LINKS)
883 return;
884
Sharvil Nanavatif1c764f2015-02-23 17:31:48 -0800885 p += 2;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800886 STREAM_TO_UINT16 (max_rx_lat, p);
887 p_cb = &(btm_cb.pm_mode_db[xx]);
888
889 p_acl = &btm_cb.acl_db[xx];
890 if(p_cb->interval == max_rx_lat)
891 {
892 /* using legacy sniff */
893 use_ssr = FALSE;
894 }
895
896 /* notify registered parties */
897 for(yy=0; yy<BTM_MAX_PM_RECORDS; yy++)
898 {
899 if(btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF)
900 {
901 if( p_acl)
902 {
903 (*btm_cb.pm_reg_db[yy].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status);
904 }
905 }
906 }
907}
Chris Mantone7ef4652014-10-15 16:31:49 -0700908#endif // BTM_SSR_INCLUDED
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700909
Satya Callojie5ba8842014-07-03 17:18:02 -0700910/*******************************************************************************
911**
912** Function btm_pm_device_in_active_or_sniff_mode
913**
914** Description This function is called to check if in active or sniff mode
915**
916** Returns TRUE, if in active or sniff mode
917**
918*******************************************************************************/
919BOOLEAN btm_pm_device_in_active_or_sniff_mode(void)
920{
921 /* The active state is the highest state-includes connected device and sniff mode*/
922
923 /* Covers active and sniff modes */
Andre Eisenbachf4c4b782015-03-19 15:15:05 -0700924 if (BTM_GetNumAclLinks() > 0)
Satya Callojie5ba8842014-07-03 17:18:02 -0700925 {
Andre Eisenbachf4c4b782015-03-19 15:15:05 -0700926 BTM_TRACE_DEBUG("%s - ACL links: %d", __func__, BTM_GetNumAclLinks());
Satya Callojie5ba8842014-07-03 17:18:02 -0700927 return TRUE;
928 }
929
Prerepa Viswanadham81b03192014-07-23 17:49:48 -0700930#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
Satya Callojie5ba8842014-07-03 17:18:02 -0700931 /* Check BLE states */
932 if (btm_ble_get_conn_st() != BLE_CONN_IDLE)
933 {
Andre Eisenbachf4c4b782015-03-19 15:15:05 -0700934 BTM_TRACE_DEBUG("%s - BLE state: %x", __func__, btm_ble_get_conn_st());
Satya Callojie5ba8842014-07-03 17:18:02 -0700935 return TRUE;
936 }
Prerepa Viswanadham81b03192014-07-23 17:49:48 -0700937#endif
Satya Callojie5ba8842014-07-03 17:18:02 -0700938
939 return FALSE;
940}
941
942/*******************************************************************************
943**
944** Function btm_pm_device_in_scan_state
945**
946** Description This function is called to check if in paging, inquiry or connecting mode
947**
948** Returns TRUE, if in paging, inquiry or connecting mode
949**
950*******************************************************************************/
951BOOLEAN btm_pm_device_in_scan_state(void)
952{
953 /* Scan state-paging, inquiry, and trying to connect */
954
955 /* Check for paging */
Pavlin Radoslavov1a3844f2015-09-25 11:21:15 -0700956 if (btm_cb.is_paging || (!fixed_queue_is_empty(btm_cb.page_queue)) ||
Satya Callojie5ba8842014-07-03 17:18:02 -0700957 BTM_BL_PAGING_STARTED == btm_cb.busy_level)
958 {
959 BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- paging");
960 return TRUE;
961 }
962
963 /* Check for inquiry */
964 if ((btm_cb.btm_inq_vars.inq_active & (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)) != 0)
965 {
966 BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- Inq active");
967 return TRUE;
968 }
969
970 return FALSE;
971}
972
973/*******************************************************************************
974**
975** Function BTM_PM_ReadControllerState
976**
977** Description This function is called to obtain the controller state
978**
979** Returns Controller State-BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and BTM_CONTRL_IDLE
980**
981*******************************************************************************/
982tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void)
983{
984 if (TRUE == btm_pm_device_in_active_or_sniff_mode())
985 return BTM_CONTRL_ACTIVE;
986 else
987 if (TRUE == btm_pm_device_in_scan_state())
988 return BTM_CONTRL_SCAN;
989 else
990 return BTM_CONTRL_IDLE;
991}
Sharvil Nanavati5cf03362014-11-14 17:04:46 -0800992
993static const char *mode_to_string(tBTM_PM_MODE mode) {
994 switch (mode) {
995 case BTM_PM_MD_ACTIVE: return "ACTIVE";
996 case BTM_PM_MD_SNIFF: return "SNIFF";
997 case BTM_PM_MD_PARK: return "PARK";
998 case BTM_PM_MD_HOLD: return "HOLD";
999 default: return "UNKNOWN";
1000 }
1001}