aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-12-31 16:25:06 +0100
committerAleksander Morgado <aleksander@lanedo.com>2013-01-11 10:05:45 +0100
commite55b543d384296ad07fddc3bbcb0a9ec51c86e6a (patch)
treeda08e28626ae5e694939e13715a806fbbe2e26e9 /src
parent49aecb57dc2aeebb1e133816aec05321e5073cda (diff)
iface-modem: implement power mode loading and setting
Diffstat (limited to 'src')
-rw-r--r--src/mm-iface-modem.c435
-rw-r--r--src/mm-iface-modem.h17
2 files changed, 349 insertions, 103 deletions
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index 9b5f8dcd..be4b70d6 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -1443,6 +1443,106 @@ 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 {
+ MmGdbusModem *skeleton;
+ GDBusMethodInvocation *invocation;
+ MMIfaceModem *self;
} HandleResetContext;
static void
@@ -2592,6 +2692,185 @@ mm_iface_modem_update_lock_info (MMIfaceModem *self,
}
/*****************************************************************************/
+/* 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 */
typedef struct _DisablingContext DisablingContext;
@@ -2601,7 +2880,6 @@ typedef enum {
DISABLING_STEP_FIRST,
DISABLING_STEP_CURRENT_BANDS,
DISABLING_STEP_ALLOWED_MODES,
- DISABLING_STEP_MODEM_POWER_DOWN,
DISABLING_STEP_LAST
} DisablingStep;
@@ -2633,27 +2911,6 @@ mm_iface_modem_disable_finish (MMIfaceModem *self,
}
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
interface_disabling_step (DisablingContext *ctx)
{
switch (ctx->step) {
@@ -2674,25 +2931,6 @@ interface_disabling_step (DisablingContext *ctx)
/* Fall down to next 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:
/* We are done without errors! */
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
@@ -2742,8 +2980,7 @@ static void interface_enabling_step (EnablingContext *ctx);
typedef enum {
ENABLING_STEP_FIRST,
ENABLING_STEP_MODEM_INIT,
- ENABLING_STEP_MODEM_POWER_UP,
- ENABLING_STEP_MODEM_AFTER_POWER_UP,
+ ENABLING_STEP_SET_POWER_STATE,
ENABLING_STEP_FLOW_CONTROL,
ENABLING_STEP_SUPPORTED_CHARSETS,
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_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);
static void
@@ -2965,29 +3219,12 @@ interface_enabling_step (EnablingContext *ctx)
/* Fall down to next step */
ctx->step++;
- case ENABLING_STEP_MODEM_POWER_UP:
- if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_up &&
- MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_up_finish) {
- MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_up (
- ctx->self,
- (GAsyncReadyCallback)modem_power_up_ready,
- ctx);
- 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_SET_POWER_STATE:
+ mm_iface_modem_set_power_state (ctx->self,
+ MM_MODEM_POWER_STATE_ON,
+ (GAsyncReadyCallback)enabling_set_power_state_ready,
+ ctx);
+ return;
case ENABLING_STEP_FLOW_CONTROL:
if (MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->setup_flow_control &&
@@ -3136,7 +3373,6 @@ typedef enum {
INITIALIZATION_STEP_FIRST,
INITIALIZATION_STEP_CURRENT_CAPABILITIES,
INITIALIZATION_STEP_MODEM_CAPABILITIES,
- INITIALIZATION_STEP_POWER_DOWN,
INITIALIZATION_STEP_BEARERS,
INITIALIZATION_STEP_MANUFACTURER,
INITIALIZATION_STEP_MODEL,
@@ -3148,6 +3384,7 @@ typedef enum {
INITIALIZATION_STEP_OWN_NUMBERS,
INITIALIZATION_STEP_SUPPORTED_MODES,
INITIALIZATION_STEP_SUPPORTED_BANDS,
+ INITIALIZATION_STEP_POWER_STATE,
INITIALIZATION_STEP_LAST
} 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 (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 (model, "Model")
STR_REPLY_READY_FN (revision, "Revision")
@@ -3346,6 +3563,8 @@ load_supported_bands_ready (MMIfaceModem *self,
interface_initialization_step (ctx);
}
+UINT_REPLY_READY_FN (power_state, "Power State", FALSE)
+
static void
modem_update_lock_info_ready (MMIfaceModem *self,
GAsyncResult *res,
@@ -3512,20 +3731,6 @@ interface_initialization_step (InitializationContext *ctx)
/* Fall down to next 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: {
MMBearerList *list = NULL;
@@ -3749,6 +3954,25 @@ interface_initialization_step (InitializationContext *ctx)
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:
if (ctx->fatal_error) {
g_simple_async_result_take_error (ctx->result, ctx->fatal_error);
@@ -3777,6 +4001,10 @@ interface_initialization_step (InitializationContext *ctx)
G_CALLBACK (handle_enable),
ctx->self);
g_signal_connect (ctx->skeleton,
+ "handle-set-power-state",
+ G_CALLBACK (handle_set_power_state),
+ ctx->self);
+ g_signal_connect (ctx->skeleton,
"handle-reset",
G_CALLBACK (handle_reset),
ctx->self);
@@ -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_supported_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 */
g_object_bind_property (self, MM_IFACE_MODEM_STATE,
diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h
index 23dac75b..6ba2b3fb 100644
--- a/src/mm-iface-modem.h
+++ b/src/mm-iface-modem.h
@@ -164,6 +164,14 @@ struct _MMIfaceModem {
GAsyncResult *res,
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 */
void (*load_signal_quality) (MMIfaceModem *self,
GAsyncReadyCallback callback,
@@ -362,6 +370,15 @@ gboolean mm_iface_modem_disable_finish (MMIfaceModem *self,
GAsyncResult *res,
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 */
void mm_iface_modem_shutdown (MMIfaceModem *self);