summaryrefslogtreecommitdiffstats
path: root/stack/hid/hidd_pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'stack/hid/hidd_pm.c')
-rw-r--r--stack/hid/hidd_pm.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/stack/hid/hidd_pm.c b/stack/hid/hidd_pm.c
new file mode 100644
index 0000000..ff3cc22
--- /dev/null
+++ b/stack/hid/hidd_pm.c
@@ -0,0 +1,288 @@
+/*****************************************************************************/
+/* */
+/* Name: hidd_pm.c */
+/* */
+/* Description: this file contains the HID Device Power Management logic */
+/* */
+/* */
+/* Copyright (c) 2002-2004, WIDCOMM Inc., All Rights Reserved. */
+/* WIDCOMM Bluetooth Core. Proprietary and confidential. */
+/*****************************************************************************/
+
+
+#include "gki.h"
+#include "bt_types.h"
+#include "hiddefs.h"
+#include "btm_api.h"
+#include "string.h"
+
+#include "hiddefs.h"
+
+#include "hidd_api.h"
+#include "hidd_int.h"
+#include "btu.h"
+
+#if HID_DEV_PM_INCLUDED == TRUE
+
+/*******************************************************************************
+**
+** Function hidd_pm_init
+**
+** Description This function is called when connection is established. It
+** initializes the control block for power management.
+**
+** Returns void
+**
+*******************************************************************************/
+
+static const tHID_DEV_PM_PWR_MD pwr_modes[] =
+{
+ HID_DEV_BUSY_MODE_PARAMS,
+ HID_DEV_IDLE_MODE_PARAMS,
+ HID_DEV_SUSP_MODE_PARAMS
+};
+
+void hidd_pm_init( void )
+{
+ int i;
+
+ hd_cb.curr_pm.mode = HCI_MODE_ACTIVE ;
+ hd_cb.final_pm.mode = 0xff;
+
+ for( i=0; i<3; i++ )
+ memcpy( &hd_cb.pm_params[i], &pwr_modes[i], sizeof( tHID_DEV_PM_PWR_MD ) ) ;
+
+ hd_cb.pm_ctrl_busy = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function hidd_pm_set_now
+**
+** Description This drives the BTM for power management settings.
+**
+** Returns TRUE if Success, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN hidd_pm_set_now( tHID_DEV_PM_PWR_MD *p_req_mode)
+{
+ tHID_DEV_PM_PWR_MD act_pm = { 0, 0, 0, 0, HCI_MODE_ACTIVE } ;
+ UINT8 st = BTM_SUCCESS;
+
+ /* Do nothing if already in required state or already performing a pm function */
+ if( (hd_cb.pm_ctrl_busy) ||
+ ((p_req_mode->mode == hd_cb.curr_pm.mode) && ( (p_req_mode->mode == HCI_MODE_ACTIVE) ||
+ ((hd_cb.curr_pm.interval >= p_req_mode->min) && (hd_cb.curr_pm.interval <= p_req_mode->max)) )) )
+ {
+ hd_cb.final_pm.mode = 0xff;
+ return TRUE;
+ }
+
+ switch( p_req_mode->mode )
+ {
+ case HCI_MODE_ACTIVE:
+ if( hd_cb.curr_pm.mode == HCI_MODE_SNIFF )
+ {
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ st = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, hd_cb.host_addr, (tBTM_PM_PWR_MD *) &act_pm);
+#else
+ st = BTM_CancelSniffMode (hd_cb.host_addr);
+#endif
+ hd_cb.pm_ctrl_busy = TRUE;
+ }
+ else if( hd_cb.curr_pm.mode == HCI_MODE_PARK )
+ {
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ st = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, hd_cb.host_addr, (tBTM_PM_PWR_MD *) &act_pm);
+#else
+ st = BTM_CancelParkMode (hd_cb.host_addr);
+#endif
+ hd_cb.pm_ctrl_busy = TRUE;
+ }
+ break;
+
+ case HCI_MODE_SNIFF:
+ if( hd_cb.curr_pm.mode != HCI_MODE_ACTIVE ) /* Transition through active state required */
+ hidd_pm_set_now (&act_pm);
+ else
+ {
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ st = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, hd_cb.host_addr, (tBTM_PM_PWR_MD *) p_req_mode);
+#else
+ st = BTM_SetSniffMode (hd_cb.host_addr, p_req_mode->min, p_req_mode->max, p_req_mode->attempt, p_req_mode->timeout);
+#endif
+ hd_cb.pm_ctrl_busy = TRUE;
+ }
+ break;
+
+ case HCI_MODE_PARK:
+ if( hd_cb.curr_pm.mode != HCI_MODE_ACTIVE ) /* Transition through active state required */
+ hidd_pm_set_now (&act_pm);
+ else
+ {
+#if BTM_PWR_MGR_INCLUDED == TRUE
+ st = BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, hd_cb.host_addr, (tBTM_PM_PWR_MD *) p_req_mode);
+#else
+ st = BTM_SetParkMode (hd_cb.host_addr, p_req_mode->min, p_req_mode->max);
+#endif
+ hd_cb.pm_ctrl_busy = TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if( st == BTM_SUCCESS || st == BTM_CMD_STARTED )
+ return TRUE;
+ else
+ {
+ st += HCI_ERR_MAX_ERR ;
+ if( hd_cb.callback )
+ hd_cb.callback( HID_DEV_EVT_PM_FAILED, hd_cb.conn_substate, (tHID_DEV_CBACK_DATA *) &st ) ;
+ return FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function hidd_pm_set_power_mode
+**
+** Description This stores the power management setting and calls fn to set
+** the power.
+**
+** Returns TRUE if Success, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN hidd_pm_set_power_mode( tHID_DEV_PM_PWR_MD *p_req_mode)
+{
+ memcpy( &hd_cb.final_pm, p_req_mode, sizeof( tHID_DEV_PM_PWR_MD ) ) ;
+ return hidd_pm_set_now( p_req_mode ) ;
+}
+
+
+/*******************************************************************************
+**
+** Function hidd_pm_proc_mode_change
+**
+** Description This is the callback function, when power mode changes.
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_pm_proc_mode_change( UINT8 hci_status, UINT8 mode, UINT16 interval )
+{
+ if (!hd_cb.reg_flag )
+ return;
+
+ hd_cb.pm_ctrl_busy = FALSE;
+
+ if( hci_status != HCI_SUCCESS )
+ {
+ if( hd_cb.callback )
+ hd_cb.callback( HID_DEV_EVT_PM_FAILED, hd_cb.conn_substate, (tHID_DEV_CBACK_DATA *) &hci_status ) ;
+ }
+ else
+ {
+ hd_cb.curr_pm.mode = mode;
+ hd_cb.curr_pm.interval = interval;
+
+ if( hd_cb.final_pm.mode != 0xff )
+ {
+ /* If we haven't reached the final power mode, set it now */
+ if( (hd_cb.final_pm.mode != hd_cb.curr_pm.mode) ||
+ ( (hd_cb.final_pm.mode != HCI_MODE_ACTIVE) &&
+ ((hd_cb.curr_pm.interval < hd_cb.final_pm.min) || (hd_cb.curr_pm.interval > hd_cb.final_pm.max))
+ ) )
+ {
+ hidd_pm_set_now( &(hd_cb.final_pm) ) ;
+ }
+ else
+ hd_cb.final_pm.mode = 0xff;
+ }
+ else
+ {
+ if( hd_cb.curr_pm.mode == HCI_MODE_ACTIVE )
+ hidd_pm_start();
+ }
+
+ if( hd_cb.callback )
+ hd_cb.callback( HID_DEV_EVT_MODE_CHG, mode, (tHID_DEV_CBACK_DATA *) &interval) ;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function hidd_pm_inact_timeout
+**
+** Description Called when idle timer expires.
+**
+** Returns void
+**
+*******************************************************************************/
+void hidd_pm_inact_timeout (TIMER_LIST_ENT *p_tle)
+{
+ hidd_pm_set_power_mode ( &(hd_cb.pm_params[HID_DEV_IDLE_CONN_ST]));
+ hd_cb.conn_substate = HID_DEV_IDLE_CONN_ST;
+}
+
+/*******************************************************************************
+**
+** Function hidd_pm_start
+**
+** Description Starts the power management function in a given state.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidd_pm_start( void )
+{
+ hidd_pm_set_power_mode ( &(hd_cb.pm_params[HID_DEV_BUSY_CONN_ST]) );
+
+ hd_cb.conn_substate = HID_DEV_BUSY_CONN_ST;
+
+ hd_cb.idle_tle.param = (UINT32) hidd_pm_inact_timeout;
+ btu_start_timer (&hd_cb.idle_tle, BTU_TTYPE_USER_FUNC, HID_DEV_INACT_TIMEOUT);
+
+ return( HID_SUCCESS );
+}
+
+/*******************************************************************************
+**
+** Function hidd_pm_stop
+**
+** Description Stops the idle timer.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidd_pm_stop( void )
+{
+ tHID_DEV_PM_PWR_MD p_md = { 0, 0, 0, 0, HCI_MODE_ACTIVE };
+
+ hidd_pm_set_power_mode( &p_md );
+ btu_stop_timer( &hd_cb.idle_tle ) ;
+ return( HID_SUCCESS );
+}
+
+
+/*******************************************************************************
+**
+** Function hidd_pm_suspend_evt
+**
+** Description Called when host suspends the device.
+**
+** Returns tHID_STATUS
+**
+*******************************************************************************/
+tHID_STATUS hidd_pm_suspend_evt( void )
+{
+ if( hd_cb.conn_substate == HID_DEV_BUSY_CONN_ST )
+ btu_stop_timer( &hd_cb.idle_tle ) ;
+
+ hidd_pm_set_power_mode ( &(hd_cb.pm_params[HID_DEV_SUSP_CONN_ST]) );
+ hd_cb.conn_substate = HID_DEV_SUSP_CONN_ST;
+ return( HID_SUCCESS );
+}
+#endif /* HID_DEV_PM_INCLUDED == TRUE */