aboutsummaryrefslogtreecommitdiff
path: root/src/mm-iface-modem.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2014-02-18 10:35:58 +0100
committerAleksander Morgado <aleksander@aleksander.es>2014-02-20 11:15:03 +0100
commit9239fbcd7a137f2bb349592d649fc80847e6e731 (patch)
tree3cae28c4c7027b7190c39b7a0d64c0850797f2ed /src/mm-iface-modem.c
parent705dd0133d8a02c0bf2a2cfa3d8920030dc1392d (diff)
iface-modem: allow transitioning to the OFF power state
There are systems in which the modem power source can be controlled externally, e.g. to switch it on or off. In these cases, it is sometimes advisable to be able to tell the modem to cleanly shut off completely before the power is cut. So, allow transitioning to the OFF power state if the modem supports it, even if afterwards the modem could be completely unreachable.
Diffstat (limited to 'src/mm-iface-modem.c')
-rw-r--r--src/mm-iface-modem.c88
1 files changed, 79 insertions, 9 deletions
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index 5edbbae0..9228bebf 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -1703,12 +1703,28 @@ handle_set_power_state_auth_ready (MMBaseModem *self,
return;
}
- /* Error if we're not in disabled state */
+ /* Only 'off', 'low' or 'up' expected */
+ if (ctx->power_state != MM_MODEM_POWER_STATE_LOW &&
+ ctx->power_state != MM_MODEM_POWER_STATE_ON &&
+ ctx->power_state != MM_MODEM_POWER_STATE_OFF) {
+ g_dbus_method_invocation_return_error (ctx->invocation,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot set '%s' power state",
+ mm_modem_power_state_get_string (ctx->power_state));
+ handle_set_power_state_context_free (ctx);
+ return;
+ }
+
modem_state = MM_MODEM_STATE_UNKNOWN;
g_object_get (self,
MM_IFACE_MODEM_STATE, &modem_state,
NULL);
- if (modem_state != MM_MODEM_STATE_DISABLED) {
+
+ /* Going into LOW or ON only allowed in disabled state */
+ if ((ctx->power_state == MM_MODEM_POWER_STATE_LOW ||
+ ctx->power_state == MM_MODEM_POWER_STATE_ON) &&
+ modem_state != MM_MODEM_STATE_DISABLED) {
g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
MM_CORE_ERROR_WRONG_STATE,
@@ -1717,14 +1733,15 @@ handle_set_power_state_auth_ready (MMBaseModem *self,
return;
}
- /* Only 'low' or 'up' expected */
- if (ctx->power_state != MM_MODEM_POWER_STATE_LOW &&
- ctx->power_state != MM_MODEM_POWER_STATE_ON) {
+ /* Going into OFF, only allowed if locked, disabled or failed */
+ if (ctx->power_state == MM_MODEM_POWER_STATE_OFF &&
+ modem_state != MM_MODEM_STATE_FAILED &&
+ modem_state != MM_MODEM_STATE_LOCKED &&
+ modem_state != MM_MODEM_STATE_DISABLED) {
g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
- MM_CORE_ERROR_INVALID_ARGS,
- "Cannot set '%s' power state",
- mm_modem_power_state_get_string (ctx->power_state));
+ MM_CORE_ERROR_WRONG_STATE,
+ "Cannot set power state: modem either enabled or initializing");
handle_set_power_state_context_free (ctx);
return;
}
@@ -3191,6 +3208,28 @@ modem_power_down_ready (MMIfaceModem *self,
}
static void
+modem_power_off_ready (MMIfaceModem *self,
+ GAsyncResult *res,
+ SetPowerStateContext *ctx)
+{
+ GError *error = NULL;
+
+ MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_off_finish (self, res, &error);
+ if (error) {
+ /* If the real and cached ones are different, set the real one */
+ if (ctx->previous_cached_power_state != ctx->previous_real_power_state)
+ mm_gdbus_modem_set_power_state (ctx->skeleton, ctx->previous_real_power_state);
+ g_simple_async_result_take_error (ctx->result, error);
+ } else {
+ mm_info ("Modem powered off... may no longer be accessible");
+ 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);
+}
+
+static void
set_power_state (SetPowerStateContext *ctx)
{
/* Already done if we're in the desired power state */
@@ -3205,11 +3244,42 @@ set_power_state (SetPowerStateContext *ctx)
return;
}
+ /* Don't allow trying to recover from a power off */
+ if (ctx->previous_real_power_state == MM_MODEM_POWER_STATE_OFF) {
+ g_simple_async_result_set_error (ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_WRONG_STATE,
+ "Cannot recover from a power off");
+ set_power_state_context_complete_and_free (ctx);
+ return;
+ }
+
/* Supported transitions:
- * UNKNOWN|OFF|LOW --> ON
+ * UNKNOWN|LOW --> ON
* ON --> LOW
+ * ON|LOW --> OFF
*/
+ /* Fully powering off the modem? */
+ if (ctx->power_state == MM_MODEM_POWER_STATE_OFF) {
+ /* Error if unsupported */
+ if (!MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_off ||
+ !MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_off_finish) {
+ g_simple_async_result_set_error (ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Powering off is not supported by this modem");
+ set_power_state_context_complete_and_free (ctx);
+ return;
+ }
+
+ MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->modem_power_off (
+ MM_IFACE_MODEM (ctx->self),
+ (GAsyncReadyCallback)modem_power_off_ready,
+ ctx);
+ return;
+ }
+
/* Going into low power mode? */
if (ctx->power_state == MM_MODEM_POWER_STATE_LOW) {
/* Error if unsupported */