iface-modem: implement power mode loading and setting

This commit is contained in:
Aleksander Morgado
2012-12-31 16:25:06 +01:00
parent 49aecb57dc
commit e55b543d38
2 changed files with 349 additions and 103 deletions

View File

@@ -1439,6 +1439,106 @@ handle_enable (MmGdbusModem *skeleton,
/*****************************************************************************/ /*****************************************************************************/
typedef struct {
MmGdbusModem *skeleton;
GDBusMethodInvocation *invocation;
MMIfaceModem *self;
MMModemPowerState power_state;
} HandleSetPowerStateContext;
static void
handle_set_power_state_context_free (HandleSetPowerStateContext *ctx)
{
g_object_unref (ctx->skeleton);
g_object_unref (ctx->invocation);
g_object_unref (ctx->self);
g_slice_free (HandleSetPowerStateContext, ctx);
}
static void
set_power_state_ready (MMIfaceModem *self,
GAsyncResult *res,
HandleSetPowerStateContext *ctx)
{
GError *error = NULL;
if (!mm_iface_modem_set_power_state_finish (self, res, &error))
g_dbus_method_invocation_take_error (ctx->invocation, error);
else
mm_gdbus_modem_complete_set_power_state (ctx->skeleton, ctx->invocation);
handle_set_power_state_context_free (ctx);
}
static void
handle_set_power_state_auth_ready (MMBaseModem *self,
GAsyncResult *res,
HandleSetPowerStateContext *ctx)
{
MMModemState modem_state;
GError *error = NULL;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_set_power_state_context_free (ctx);
return;
}
/* Error if we're not in disabled state */
modem_state = MM_MODEM_STATE_UNKNOWN;
g_object_get (self,
MM_IFACE_MODEM_STATE, &modem_state,
NULL);
if (modem_state != MM_MODEM_STATE_DISABLED) {
g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
MM_CORE_ERROR_WRONG_STATE,
"Cannot set power state: not in disabled state");
handle_set_power_state_context_free (ctx);
return;
}
/* Only 'low' or 'up' expected */
if (ctx->power_state != MM_MODEM_POWER_STATE_LOW &&
ctx->power_state != MM_MODEM_POWER_STATE_ON) {
g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"Cannot set '%s' power state",
ctx->power_state);
handle_set_power_state_context_free (ctx);
return;
}
mm_iface_modem_set_power_state (MM_IFACE_MODEM (self),
ctx->power_state,
(GAsyncReadyCallback)set_power_state_ready,
ctx);
}
static gboolean
handle_set_power_state (MmGdbusModem *skeleton,
GDBusMethodInvocation *invocation,
guint32 power_state,
MMIfaceModem *self)
{
HandleSetPowerStateContext *ctx;
ctx = g_slice_new (HandleSetPowerStateContext);
ctx->skeleton = g_object_ref (skeleton);
ctx->invocation = g_object_ref (invocation);
ctx->self = g_object_ref (self);
ctx->power_state = (MMModemPowerState)power_state;
mm_base_modem_authorize (MM_BASE_MODEM (self),
invocation,
MM_AUTHORIZATION_DEVICE_CONTROL,
(GAsyncReadyCallback)handle_set_power_state_auth_ready,
ctx);
return TRUE;
}
/*****************************************************************************/
typedef struct { typedef struct {
MmGdbusModem *skeleton; MmGdbusModem *skeleton;
GDBusMethodInvocation *invocation; GDBusMethodInvocation *invocation;
@@ -2591,6 +2691,185 @@ mm_iface_modem_update_lock_info (MMIfaceModem *self,
update_lock_info_context_step (ctx); update_lock_info_context_step (ctx);
} }
/*****************************************************************************/
/* Set power state sequence */
typedef struct {
MMIfaceModem *self;
GSimpleAsyncResult *result;
MmGdbusModem *skeleton;
MMModemPowerState power_state;
MMModemPowerState previous_power_state;
} SetPowerStateContext;
static void
set_power_state_context_complete_and_free (SetPowerStateContext *ctx)
{
g_simple_async_result_complete_in_idle (ctx->result);
g_object_unref (ctx->self);
g_object_unref (ctx->result);
if (ctx->skeleton)
g_object_unref (ctx->skeleton);
g_slice_free (SetPowerStateContext, ctx);
}
gboolean
mm_iface_modem_set_power_state_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
}
static void
modem_after_power_up_ready (MMIfaceModem *self,
GAsyncResult *res,
SetPowerStateContext *ctx)
{
GError *error = NULL;
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up_finish (self, res, &error);
if (error)
g_simple_async_result_take_error (ctx->result, error);
else
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
set_power_state_context_complete_and_free (ctx);
}
static void
modem_power_up_ready (MMIfaceModem *self,
GAsyncResult *res,
SetPowerStateContext *ctx)
{
GError *error = NULL;
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish (self, res, &error);
if (error) {
g_simple_async_result_take_error (ctx->result, error);
set_power_state_context_complete_and_free (ctx);
return;
}
mm_dbg ("Modem set in full-power mode...");
mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->power_state);
/* If we have something to do just after power-up, do it */
if (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up &&
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up_finish) {
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_after_power_up (
self,
(GAsyncReadyCallback)modem_after_power_up_ready,
ctx);
return;
}
/* Otherwise, we're done */
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
set_power_state_context_complete_and_free (ctx);
}
static void
modem_power_down_ready (MMIfaceModem *self,
GAsyncResult *res,
SetPowerStateContext *ctx)
{
GError *error = NULL;
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish (self, res, &error);
if (error)
g_simple_async_result_take_error (ctx->result, error);
else {
mm_dbg ("Modem set in low-power mode...");
mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->power_state);
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
}
set_power_state_context_complete_and_free (ctx);
}
void
mm_iface_modem_set_power_state (MMIfaceModem *self,
MMModemPowerState power_state,
GAsyncReadyCallback callback,
gpointer user_data)
{
SetPowerStateContext *ctx;
ctx = g_slice_new0 (SetPowerStateContext);
ctx->self = g_object_ref (self);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
mm_iface_modem_set_power_state);
ctx->power_state = power_state;
g_object_get (ctx->self,
MM_IFACE_MODEM_DBUS_SKELETON, &ctx->skeleton,
NULL);
if (!ctx->skeleton) {
g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Couldn't get interface skeleton");
set_power_state_context_complete_and_free (ctx);
return;
}
ctx->previous_power_state = mm_gdbus_modem_get_power_state (ctx->skeleton);
/* Already done if we're in the desired power state */
if (ctx->previous_power_state == ctx->power_state) {
mm_dbg ("No need to change power state: already in '%s' power state",
mm_modem_power_state_get_string (ctx->power_state));
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
set_power_state_context_complete_and_free (ctx);
return;
}
/* Supported transitions:
* UNKNOWN|OFF|LOW --> ON
* ON --> LOW
*/
/* Going into low power mode? */
if (ctx->power_state == MM_MODEM_POWER_STATE_LOW) {
/* Error if unsupported */
if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down ||
!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish) {
g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
"Going into low-power mode is not supported by this modem");
set_power_state_context_complete_and_free (ctx);
return;
}
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down (MM_IFACE_MODEM (self),
(GAsyncReadyCallback)modem_power_down_ready,
ctx);
return;
}
/* Going out of low power mode? */
if (ctx->power_state == MM_MODEM_POWER_STATE_ON) {
/* Error if unsupported */
if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up ||
!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish) {
g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
"Going into full-power mode is not supported by this modem");
set_power_state_context_complete_and_free (ctx);
return;
}
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up (MM_IFACE_MODEM (self),
(GAsyncReadyCallback)modem_power_up_ready,
ctx);
return;
}
g_assert_not_reached ();
}
/*****************************************************************************/ /*****************************************************************************/
/* MODEM DISABLING */ /* MODEM DISABLING */
@@ -2601,7 +2880,6 @@ typedef enum {
DISABLING_STEP_FIRST, DISABLING_STEP_FIRST,
DISABLING_STEP_CURRENT_BANDS, DISABLING_STEP_CURRENT_BANDS,
DISABLING_STEP_ALLOWED_MODES, DISABLING_STEP_ALLOWED_MODES,
DISABLING_STEP_MODEM_POWER_DOWN,
DISABLING_STEP_LAST DISABLING_STEP_LAST
} DisablingStep; } DisablingStep;
@@ -2632,27 +2910,6 @@ mm_iface_modem_disable_finish (MMIfaceModem *self,
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
} }
static void
modem_power_down_ready (MMIfaceModem *self,
GAsyncResult *res,
DisablingContext *ctx)
{
GError *error = NULL;
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish (self, res, &error);
if (error) {
g_simple_async_result_take_error (ctx->result, error);
disabling_context_complete_and_free (ctx);
return;
}
mm_dbg ("Modem properly powered down...");
/* Go on to next step */
ctx->step++;
interface_disabling_step (ctx);
}
static void static void
interface_disabling_step (DisablingContext *ctx) interface_disabling_step (DisablingContext *ctx)
{ {
@@ -2674,25 +2931,6 @@ interface_disabling_step (DisablingContext *ctx)
/* Fall down to next step */ /* Fall down to next step */
ctx->step++; ctx->step++;
case DISABLING_STEP_MODEM_POWER_DOWN:
/* CFUN=0 is dangerous and often will shoot devices in the head (that's
* what it's supposed to do). So don't use CFUN=0 by default, but let
* specific plugins use it when they know it's safe to do so. For
* example, CFUN=0 will often make phones turn themselves off, but some
* dedicated devices (ex Sierra WWAN cards) will just turn off their
* radio but otherwise still work.
*/
if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_down &&
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_down_finish) {
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_down (
ctx->self,
(GAsyncReadyCallback)modem_power_down_ready,
ctx);
return;
}
/* Fall down to next step */
ctx->step++;
case DISABLING_STEP_LAST: case DISABLING_STEP_LAST:
/* We are done without errors! */ /* We are done without errors! */
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
@@ -2742,8 +2980,7 @@ static void interface_enabling_step (EnablingContext *ctx);
typedef enum { typedef enum {
ENABLING_STEP_FIRST, ENABLING_STEP_FIRST,
ENABLING_STEP_MODEM_INIT, ENABLING_STEP_MODEM_INIT,
ENABLING_STEP_MODEM_POWER_UP, ENABLING_STEP_SET_POWER_STATE,
ENABLING_STEP_MODEM_AFTER_POWER_UP,
ENABLING_STEP_FLOW_CONTROL, ENABLING_STEP_FLOW_CONTROL,
ENABLING_STEP_SUPPORTED_CHARSETS, ENABLING_STEP_SUPPORTED_CHARSETS,
ENABLING_STEP_CHARSET, ENABLING_STEP_CHARSET,
@@ -2818,8 +3055,25 @@ mm_iface_modem_enable_finish (MMIfaceModem *self,
} }
VOID_REPLY_READY_FN (modem_init); VOID_REPLY_READY_FN (modem_init);
VOID_REPLY_READY_FN (modem_power_up);
VOID_REPLY_READY_FN (modem_after_power_up); static void
enabling_set_power_state_ready (MMIfaceModem *self,
GAsyncResult *res,
EnablingContext *ctx)
{
GError *error = NULL;
if (!mm_iface_modem_set_power_state_finish (self, res, &error)) {
g_simple_async_result_take_error (ctx->result, error);
enabling_context_complete_and_free (ctx);
return;
}
/* Go on to next step */
ctx->step++;
interface_enabling_step (ctx);
}
VOID_REPLY_READY_FN (setup_flow_control); VOID_REPLY_READY_FN (setup_flow_control);
static void static void
@@ -2965,29 +3219,12 @@ interface_enabling_step (EnablingContext *ctx)
/* Fall down to next step */ /* Fall down to next step */
ctx->step++; ctx->step++;
case ENABLING_STEP_MODEM_POWER_UP: case ENABLING_STEP_SET_POWER_STATE:
if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_up && mm_iface_modem_set_power_state (ctx->self,
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_up_finish) { MM_MODEM_POWER_STATE_ON,
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_up ( (GAsyncReadyCallback)enabling_set_power_state_ready,
ctx->self,
(GAsyncReadyCallback)modem_power_up_ready,
ctx); ctx);
return; return;
}
/* Fall down to next step */
ctx->step++;
case ENABLING_STEP_MODEM_AFTER_POWER_UP:
if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_after_power_up &&
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_after_power_up_finish) {
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_after_power_up (
ctx->self,
(GAsyncReadyCallback)modem_after_power_up_ready,
ctx);
return;
}
/* Fall down to next step */
ctx->step++;
case ENABLING_STEP_FLOW_CONTROL: case ENABLING_STEP_FLOW_CONTROL:
if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->setup_flow_control && if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->setup_flow_control &&
@@ -3136,7 +3373,6 @@ typedef enum {
INITIALIZATION_STEP_FIRST, INITIALIZATION_STEP_FIRST,
INITIALIZATION_STEP_CURRENT_CAPABILITIES, INITIALIZATION_STEP_CURRENT_CAPABILITIES,
INITIALIZATION_STEP_MODEM_CAPABILITIES, INITIALIZATION_STEP_MODEM_CAPABILITIES,
INITIALIZATION_STEP_POWER_DOWN,
INITIALIZATION_STEP_BEARERS, INITIALIZATION_STEP_BEARERS,
INITIALIZATION_STEP_MANUFACTURER, INITIALIZATION_STEP_MANUFACTURER,
INITIALIZATION_STEP_MODEL, INITIALIZATION_STEP_MODEL,
@@ -3148,6 +3384,7 @@ typedef enum {
INITIALIZATION_STEP_OWN_NUMBERS, INITIALIZATION_STEP_OWN_NUMBERS,
INITIALIZATION_STEP_SUPPORTED_MODES, INITIALIZATION_STEP_SUPPORTED_MODES,
INITIALIZATION_STEP_SUPPORTED_BANDS, INITIALIZATION_STEP_SUPPORTED_BANDS,
INITIALIZATION_STEP_POWER_STATE,
INITIALIZATION_STEP_LAST INITIALIZATION_STEP_LAST
} InitializationStep; } InitializationStep;
@@ -3245,26 +3482,6 @@ initialization_context_complete_and_free_if_cancelled (InitializationContext *ct
UINT_REPLY_READY_FN (current_capabilities, "Current Capabilities", TRUE) UINT_REPLY_READY_FN (current_capabilities, "Current Capabilities", TRUE)
UINT_REPLY_READY_FN (modem_capabilities, "Modem Capabilities", FALSE) UINT_REPLY_READY_FN (modem_capabilities, "Modem Capabilities", FALSE)
static void
initialization_modem_power_down_ready (MMIfaceModem *self,
GAsyncResult *res,
InitializationContext *ctx)
{
GError *error = NULL;
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_init_power_down_finish (self, res, &error);
if (error) {
mm_dbg ("Couldn't power down the modem during initialization: '%s'", error->message);
g_error_free (error);
} else
mm_dbg ("Modem initially powered down...");
/* Go on to next step */
ctx->step++;
interface_initialization_step (ctx);
}
STR_REPLY_READY_FN (manufacturer, "Manufacturer") STR_REPLY_READY_FN (manufacturer, "Manufacturer")
STR_REPLY_READY_FN (model, "Model") STR_REPLY_READY_FN (model, "Model")
STR_REPLY_READY_FN (revision, "Revision") STR_REPLY_READY_FN (revision, "Revision")
@@ -3346,6 +3563,8 @@ load_supported_bands_ready (MMIfaceModem *self,
interface_initialization_step (ctx); interface_initialization_step (ctx);
} }
UINT_REPLY_READY_FN (power_state, "Power State", FALSE)
static void static void
modem_update_lock_info_ready (MMIfaceModem *self, modem_update_lock_info_ready (MMIfaceModem *self,
GAsyncResult *res, GAsyncResult *res,
@@ -3512,20 +3731,6 @@ interface_initialization_step (InitializationContext *ctx)
/* Fall down to next step */ /* Fall down to next step */
ctx->step++; ctx->step++;
case INITIALIZATION_STEP_POWER_DOWN:
/* We run the power down command during initialization, to ensure we
* start with radio off, when possible */
if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_init_power_down &&
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_init_power_down_finish) {
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_init_power_down (
ctx->self,
(GAsyncReadyCallback)initialization_modem_power_down_ready,
ctx);
return;
}
/* Fall down to next step */
ctx->step++;
case INITIALIZATION_STEP_BEARERS: { case INITIALIZATION_STEP_BEARERS: {
MMBearerList *list = NULL; MMBearerList *list = NULL;
@@ -3749,6 +3954,25 @@ interface_initialization_step (InitializationContext *ctx)
ctx->step++; ctx->step++;
} }
case INITIALIZATION_STEP_POWER_STATE:
/* Initial power state is meant to be loaded only once. Therefore, if we
* already have it loaded, don't try to load it again. */
if (mm_gdbus_modem_get_power_state (ctx->skeleton) == MM_MODEM_POWER_STATE_UNKNOWN) {
if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_power_state &&
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_power_state_finish) {
MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_power_state (
ctx->self,
(GAsyncReadyCallback)load_power_state_ready,
ctx);
return;
}
/* We don't know how to load current power state; assume ON */
mm_gdbus_modem_set_power_state (ctx->skeleton, MM_MODEM_POWER_STATE_ON);
}
/* Fall down to next step */
ctx->step++;
case INITIALIZATION_STEP_LAST: case INITIALIZATION_STEP_LAST:
if (ctx->fatal_error) { if (ctx->fatal_error) {
g_simple_async_result_take_error (ctx->result, ctx->fatal_error); g_simple_async_result_take_error (ctx->result, ctx->fatal_error);
@@ -3776,6 +4000,10 @@ interface_initialization_step (InitializationContext *ctx)
"handle-enable", "handle-enable",
G_CALLBACK (handle_enable), G_CALLBACK (handle_enable),
ctx->self); ctx->self);
g_signal_connect (ctx->skeleton,
"handle-set-power-state",
G_CALLBACK (handle_set_power_state),
ctx->self);
g_signal_connect (ctx->skeleton, g_signal_connect (ctx->skeleton,
"handle-reset", "handle-reset",
G_CALLBACK (handle_reset), G_CALLBACK (handle_reset),
@@ -3855,6 +4083,7 @@ mm_iface_modem_initialize (MMIfaceModem *self,
mm_gdbus_modem_set_preferred_mode (skeleton, MM_MODEM_MODE_NONE); mm_gdbus_modem_set_preferred_mode (skeleton, MM_MODEM_MODE_NONE);
mm_gdbus_modem_set_supported_bands (skeleton, mm_common_build_bands_unknown ()); mm_gdbus_modem_set_supported_bands (skeleton, mm_common_build_bands_unknown ());
mm_gdbus_modem_set_bands (skeleton, mm_common_build_bands_unknown ()); mm_gdbus_modem_set_bands (skeleton, mm_common_build_bands_unknown ());
mm_gdbus_modem_set_power_state (skeleton, MM_MODEM_POWER_STATE_UNKNOWN);
/* Bind our State property */ /* Bind our State property */
g_object_bind_property (self, MM_IFACE_MODEM_STATE, g_object_bind_property (self, MM_IFACE_MODEM_STATE,

View File

@@ -164,6 +164,14 @@ struct _MMIfaceModem {
GAsyncResult *res, GAsyncResult *res,
GError **error); GError **error);
/* Loading of the PowerState property */
void (* load_power_state) (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data);
MMModemPowerState (*load_power_state_finish) (MMIfaceModem *self,
GAsyncResult *res,
GError **error);
/* Loading of the SignalQuality property */ /* Loading of the SignalQuality property */
void (*load_signal_quality) (MMIfaceModem *self, void (*load_signal_quality) (MMIfaceModem *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
@@ -362,6 +370,15 @@ gboolean mm_iface_modem_disable_finish (MMIfaceModem *self,
GAsyncResult *res, GAsyncResult *res,
GError **error); GError **error);
/* Allow setting power state */
void mm_iface_modem_set_power_state (MMIfaceModem *self,
MMModemPowerState power_state,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_iface_modem_set_power_state_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error);
/* Shutdown Modem interface */ /* Shutdown Modem interface */
void mm_iface_modem_shutdown (MMIfaceModem *self); void mm_iface_modem_shutdown (MMIfaceModem *self);