bta_dm_pm.c revision 5fc4be1aa79e3b732e4503a84908522fd754b56f
1/******************************************************************************
2 *
3 *  Copyright (C) 2003-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 the action functions for device manager state
22 *  machine.
23 *
24 ******************************************************************************/
25
26#include "gki.h"
27#include "bd.h"
28#include "bta_sys.h"
29#include "bta_api.h"
30#include "bta_dm_int.h"
31#include "btm_api.h"
32
33#include <string.h>
34
35
36static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
37static void bta_dm_pm_set_mode(BD_ADDR peer_addr, BOOLEAN timed_out );
38static void bta_dm_pm_timer_cback(void *p_tle);
39static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status);
40static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr);
41static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index);
42static BOOLEAN bta_dm_pm_is_sco_active ();
43static void bta_dm_pm_hid_check(BOOLEAN bScoActive);
44static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable);
45
46#if (BTM_SSR_INCLUDED == TRUE)
47#if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE)
48#include "../hh/bta_hh_int.h"
49/* BTA_DM_PM_SSR1 will be dedicated for HH SSR setting entry, no other profile can use it */
50#define BTA_DM_PM_SSR_HH      BTA_DM_PM_SSR1
51#endif
52static void bta_dm_pm_ssr(BD_ADDR peer_addr);
53#endif
54
55tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
56
57
58/*******************************************************************************
59**
60** Function         bta_dm_init_pm
61**
62** Description      Initialises the BT low power manager
63**
64**
65** Returns          void
66**
67*******************************************************************************/
68void bta_dm_init_pm(void)
69{
70
71    memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs));
72
73    /* if there are no power manger entries, so not register */
74    if(p_bta_dm_pm_cfg[0].app_id != 0)
75    {
76        bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)bta_dm_pm_cback);
77
78        BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id,
79                       bta_dm_pm_btm_cback);
80    }
81
82
83}
84
85
86/*******************************************************************************
87**
88** Function         bta_dm_disable_pm
89**
90** Description      Disable PM
91**
92**
93** Returns          void
94**
95*******************************************************************************/
96void bta_dm_disable_pm(void)
97{
98    UINT8 i;
99
100    bta_sys_pm_register(NULL);
101    BTM_PmRegister( BTM_PM_DEREG, &bta_dm_cb.pm_id, NULL);
102
103    /* Need to stop all active timers. */
104    for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
105    {
106        if(bta_dm_cb.pm_timer[i].in_use)
107        {
108            APPL_TRACE_DEBUG("stop dm_pm_timer:%d", i);
109            bta_sys_stop_timer(&bta_dm_cb.pm_timer[i].timer);
110            bta_dm_cb.pm_timer[i].in_use = FALSE;
111        }
112    }
113}
114
115/*******************************************************************************
116**
117** Function         bta_dm_pm_stop_timer
118**
119** Description      stop a PM timer
120**
121**
122** Returns          void
123**
124*******************************************************************************/
125static void bta_dm_pm_stop_timer(BD_ADDR peer_addr)
126{
127    UINT8 i;
128
129    for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
130    {
131
132        if(bta_dm_cb.pm_timer[i].in_use && !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr))
133        {
134            APPL_TRACE_DEBUG("stop dm_pm_timer:%d", i);
135            bta_sys_stop_timer(&bta_dm_cb.pm_timer[i].timer);
136            bta_dm_cb.pm_timer[i].in_use = FALSE;
137            break;
138        }
139
140    }
141}
142
143/*******************************************************************************
144**
145** Function         bta_dm_pm_cback
146**
147** Description      Conn change callback from sys for low power management
148**
149**
150** Returns          void
151**
152*******************************************************************************/
153static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
154{
155
156    UINT8 i,j;
157    UINT16 policy_setting;
158    tBTM_STATUS btm_status;
159    tBTM_VERSION_INFO vers;
160#if (BTM_SSR_INCLUDED == TRUE)
161    int               index = BTA_DM_PM_SSR0;
162#endif
163    tBTA_DM_PEER_DEVICE *p_dev;
164
165    APPL_TRACE_DEBUG("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id, app_id);
166
167    btm_status = BTM_ReadLocalVersion (&vers);
168    p_dev = bta_dm_find_peer_device(peer_addr);
169
170    /* find if there is an power mode entry for the service */
171    for(i=1; i<=p_bta_dm_pm_cfg[0].app_id; i++)
172    {
173
174        if((p_bta_dm_pm_cfg[i].id == id)
175            && ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[i].app_id == app_id )))
176            break;
177
178    }
179
180    /* if no entries are there for the app_id and subystem in p_bta_dm_pm_spec*/
181    if(i> p_bta_dm_pm_cfg[0].app_id)
182        return;
183
184    bta_dm_pm_stop_timer(peer_addr);
185    /*p_dev = bta_dm_find_peer_device(peer_addr);*/
186
187#if (BTM_SSR_INCLUDED == TRUE)
188    /* set SSR parameters on SYS CONN OPEN */
189    if((BTA_SYS_CONN_OPEN == status) && p_dev && (p_dev->info & BTA_DM_DI_USE_SSR))
190    {
191        index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr;
192    }
193#endif
194
195    /* if no action for the event */
196    if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_ACTION)
197    {
198#if (BTM_SSR_INCLUDED == TRUE)
199        if(BTA_DM_PM_SSR0 == index) /* and do not need to set SSR, return. */
200#endif
201        return;
202    }
203
204    for(j=0; j<bta_dm_conn_srvcs.count ; j++)
205    {
206        /* check if an entry already present */
207        if((bta_dm_conn_srvcs.conn_srvc[j].id == id)
208            && (bta_dm_conn_srvcs.conn_srvc[j].app_id == app_id )
209            && !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr))
210            break;
211
212    }
213
214        /* if subsystem has no more preference on the power mode remove
215       the cb */
216    if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_PREF)
217    {
218
219        if(j != bta_dm_conn_srvcs.count)
220        {
221            bta_dm_conn_srvcs.count--;
222
223            for(; j<bta_dm_conn_srvcs.count ; j++)
224            {
225
226                memcpy(&bta_dm_conn_srvcs.conn_srvc[j], &bta_dm_conn_srvcs.conn_srvc[j+1], sizeof(bta_dm_conn_srvcs.conn_srvc[j]));
227
228            }
229        }
230        else
231        {
232            APPL_TRACE_WARNING("bta_dm_act no entry for connected service cbs");
233            return;
234        }
235    }
236    else if(j == bta_dm_conn_srvcs.count )
237    {
238        /* check if we have more connected service that cbs */
239        if(bta_dm_conn_srvcs.count == BTA_DM_NUM_CONN_SRVS)
240        {
241            APPL_TRACE_WARNING("bta_dm_act no more connected service cbs");
242            return;
243        }
244
245        /* fill in a new cb */
246        bta_dm_conn_srvcs.conn_srvc[j].id = id;
247        bta_dm_conn_srvcs.conn_srvc[j].app_id = app_id;
248        bdcpy(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr);
249
250        APPL_TRACE_WARNING("new conn_srvc id:%d, app_id:%d", id, app_id);
251
252        bta_dm_conn_srvcs.count++;
253        bta_dm_conn_srvcs.conn_srvc[j].state = status;
254    }
255    else
256    {
257        /* no service is added or removed. only updating status. */
258        bta_dm_conn_srvcs.conn_srvc[j].state = status;
259    }
260
261    if(p_dev)
262    {
263        p_dev->pm_mode_attempted = 0;
264        p_dev->pm_mode_failed = 0;
265    }
266
267#if (BTM_SSR_INCLUDED == TRUE)
268    if(p_bta_dm_ssr_spec[index].max_lat
269#if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE)
270       || index == BTA_DM_PM_SSR_HH
271#endif
272       )
273    {
274        bta_dm_pm_ssr(peer_addr);
275    }
276#endif
277
278    bta_dm_pm_set_mode(peer_addr, FALSE);
279
280    /* perform the HID link workaround if needed
281    ** 1. If SCO up/down event is received OR
282    ** 2. If HID connection open is received and SCO is already active.
283    **     This will handle the case where HID connects when SCO already active
284    */
285    if ( (btm_status == BTM_SUCCESS) &&
286         ( ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ||
287           ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active()) ) )
288    {
289        BOOLEAN bScoActive;
290        if (status == BTA_SYS_CONN_OPEN)
291            bScoActive = TRUE;
292        else
293            bScoActive = (status == BTA_SYS_SCO_OPEN);
294
295        bta_dm_pm_hid_check(bScoActive);
296    }
297
298}
299
300
301/*******************************************************************************
302**
303** Function         bta_dm_pm_set_mode
304**
305** Description      Set the power mode for the device
306**
307**
308** Returns          void
309**
310*******************************************************************************/
311static void bta_dm_pm_set_mode(BD_ADDR peer_addr, BOOLEAN timed_out )
312{
313
314    tBTA_DM_PM_ACTTION  pm_action = BTA_DM_PM_NO_ACTION;
315    UINT16              timeout = 0;
316    UINT8               i,j;
317    tBTA_DM_PM_ACTTION  failed_pm = 0;
318    tBTA_DM_PEER_DEVICE *p_peer_device = NULL;
319    tBTA_DM_PM_ACTTION   allowed_modes = 0;
320    tBTA_DM_PM_ACTTION   pref_modes = 0;
321    tBTA_DM_PM_CFG      *p_pm_cfg;
322    tBTA_DM_PM_SPEC     *p_pm_spec;
323    tBTA_DM_PM_ACTN     *p_act0, *p_act1;
324    tBTA_DM_SRVCS       *p_srvcs;
325
326
327    if(!bta_dm_cb.device_list.count)
328        return;
329
330    /* see if any attempt to put device in low power mode failed */
331    p_peer_device = bta_dm_find_peer_device(peer_addr);
332    /* if no peer device found return */
333    if (p_peer_device == NULL)
334        return;
335
336    failed_pm = p_peer_device->pm_mode_failed;
337
338    for(i=0; i<bta_dm_conn_srvcs.count ; i++)
339    {
340
341        p_srvcs = &bta_dm_conn_srvcs.conn_srvc[i];
342        if(!bdcmp(p_srvcs->peer_bdaddr, peer_addr))
343        {
344
345            /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
346            for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++)
347            {
348                if((p_bta_dm_pm_cfg[j].id == p_srvcs->id)
349                    && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID ) ||
350                    (p_bta_dm_pm_cfg[j].app_id == p_srvcs->app_id)))
351                    break;
352            }
353
354            p_pm_cfg = &p_bta_dm_pm_cfg[j];
355            p_pm_spec = &p_bta_dm_pm_spec[p_pm_cfg->spec_idx];
356            p_act0 = &p_pm_spec->actn_tbl[p_srvcs->state][0];
357            p_act1 = &p_pm_spec->actn_tbl[p_srvcs->state][1];
358
359            APPL_TRACE_DEBUG("bta_dm_pm_set_mode: srvcsid: %d, state: %d, j: %d", p_srvcs->id, p_srvcs->state, j);
360            allowed_modes |= p_pm_spec->allow_mask;
361
362            /* PM actions are in the order of strictness */
363
364            /* first check if the first preference is ok */
365            if(!(failed_pm & p_act0->power_mode))
366            {
367                pref_modes |= p_act0->power_mode;
368
369                if(p_act0->power_mode > pm_action)
370                {
371                    pm_action = p_act0->power_mode;
372                    timeout =  p_act0->timeout;
373
374                }
375            }
376            /* if first preference has already failed, try second preference */
377            else if(!(failed_pm & p_act1->power_mode))
378            {
379                pref_modes |= p_act1->power_mode;
380
381                if(p_act1->power_mode > pm_action)
382                {
383                    pm_action = p_act1->power_mode;
384                    timeout =  p_act1->timeout;
385
386                }
387            }
388        }
389    }
390
391    if(pm_action & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF))
392    {
393
394        /* some service don't like the mode */
395        if(!(allowed_modes & pm_action))
396        {
397
398            /* select the other mode if its allowed and preferred, otherwise 0 which is BTA_DM_PM_NO_ACTION */
399            pm_action =  (allowed_modes & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & pref_modes);
400
401            /* no timeout needed if no action is required */
402            if(pm_action == BTA_DM_PM_NO_ACTION)
403            {
404                timeout = 0;
405            }
406
407        }
408
409
410    }
411
412    if(!timed_out && timeout)
413    {
414
415        for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
416        {
417
418            if(!bta_dm_cb.pm_timer[i].in_use)
419            {
420                bta_dm_cb.pm_timer[i].in_use = TRUE;
421                bdcpy(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr);
422                bta_dm_cb.pm_timer[i].timer.p_cback = bta_dm_pm_timer_cback;
423                bta_sys_start_timer(&bta_dm_cb.pm_timer[i].timer, 0, timeout);
424                APPL_TRACE_DEBUG("start dm_pm_timer:%d, %d", i, timeout);
425                return;
426
427            }
428
429        }
430
431        /* no more timers */
432        if(i==BTA_DM_NUM_PM_TIMER)
433        {
434            APPL_TRACE_WARNING("bta_dm_act dm_pm_timer no more");
435            return;
436        }
437    }
438
439    if(pm_action == BTA_DM_PM_NO_ACTION)
440    {
441
442
443    }
444    else if(pm_action == BTA_DM_PM_PARK)
445    {
446        p_peer_device->pm_mode_attempted = BTA_DM_PM_PARK;
447        bta_dm_pm_park(peer_addr);
448
449    }
450    else if(pm_action & BTA_DM_PM_SNIFF)
451    {
452        /* dont initiate SNIFF, if link_policy has it disabled */
453        if (p_peer_device->link_policy & HCI_ENABLE_SNIFF_MODE)
454        {
455	        p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF;
456    	    bta_dm_pm_sniff(p_peer_device, (UINT8)(pm_action & 0x0F) );
457        }
458        else
459        {
460            APPL_TRACE_DEBUG("bta_dm_pm_set_mode: Link policy disallows SNIFF, ignore request");
461        }
462    }
463    else if(pm_action == BTA_DM_PM_ACTIVE)
464    {
465
466        bta_dm_pm_active(peer_addr);
467
468    }
469
470
471}
472
473
474/*******************************************************************************
475**
476** Function         bta_ag_pm_park
477**
478** Description      Switch to park mode.
479**
480**
481** Returns          TRUE if park attempted, FALSE otherwise.
482**
483*******************************************************************************/
484static BOOLEAN bta_dm_pm_park(BD_ADDR peer_addr)
485{
486
487    tBTM_PM_MODE    mode = BTM_PM_STS_ACTIVE;
488
489    /* if not in park mode, switch to park */
490    BTM_ReadPowerMode(peer_addr, &mode);
491
492    if(mode != BTM_PM_MD_PARK)
493    {
494        BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &p_bta_dm_pm_md[BTA_DM_PM_PARK_IDX]);
495    }
496    return TRUE;
497
498}
499
500
501/*******************************************************************************
502**
503** Function         bta_ag_pm_sniff
504**
505** Description      Switch to sniff mode.
506**
507**
508** Returns          TRUE if sniff attempted, FALSE otherwise.
509**
510*******************************************************************************/
511static BOOLEAN bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE *p_peer_dev, UINT8 index)
512{
513    tBTM_PM_MODE    mode = BTM_PM_STS_ACTIVE;
514    tBTM_PM_PWR_MD  pwr_md;
515    tBTM_STATUS     status;
516
517    BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode);
518
519#if (BTM_SSR_INCLUDED == TRUE)
520    APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index, p_peer_dev->info);
521    if (mode != BTM_PM_MD_SNIFF ||
522        (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures ()) &&
523         HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadRemoteFeatures (p_peer_dev->peer_bdaddr)) &&
524         !(p_peer_dev->info & BTA_DM_DI_USE_SSR)))
525#else
526    APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d", mode, index);
527    if(mode != BTM_PM_MD_SNIFF)
528#endif
529    {
530        /* if the current mode is not sniff, issue the sniff command.
531         * If sniff, but SSR is not used in this link, still issue the command */
532        memcpy(&pwr_md, &p_bta_dm_pm_md[index], sizeof (tBTM_PM_PWR_MD));
533        if (p_peer_dev->info & BTA_DM_DI_INT_SNIFF)
534        {
535            pwr_md.mode |= BTM_PM_MD_FORCE;
536        }
537        status = BTM_SetPowerMode (bta_dm_cb.pm_id, p_peer_dev->peer_bdaddr, &pwr_md);
538        if (status == BTM_CMD_STORED|| status == BTM_CMD_STARTED)
539        {
540            p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF);
541            p_peer_dev->info |= BTA_DM_DI_SET_SNIFF;
542        }
543        else if (status == BTM_SUCCESS)
544        {
545            APPL_TRACE_DEBUG("bta_dm_pm_sniff BTM_SetPowerMode() returns BTM_SUCCESS");
546            p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF);
547        }
548        else /* error */
549        {
550            APPL_TRACE_ERROR("bta_dm_pm_sniff BTM_SetPowerMode() returns ERROR status=%d", status);
551            p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF);
552        }
553    }
554    /* else already in sniff and is using SSR, do nothing */
555
556    return TRUE;
557
558}
559/*******************************************************************************
560**
561** Function         bta_dm_pm_ssr
562**
563** Description      checks and sends SSR parameters
564**
565** Returns          void
566**
567*******************************************************************************/
568#if (BTM_SSR_INCLUDED == TRUE)
569static void bta_dm_pm_ssr(BD_ADDR peer_addr)
570{
571    tBTA_DM_SSR_SPEC *p_spec, *p_spec_cur;
572    UINT8   i,j;
573    int     ssr = BTA_DM_PM_SSR0;
574
575    /* go through the connected services */
576    for(i=0; i<bta_dm_conn_srvcs.count ; i++)
577    {
578        if(!bdcmp(bta_dm_conn_srvcs.conn_srvc[i].peer_bdaddr, peer_addr))
579        {
580            /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
581            for(j=1; j<=p_bta_dm_pm_cfg[0].app_id; j++)
582            {
583                /* find the associated p_bta_dm_pm_cfg */
584                if((p_bta_dm_pm_cfg[j].id == bta_dm_conn_srvcs.conn_srvc[i].id)
585                    && ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID )
586                    || (p_bta_dm_pm_cfg[j].app_id == bta_dm_conn_srvcs.conn_srvc[i].app_id)))
587                {
588                    APPL_TRACE_WARNING("bta_dm_pm_ssr conn_srvc id:%d, app_id:%d",
589                        bta_dm_conn_srvcs.conn_srvc[i].id, bta_dm_conn_srvcs.conn_srvc[i].app_id);
590                    break;
591                }
592            }
593
594            /* find the ssr index with the smallest max latency. */
595            p_spec_cur = &p_bta_dm_ssr_spec[p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr];
596            p_spec = &p_bta_dm_ssr_spec[ssr];
597
598#if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE)
599            /* HH has the per connection SSR preference, already read the SSR params from BTA HH */
600            if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr == BTA_DM_PM_SSR_HH)
601            {
602                if (bta_hh_read_ssr_param(peer_addr, &p_spec_cur->max_lat, &p_spec_cur->min_rmt_to) == BTA_HH_ERR)
603                    continue;
604            }
605#endif
606            if (p_spec_cur->max_lat < p_spec->max_lat ||
607                (ssr == BTA_DM_PM_SSR0 && p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr != BTA_DM_PM_SSR0))
608            {
609                ssr = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr;
610            }
611
612        }
613    }
614
615    p_spec = &p_bta_dm_ssr_spec[ssr];
616    APPL_TRACE_WARNING("bta_dm_pm_ssr:%d, lat:%d", ssr, p_spec->max_lat);
617    if(p_spec->max_lat)
618    {
619        /* set the SSR parameters. */
620        BTM_SetSsrParams (peer_addr, p_spec->max_lat,
621            p_spec->min_rmt_to, p_spec->min_loc_to);
622    }
623}
624#endif
625/*******************************************************************************
626**
627** Function         bta_dm_pm_active
628**
629** Description      Brings connection to active mode
630**
631**
632** Returns          void
633**
634*******************************************************************************/
635void bta_dm_pm_active(BD_ADDR peer_addr)
636{
637    tBTM_PM_PWR_MD  pm;
638
639    memset( (void*)&pm, 0, sizeof(pm));
640
641    /* switch to active mode */
642    pm.mode = BTM_PM_MD_ACTIVE;
643    BTM_SetPowerMode (bta_dm_cb.pm_id, peer_addr, &pm);
644
645
646}
647
648
649/*******************************************************************************
650**
651** Function         bta_dm_pm_btm_cback
652**
653** Description      BTM power manager callback.
654**
655**
656** Returns          void
657**
658*******************************************************************************/
659static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status, UINT16 value, UINT8 hci_status)
660{
661   tBTA_DM_PM_BTM_STATUS  *p_buf;
662
663   if ((p_buf = (tBTA_DM_PM_BTM_STATUS *) GKI_getbuf(sizeof(tBTA_DM_PM_BTM_STATUS))) != NULL)
664    {
665        p_buf->hdr.event = BTA_DM_PM_BTM_STATUS_EVT;
666        p_buf->status = status;
667        p_buf->value = value;
668        p_buf->hci_status = hci_status;
669        bdcpy(p_buf->bd_addr, bd_addr);
670        bta_sys_sendmsg(p_buf);
671    }
672}
673
674/*******************************************************************************
675**
676** Function         bta_dm_pm_timer_cback
677**
678** Description      Power management timer callback.
679**
680**
681** Returns          void
682**
683*******************************************************************************/
684static void bta_dm_pm_timer_cback(void *p_tle)
685{
686    tBTA_DM_PM_TIMER  *p_buf;
687    UINT8 i;
688
689    APPL_TRACE_WARNING("dm_pm_timer expires");
690
691    for(i=0; i<BTA_DM_NUM_PM_TIMER; i++)
692    {
693
694        if(bta_dm_cb.pm_timer[i].in_use)
695        {
696
697            if(&bta_dm_cb.pm_timer[i].timer == (TIMER_LIST_ENT*) p_tle)
698            {
699                APPL_TRACE_WARNING("dm_pm_timer expires %d", i);
700                bta_dm_cb.pm_timer[i].in_use = FALSE;
701                break;
702            }
703
704        }
705
706    }
707
708
709    /* no more timers */
710    if(i==BTA_DM_NUM_PM_TIMER)
711    {
712        return;
713    }
714
715    if ((p_buf = (tBTA_DM_PM_TIMER *) GKI_getbuf(sizeof(tBTA_DM_PM_TIMER))) != NULL)
716    {
717        p_buf->hdr.event = BTA_DM_PM_TIMER_EVT;
718        bdcpy(p_buf->bd_addr, bta_dm_cb.pm_timer[i].peer_bdaddr);
719        bta_sys_sendmsg(p_buf);
720    }
721}
722
723/*******************************************************************************
724**
725** Function         bta_dm_pm_btm_status
726**
727** Description      Process pm status event from btm
728**
729**
730** Returns          void
731**
732*******************************************************************************/
733void bta_dm_pm_btm_status(tBTA_DM_MSG *p_data)
734{
735
736    tBTA_DM_PEER_DEVICE *p_dev;
737    tBTA_DM_DEV_INFO    info;
738
739    APPL_TRACE_DEBUG("bta_dm_pm_btm_status:%d", p_data->pm_status.status);
740    p_dev = bta_dm_find_peer_device(p_data->pm_status.bd_addr);
741    if(NULL == p_dev)
742        return;
743
744    info = p_dev->info;
745    /* check new mode */
746    switch (p_data->pm_status.status)
747    {
748        case BTM_PM_STS_ACTIVE:
749            /* if our sniff or park attempt failed
750            we should not try it again*/
751            if (p_data->pm_status.hci_status != 0)
752            {
753                APPL_TRACE_ERROR("bta_dm_pm_btm_status  hci_status=%d", p_data->pm_status.hci_status);
754                p_dev->info &= ~(BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF|BTA_DM_DI_SET_SNIFF);
755
756                if(p_dev->pm_mode_attempted &(BTA_DM_PM_PARK | BTA_DM_PM_SNIFF))
757                {
758                    p_dev->pm_mode_failed
759                        |= ((BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & p_dev->pm_mode_attempted);
760                    bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
761                    bta_dm_pm_set_mode(p_data->pm_status.bd_addr, FALSE);
762                }
763            }
764            else
765            {
766#if (BTM_SSR_INCLUDED == TRUE)
767                if(p_dev->prev_low)
768                {
769                    /* need to send the SSR paramaters to controller again */
770                    bta_dm_pm_ssr(p_dev->peer_bdaddr);
771                }
772                p_dev->prev_low = BTM_PM_STS_ACTIVE;
773#endif
774                bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
775                bta_dm_pm_set_mode(p_data->pm_status.bd_addr, FALSE);
776            }
777            break;
778
779#if (BTM_SSR_INCLUDED == TRUE)
780        case BTM_PM_STS_PARK:
781        case BTM_PM_STS_HOLD:
782            /* save the previous low power mode - for SSR.
783             * SSR parameters are sent to controller on "conn open".
784             * the numbers stay good until park/hold/detach */
785            if(p_dev->info & BTA_DM_DI_USE_SSR)
786                p_dev->prev_low = p_data->pm_status.status;
787            break;
788
789        case BTM_PM_STS_SSR:
790            if(p_data->pm_status.value)
791                p_dev->info |= BTA_DM_DI_USE_SSR;
792            else
793                p_dev->info &= ~BTA_DM_DI_USE_SSR;
794            break;
795#endif
796        case BTM_PM_STS_SNIFF:
797            if (p_data->pm_status.hci_status == 0)
798            {
799                /* Stop PM timer now if already active for
800                 * particular device since link is already
801                 * put in sniff mode by remote device, and
802                 * PM timer sole purpose is to put the link
803                 * in sniff mode from host side.
804                 */
805                bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
806            }
807            p_dev->info &= ~(BTA_DM_DI_SET_SNIFF|BTA_DM_DI_INT_SNIFF|BTA_DM_DI_ACP_SNIFF);
808            if (info & BTA_DM_DI_SET_SNIFF)
809                p_dev->info |= BTA_DM_DI_INT_SNIFF;
810            else
811                p_dev->info |= BTA_DM_DI_ACP_SNIFF;
812            break;
813
814        case BTM_PM_STS_ERROR:
815            p_dev->info &= ~BTA_DM_DI_SET_SNIFF;
816            break;
817
818        default:
819            break;
820    }
821
822
823
824}
825
826/*******************************************************************************
827**
828** Function         bta_dm_pm_timer
829**
830** Description      Process pm timer event from btm
831**
832**
833** Returns          void
834**
835*******************************************************************************/
836void bta_dm_pm_timer(tBTA_DM_MSG *p_data)
837{
838
839    APPL_TRACE_WARNING("proc dm_pm_timer expires");
840    bta_dm_pm_set_mode(p_data->pm_status.bd_addr, TRUE);
841
842
843}
844
845/*******************************************************************************
846**
847** Function         bta_dm_find_peer_device
848**
849** Description      Given an address, find the associated control block.
850**
851** Returns          tBTA_DM_PEER_DEVICE
852**
853*******************************************************************************/
854tBTA_DM_PEER_DEVICE * bta_dm_find_peer_device(BD_ADDR peer_addr)
855{
856    tBTA_DM_PEER_DEVICE *p_dev = NULL;
857    int i;
858
859    for(i=0; i<bta_dm_cb.device_list.count; i++)
860    {
861        if(!bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr))
862        {
863            p_dev = &bta_dm_cb.device_list.peer_device[i];
864            break;
865        }
866
867    }
868    return p_dev;
869}
870
871/*******************************************************************************
872**
873** Function         bta_dm_is_sco_active
874**
875** Description      Loop through connected services for HFP+State=SCO
876**
877** Returns          BOOLEAN. TRUE if SCO active, else FALSE
878**
879*******************************************************************************/
880static BOOLEAN bta_dm_pm_is_sco_active ()
881{
882    int j;
883    BOOLEAN bScoActive = FALSE;
884
885    for(j=0; j<bta_dm_conn_srvcs.count ; j++)
886    {
887        /* check if an entry already present */
888        if ( (bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_AG )  && (bta_dm_conn_srvcs.conn_srvc[j].state == BTA_SYS_SCO_OPEN) )
889        {
890            bScoActive = TRUE;
891            break;
892        }
893    }
894
895    APPL_TRACE_DEBUG("bta_dm_is_sco_active: SCO active: %d", bScoActive);
896    return bScoActive;
897}
898
899
900/*******************************************************************************
901**
902** Function         bta_dm_pm_hid_check
903**
904** Description      Disables/Enables sniff in link policy based on SCO Up/Down
905**
906** Returns          None
907**
908*******************************************************************************/
909
910static void bta_dm_pm_hid_check(BOOLEAN bScoActive)
911{
912    int j;
913
914    /* if HID is active, disable the link policy */
915    for(j=0; j<bta_dm_conn_srvcs.count ; j++)
916    {
917        /* check if an entry already present */
918        if(bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_HH )
919        {
920            APPL_TRACE_DEBUG ("SCO status change(Active: %d), modify HID link policy. state: %d",
921                bScoActive, bta_dm_conn_srvcs.conn_srvc[j].state);
922            bta_dm_pm_set_sniff_policy( bta_dm_find_peer_device(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr), bScoActive);
923
924            /* if we had disabled link policy, seems like the hid device stop retrying SNIFF after a few tries. force sniff if needed */
925            if (!bScoActive)
926                bta_dm_pm_set_mode(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, FALSE);
927        }
928    }
929
930}
931
932/*******************************************************************************
933**
934** Function         bta_dm_pm_set_sniff_policy
935**
936** Description      Disables/Enables sniff in link policy for the give device
937**
938** Returns          None
939**
940*******************************************************************************/
941static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE *p_dev, BOOLEAN bDisable)
942{
943    UINT16 policy_setting;
944
945    if (!p_dev)
946        return;
947
948    if (bDisable)
949    {
950        policy_setting = bta_dm_cb.cur_policy &
951            (HCI_ENABLE_MASTER_SLAVE_SWITCH |
952             HCI_ENABLE_HOLD_MODE  |
953             HCI_ENABLE_PARK_MODE);
954
955    }
956    else
957    {
958        /*  allow sniff after sco is closed */
959         policy_setting= bta_dm_cb.cur_policy;
960    }
961
962    /* if disabling SNIFF, make sure link is Active */
963    if (bDisable)
964        bta_dm_pm_active(p_dev->peer_bdaddr);
965
966    /* update device record and set link policy */
967    p_dev->link_policy = policy_setting;
968    BTM_SetLinkPolicy(p_dev->peer_bdaddr, &policy_setting);
969
970}
971
972#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
973/*******************************************************************************
974**
975** Function         bta_dm_pm_obtain_controller_state
976**
977** Description      This function obtains the consolidated controller power state
978**
979** Parameters:
980**
981*******************************************************************************/
982tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void)
983{
984    /*   Did not use counts as it is not sure, how accurate the count values are in
985     **  bta_dm_cb.device_list.count > 0 || bta_dm_cb.device_list.le_count > 0 */
986
987    tBTA_DM_CONTRL_STATE cur_state = BTA_DM_CONTRL_UNKNOWN;
988    cur_state = BTM_PM_ReadControllerState();
989
990    APPL_TRACE_DEBUG("bta_dm_pm_obtain_controller_state: %d", cur_state);
991    return cur_state;
992}
993#endif
994