From 9bbc6ab53b14097c510548dde4818a596e551617 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 27 Oct 2009 15:01:00 -0700 Subject: core: initial implementation of modem states Needs more work for GSM, but should be reasonably complete for CDMA. --- src/mm-generic-cdma.c | 50 ++++++++++++++++++++++++++++++++------- src/mm-generic-gsm.c | 35 ++++++++++++++++++++++++++- src/mm-generic-gsm.h | 3 +++ src/mm-modem-base.c | 11 +++++++++ src/mm-modem.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/mm-modem.h | 30 ++++++++++++++++++++++++ 6 files changed, 184 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index b113ddc6..2ca395c0 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -291,6 +291,18 @@ mm_generic_cdma_evdo_get_registration_state_sync (MMGenericCdma *self) /*****************************************************************************/ +static void +set_state_enabled (MMGenericCdma *self, MMModemStateReason reason) +{ + MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self); + + if ( priv->cdma_1x_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN + || priv->evdo_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); + else + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_ENABLED, reason); +} + static void registration_cleanup (MMGenericCdma *self, GQuark error_class, guint32 error_num) { @@ -337,6 +349,8 @@ enable_error_reporting_done (MMSerialPort *port, g_assert (info->error); } + set_state_enabled (MM_GENERIC_CDMA (info->modem), MM_MODEM_STATE_REASON_NONE); + /* Ignore errors, see FIXME in init_done() */ mm_callback_info_schedule (info); } @@ -406,8 +420,12 @@ disable_flash_done (MMSerialPort *port, if (error) info->error = g_error_copy (error); - else + else { mm_serial_port_close (port); + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); + } mm_callback_info_schedule (info); } @@ -445,13 +463,15 @@ dial_done (MMSerialPort *port, MMGenericCdma *self = MM_GENERIC_CDMA (info->modem); MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);; - if (error) + if (error) { info->error = g_error_copy (error); - else { + mm_modem_set_state (info->modem, MM_MODEM_STATE_REGISTERED, MM_MODEM_STATE_REASON_NONE); + } else { /* Clear reg tries; we're obviously registered by this point */ registration_cleanup (self, 0, 0); mm_port_set_connected (priv->data, TRUE); + mm_modem_set_state (info->modem, MM_MODEM_STATE_CONNECTED, MM_MODEM_STATE_REASON_NONE); } mm_callback_info_schedule (info); @@ -467,6 +487,8 @@ connect (MMModem *modem, MMCallbackInfo *info; char *command; + mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE); + info = mm_callback_info_new (modem, callback, user_data); command = g_strconcat ("DT", number, NULL); mm_serial_port_queue_command (priv->primary, command, 60, dial_done, info); @@ -488,6 +510,9 @@ disconnect_flash_done (MMSerialPort *port, } mm_port_set_connected (priv->data, FALSE); + + set_state_enabled (MM_GENERIC_CDMA (info->modem), MM_MODEM_STATE_REASON_NONE); + mm_callback_info_schedule (info); } @@ -1259,6 +1284,12 @@ reg_state_changed (MMModemCdma *self, #endif } +static void +set_simple_state (MMCallbackInfo *info, SimpleState state) +{ + mm_callback_info_set_data (info, "simple-connect-state", GUINT_TO_POINTER (state), NULL); +} + static void simple_state_machine (MMModem *modem, GError *error, gpointer user_data) { @@ -1275,11 +1306,11 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) switch (state) { case SIMPLE_STATE_BEGIN: - state = SIMPLE_STATE_ENABLE; + set_simple_state (info, SIMPLE_STATE_ENABLE); mm_modem_enable (modem, simple_state_machine, info); break; case SIMPLE_STATE_ENABLE: - state = SIMPLE_STATE_REGISTER; + set_simple_state (info, SIMPLE_STATE_REGISTER); mm_modem_cdma_get_registration_state (MM_MODEM_CDMA (modem), simple_reg_callback, info); @@ -1291,12 +1322,14 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) break; case SIMPLE_STATE_REGISTER: registration_cleanup (MM_GENERIC_CDMA (modem), 0, 0); - state = SIMPLE_STATE_CONNECT; + set_simple_state (info, SIMPLE_STATE_CONNECT); + mm_modem_set_state (modem, MM_MODEM_STATE_REGISTERED, MM_MODEM_STATE_REASON_NONE); + str = simple_get_string_property (info, "number", &info->error); mm_modem_connect (modem, str, simple_state_machine, info); break; case SIMPLE_STATE_CONNECT: - state = SIMPLE_STATE_DONE; + set_simple_state (info, SIMPLE_STATE_DONE); break; case SIMPLE_STATE_DONE: break; @@ -1306,8 +1339,7 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) if (info->error || state == SIMPLE_STATE_DONE) { registration_cleanup (MM_GENERIC_CDMA (modem), 0, 0); mm_callback_info_schedule (info); - } else - mm_callback_info_set_data (info, "simple-connect-state", GUINT_TO_POINTER (state), NULL); + } } static void diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 169fca8a..840a5ab0 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -159,6 +159,8 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *modem, mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (modem), priv->reg_status, priv->oper_code, priv->oper_name); } + + mm_generic_gsm_update_enabled_state (modem, MM_MODEM_STATE_REASON_NONE); } } @@ -209,6 +211,28 @@ mm_generic_gsm_check_pin (MMGenericGsm *modem, /*****************************************************************************/ +void +mm_generic_gsm_update_enabled_state (MMGenericGsm *self, MMModemStateReason reason) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + + switch (priv->reg_status) { + case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME: + case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING: + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING: + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_SEARCHING, reason); + break; + case MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE: + case MM_MODEM_GSM_NETWORK_REG_STATUS_DENIED: + case MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN: + default: + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_ENABLED, reason); + break; + } +} + static void check_valid (MMGenericGsm *self) { @@ -348,6 +372,10 @@ enable_done (MMSerialPort *port, * on the phone and let the subclass decided whether it wants to handle * errors or ignore them. */ + + mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (info->modem), + MM_MODEM_STATE_REASON_NONE); + mm_callback_info_schedule (info); } @@ -428,8 +456,13 @@ disable_done (MMSerialPort *port, GError *error, gpointer user_data) { + MMCallbackInfo *info = user_data; + mm_serial_port_close (port); - mm_callback_info_schedule ((MMCallbackInfo *) user_data); + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); + mm_callback_info_schedule (info); } static void diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index ac2ce365..9788bad7 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -85,4 +85,7 @@ MMPort *mm_generic_gsm_grab_port (MMGenericGsm *modem, MMPortType ptype, GError **error); +void mm_generic_gsm_update_enabled_state (MMGenericGsm *modem, + MMModemStateReason reason); + #endif /* MM_GENERIC_GSM_H */ diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index 1df965f8..8398f936 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -40,6 +40,7 @@ typedef struct { char *device; guint32 ip_method; gboolean valid; + MMModemState state; GHashTable *ports; } MMModemBasePrivate; @@ -181,6 +182,9 @@ set_property (GObject *object, guint prop_id, MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (object); switch (prop_id) { + case MM_MODEM_PROP_STATE: + priv->state = g_value_get_uint (value); + break; case MM_MODEM_PROP_DRIVER: /* Construct only */ priv->driver = g_value_dup_string (value); @@ -212,6 +216,9 @@ get_property (GObject *object, guint prop_id, MMModemBasePrivate *priv = MM_MODEM_BASE_GET_PRIVATE (object); switch (prop_id) { + case MM_MODEM_PROP_STATE: + g_value_set_uint (value, priv->state); + break; case MM_MODEM_PROP_MASTER_DEVICE: g_value_set_string (value, priv->device); break; @@ -265,6 +272,10 @@ mm_modem_base_class_init (MMModemBaseClass *klass) object_class->set_property = set_property; object_class->finalize = finalize; + g_object_class_override_property (object_class, + MM_MODEM_PROP_STATE, + MM_MODEM_STATE); + g_object_class_override_property (object_class, MM_MODEM_PROP_MASTER_DEVICE, MM_MODEM_MASTER_DEVICE); diff --git a/src/mm-modem.c b/src/mm-modem.c index ca2afbd7..11934a20 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -19,6 +19,7 @@ #include "mm-modem.h" #include "mm-errors.h" #include "mm-callback-info.h" +#include "mm-marshal.h" static void impl_modem_enable (MMModem *modem, gboolean enable, DBusGMethodInvocation *context); static void impl_modem_connect (MMModem *modem, const char *number, DBusGMethodInvocation *context); @@ -57,9 +58,18 @@ mm_modem_enable (MMModem *self, MMModemFn callback, gpointer user_data) { + MMModemState state; + g_return_if_fail (MM_IS_MODEM (self)); g_return_if_fail (callback != NULL); + state = mm_modem_get_state (self); + if (state >= MM_MODEM_STATE_ENABLED) { + /* Already enabled */ + callback (self, NULL, user_data); + return; + } + if (MM_MODEM_GET_INTERFACE (self)->enable) MM_MODEM_GET_INTERFACE (self)->enable (self, callback, user_data); else @@ -71,9 +81,18 @@ mm_modem_disable (MMModem *self, MMModemFn callback, gpointer user_data) { + MMModemState state; + g_return_if_fail (MM_IS_MODEM (self)); g_return_if_fail (callback != NULL); + state = mm_modem_get_state (self); + if (state <= MM_MODEM_STATE_DISABLED) { + /* Already disabled */ + callback (self, NULL, user_data); + return; + } + if (MM_MODEM_GET_INTERFACE (self)->disable) MM_MODEM_GET_INTERFACE (self)->disable (self, callback, user_data); else @@ -381,11 +400,37 @@ mm_modem_get_device (MMModem *self) return device; } +MMModemState +mm_modem_get_state (MMModem *self) +{ + MMModemState state = MM_MODEM_STATE_UNKNOWN; + + g_object_get (G_OBJECT (self), MM_MODEM_STATE, &state, NULL); + return state; +} + +void +mm_modem_set_state (MMModem *self, + MMModemState new_state, + MMModemStateReason reason) +{ + MMModemState old_state = MM_MODEM_STATE_UNKNOWN; + + g_object_get (G_OBJECT (self), MM_MODEM_STATE, &old_state, NULL); + + if (new_state != old_state) { + g_object_set (G_OBJECT (self), MM_MODEM_STATE, new_state, NULL); + g_signal_emit_by_name (G_OBJECT (self), "state-changed", new_state, old_state, reason); +g_message ("%s: state %d -> %d", __func__, old_state, new_state); + } +} + /*****************************************************************************/ static void mm_modem_init (gpointer g_iface) { + GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); static gboolean initialized = FALSE; if (initialized) @@ -450,6 +495,26 @@ mm_modem_init (gpointer g_iface) FALSE, G_PARAM_READABLE)); + g_object_interface_install_property + (g_iface, + g_param_spec_uint (MM_MODEM_STATE, + "State", + "State", + MM_MODEM_STATE_UNKNOWN, + MM_MODEM_STATE_LAST, + MM_MODEM_STATE_UNKNOWN, + G_PARAM_READWRITE)); + + /* Signals */ + g_signal_new ("state-changed", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MMModem, state_changed), + NULL, NULL, + mm_marshal_VOID__UINT_UINT_UINT, + G_TYPE_NONE, 3, + G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); + initialized = TRUE; } diff --git a/src/mm-modem.h b/src/mm-modem.h index 29f72b43..f771f3ad 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -21,6 +21,22 @@ #include "mm-port.h" +typedef enum { + MM_MODEM_STATE_UNKNOWN = 0, + MM_MODEM_STATE_DISABLED = 10, + MM_MODEM_STATE_ENABLED = 20, + MM_MODEM_STATE_SEARCHING = 30, + MM_MODEM_STATE_REGISTERED = 40, + MM_MODEM_STATE_CONNECTING = 50, + MM_MODEM_STATE_CONNECTED = 60, + + MM_MODEM_STATE_LAST = MM_MODEM_STATE_CONNECTED +} MMModemState; + +typedef enum { + MM_MODEM_STATE_REASON_NONE = 0 +} MMModemStateReason; + #define MM_TYPE_MODEM (mm_modem_get_type ()) #define MM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM, MMModem)) #define MM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM)) @@ -33,6 +49,7 @@ #define MM_MODEM_IP_METHOD "ip-method" #define MM_MODEM_VALID "valid" /* not exported */ #define MM_MODEM_PLUGIN "plugin" /* not exported */ +#define MM_MODEM_STATE "state" /* not exported */ #define MM_MODEM_TYPE_UNKNOWN 0 #define MM_MODEM_TYPE_GSM 1 @@ -52,6 +69,7 @@ typedef enum { MM_MODEM_PROP_IP_METHOD, MM_MODEM_PROP_VALID, /* Not exported */ MM_MODEM_PROP_PLUGIN, /* Not exported */ + MM_MODEM_PROP_STATE, /* Not exported */ } MMModemProp; typedef struct _MMModem MMModem; @@ -126,6 +144,12 @@ struct _MMModem { void (*get_info) (MMModem *self, MMModemInfoFn callback, gpointer user_data); + + /* Signals */ + void (*state_changed) (MMModem *self, + MMModemState new_state, + MMModemState old_state, + MMModemStateReason reason); }; GType mm_modem_get_type (void); @@ -174,5 +198,11 @@ gboolean mm_modem_get_valid (MMModem *self); char *mm_modem_get_device (MMModem *self); +MMModemState mm_modem_get_state (MMModem *self); + +void mm_modem_set_state (MMModem *self, + MMModemState new_state, + MMModemStateReason reason); + #endif /* MM_MODEM_H */ -- cgit v1.2.3-70-g09d2 From 500fb5f29aebb583f2f8c27fed11a5cd394c9958 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 23 Nov 2009 23:30:04 -0800 Subject: gsm: don't regress states on registration change if still registered --- src/mm-generic-gsm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index eb712aba..468cdfc2 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -219,7 +219,8 @@ mm_generic_gsm_update_enabled_state (MMGenericGsm *self, MMModemStateReason reas switch (priv->reg_status) { case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME: case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING: - mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); + if (mm_modem_get_state (MM_MODEM (self)) < MM_MODEM_STATE_CONNECTING) + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); break; case MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING: mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_SEARCHING, reason); -- cgit v1.2.3-70-g09d2 From d8ff5f74e008289ad512bb15f2c4cb1576752221 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 23 Nov 2009 23:30:30 -0800 Subject: core: state -> DISABLED when the modem becomes invalid --- src/mm-modem-base.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index 8398f936..a9386ff6 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -149,6 +149,13 @@ mm_modem_base_set_valid (MMModemBase *self, gboolean new_valid) if (priv->valid != new_valid) { priv->valid = new_valid; g_object_notify (G_OBJECT (self), MM_MODEM_VALID); + + if (!new_valid) { + /* If no longer valid, modem must be disabled */ + mm_modem_set_state (MM_MODEM (self), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); + } } } -- cgit v1.2.3-70-g09d2 From 3350a3aeea6ceeb959d7622b62f53ab86bb2ab48 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 12:57:18 -0800 Subject: cdma: set correct modem state on connect failure --- src/mm-generic-cdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index be95116c..b94be276 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -466,7 +466,7 @@ dial_done (MMSerialPort *port, if (error) { info->error = g_error_copy (error); - mm_modem_set_state (info->modem, MM_MODEM_STATE_REGISTERED, MM_MODEM_STATE_REASON_NONE); + set_state_enabled (MM_GENERIC_CDMA (info->modem), MM_MODEM_STATE_REASON_NONE); } else { /* Clear reg tries; we're obviously registered by this point */ registration_cleanup (self, 0, 0); -- cgit v1.2.3-70-g09d2 From 231d2ca90b6d197d4594407fc3e6b6ee2c7fb850 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 12:57:39 -0800 Subject: core: schedule enabled/disabled callbacks to avoid infinite recursion --- src/mm-modem.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mm-modem.c b/src/mm-modem.c index 11934a20..72efe0b9 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -65,8 +65,11 @@ mm_modem_enable (MMModem *self, state = mm_modem_get_state (self); if (state >= MM_MODEM_STATE_ENABLED) { + MMCallbackInfo *info; + /* Already enabled */ - callback (self, NULL, user_data); + info = mm_callback_info_new (self, callback, user_data); + mm_callback_info_schedule (info); return; } @@ -88,8 +91,11 @@ mm_modem_disable (MMModem *self, state = mm_modem_get_state (self); if (state <= MM_MODEM_STATE_DISABLED) { + MMCallbackInfo *info; + /* Already disabled */ - callback (self, NULL, user_data); + info = mm_callback_info_new (self, callback, user_data); + mm_callback_info_schedule (info); return; } -- cgit v1.2.3-70-g09d2 From d269a9a278687c82e5a6ec3f1bba0f91161a05c7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 12:58:57 -0800 Subject: core: state should always be reset to DISABLED when validity changes When the modem becomes valid, it should initially be in disabled state, and when it becomes invalid, it should also go to disabled. --- src/mm-modem-base.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index a9386ff6..174d9d25 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -150,12 +150,12 @@ mm_modem_base_set_valid (MMModemBase *self, gboolean new_valid) priv->valid = new_valid; g_object_notify (G_OBJECT (self), MM_MODEM_VALID); - if (!new_valid) { - /* If no longer valid, modem must be disabled */ - mm_modem_set_state (MM_MODEM (self), - MM_MODEM_STATE_DISABLED, - MM_MODEM_STATE_REASON_NONE); - } + /* Modem starts off in disabled state, and jumps to disabled when + * it's no longer valid. + */ + mm_modem_set_state (MM_MODEM (self), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); } } -- cgit v1.2.3-70-g09d2 From 015da49d06fd7f19c444ba7b9e98baeb31c72c4d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 14:19:25 -0800 Subject: core: set modem state before potentially destroying the modem --- src/mm-modem-base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mm-modem-base.c b/src/mm-modem-base.c index 174d9d25..d50d7517 100644 --- a/src/mm-modem-base.c +++ b/src/mm-modem-base.c @@ -148,7 +148,6 @@ mm_modem_base_set_valid (MMModemBase *self, gboolean new_valid) if (priv->valid != new_valid) { priv->valid = new_valid; - g_object_notify (G_OBJECT (self), MM_MODEM_VALID); /* Modem starts off in disabled state, and jumps to disabled when * it's no longer valid. @@ -156,6 +155,8 @@ mm_modem_base_set_valid (MMModemBase *self, gboolean new_valid) mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE); + + g_object_notify (G_OBJECT (self), MM_MODEM_VALID); } } -- cgit v1.2.3-70-g09d2 From 0f19bbff0f7b29c5922307526c3a7770fe8718e1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 15:37:37 -0800 Subject: core: add a few more interim modem states --- src/mm-modem.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/mm-modem.h b/src/mm-modem.h index f771f3ad..0af1e534 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -23,12 +23,15 @@ typedef enum { MM_MODEM_STATE_UNKNOWN = 0, - MM_MODEM_STATE_DISABLED = 10, - MM_MODEM_STATE_ENABLED = 20, - MM_MODEM_STATE_SEARCHING = 30, - MM_MODEM_STATE_REGISTERED = 40, - MM_MODEM_STATE_CONNECTING = 50, - MM_MODEM_STATE_CONNECTED = 60, + MM_MODEM_STATE_DISABLING = 10, + MM_MODEM_STATE_DISABLED = 20, + MM_MODEM_STATE_ENABLING = 30, + MM_MODEM_STATE_ENABLED = 40, + MM_MODEM_STATE_SEARCHING = 50, + MM_MODEM_STATE_REGISTERED = 60, + MM_MODEM_STATE_DISCONNECTING = 70, + MM_MODEM_STATE_CONNECTING = 80, + MM_MODEM_STATE_CONNECTED = 90, MM_MODEM_STATE_LAST = MM_MODEM_STATE_CONNECTED } MMModemState; -- cgit v1.2.3-70-g09d2 From e9964231e931f283ecf232f23f45282a22e3471a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 15:38:11 -0800 Subject: core: use modem states to protect against double operations --- src/mm-modem.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/mm-modem.c b/src/mm-modem.c index 72efe0b9..10052fa4 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -67,8 +67,16 @@ mm_modem_enable (MMModem *self, if (state >= MM_MODEM_STATE_ENABLED) { MMCallbackInfo *info; - /* Already enabled */ info = mm_callback_info_new (self, callback, user_data); + + if (state == MM_MODEM_STATE_ENABLING) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_IN_PROGRESS, + "The device is already being enabled."); + } else { + /* Already enabled */ + } + mm_callback_info_schedule (info); return; } @@ -79,6 +87,42 @@ mm_modem_enable (MMModem *self, async_op_not_supported (self, callback, user_data); } +static void +finish_disable (MMModem *self, + MMModemFn callback, + gpointer user_data) +{ + + if (MM_MODEM_GET_INTERFACE (self)->disable) + MM_MODEM_GET_INTERFACE (self)->disable (self, callback, user_data); + else + async_op_not_supported (self, callback, user_data); +} + +typedef struct { + MMModemFn callback; + gpointer user_data; +} DisableDisconnectInfo; + +static void +disable_disconnect_done (MMModem *self, + GError *error, + gpointer user_data) +{ + DisableDisconnectInfo *cb_data = user_data; + + /* ignore errors */ + if (error) { + g_warning ("%s: (%s): error disconnecting the modem while disabling: (%d) %s", + __func__, + mm_modem_get_device (self), + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + } + finish_disable (self, cb_data->callback, cb_data->user_data); + g_free (cb_data); +} + void mm_modem_disable (MMModem *self, MMModemFn callback, @@ -93,16 +137,30 @@ mm_modem_disable (MMModem *self, if (state <= MM_MODEM_STATE_DISABLED) { MMCallbackInfo *info; - /* Already disabled */ info = mm_callback_info_new (self, callback, user_data); + + if (state == MM_MODEM_STATE_DISABLING) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_IN_PROGRESS, + "The device is already being disabled."); + } else { + /* Already disabled */ + } + mm_callback_info_schedule (info); return; } - if (MM_MODEM_GET_INTERFACE (self)->disable) - MM_MODEM_GET_INTERFACE (self)->disable (self, callback, user_data); - else - async_op_not_supported (self, callback, user_data); + /* If the modem is connected, disconnect it */ + if (state >= MM_MODEM_STATE_CONNECTING) { + DisableDisconnectInfo *cb_data; + + cb_data = g_malloc0 (sizeof (DisableDisconnectInfo)); + cb_data->callback = callback; + cb_data->user_data = user_data; + mm_modem_disconnect (self, disable_disconnect_done, cb_data); + } else + finish_disable (self, callback, user_data); } static void @@ -122,10 +180,30 @@ mm_modem_connect (MMModem *self, MMModemFn callback, gpointer user_data) { + MMModemState state; + g_return_if_fail (MM_IS_MODEM (self)); g_return_if_fail (callback != NULL); g_return_if_fail (number != NULL); + state = mm_modem_get_state (self); + if (state >= MM_MODEM_STATE_CONNECTING) { + MMCallbackInfo *info; + + /* Already connecting */ + info = mm_callback_info_new (self, callback, user_data); + if (state == MM_MODEM_STATE_CONNECTING) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_IN_PROGRESS, + "The device is already being connected."); + } else { + /* already connected */ + } + + mm_callback_info_schedule (info); + return; + } + if (MM_MODEM_GET_INTERFACE (self)->connect) MM_MODEM_GET_INTERFACE (self)->connect (self, number, callback, user_data); else @@ -236,9 +314,30 @@ mm_modem_disconnect (MMModem *self, MMModemFn callback, gpointer user_data) { + MMModemState state; + g_return_if_fail (MM_IS_MODEM (self)); g_return_if_fail (callback != NULL); + state = mm_modem_get_state (self); + if (state <= MM_MODEM_STATE_DISCONNECTING) { + MMCallbackInfo *info; + + /* Already connecting */ + info = mm_callback_info_new (self, callback, user_data); + if (state == MM_MODEM_STATE_DISCONNECTING) { + info->error = g_error_new_literal (MM_MODEM_ERROR, + MM_MODEM_ERROR_OPERATION_IN_PROGRESS, + "The device is already being disconnected."); + } else { + /* already disconnected */ + } + + mm_callback_info_schedule (info); + return; + } + + if (MM_MODEM_GET_INTERFACE (self)->disconnect) MM_MODEM_GET_INTERFACE (self)->disconnect (self, callback, user_data); else -- cgit v1.2.3-70-g09d2 From a295afdd2ddd99dea8435d95a72f02d0ade2b2b7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 15:39:06 -0800 Subject: cdma: update for new modem states and make connect actually work --- src/mm-generic-cdma.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index b94be276..e948e32a 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -293,15 +293,20 @@ mm_generic_cdma_evdo_get_registration_state_sync (MMGenericCdma *self) /*****************************************************************************/ static void -set_state_enabled (MMGenericCdma *self, MMModemStateReason reason) +update_enabled_state (MMGenericCdma *self, + gboolean just_disconnected, + MMModemStateReason reason) { MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self); - if ( priv->cdma_1x_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN - || priv->evdo_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) - mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); - else - mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_ENABLED, reason); + if ( just_disconnected + || (mm_modem_get_state (MM_MODEM (self)) < MM_MODEM_STATE_DISCONNECTING)) { + if ( priv->cdma_1x_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN + || priv->evdo_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); + else + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_ENABLED, reason); + } } static void @@ -350,7 +355,7 @@ enable_error_reporting_done (MMSerialPort *port, g_assert (info->error); } - set_state_enabled (MM_GENERIC_CDMA (info->modem), MM_MODEM_STATE_REASON_NONE); + update_enabled_state (MM_GENERIC_CDMA (info->modem), FALSE, MM_MODEM_STATE_REASON_NONE); /* Ignore errors, see FIXME in init_done() */ mm_callback_info_schedule (info); @@ -418,6 +423,7 @@ disable_flash_done (MMSerialPort *port, gpointer user_data) { MMCallbackInfo *info = user_data; + MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); if (error) info->error = g_error_copy (error); @@ -426,6 +432,9 @@ disable_flash_done (MMSerialPort *port, mm_modem_set_state (MM_MODEM (info->modem), MM_MODEM_STATE_DISABLED, MM_MODEM_STATE_REASON_NONE); + + priv->cdma_1x_reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + priv->evdo_reg_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; } mm_callback_info_schedule (info); @@ -466,7 +475,7 @@ dial_done (MMSerialPort *port, if (error) { info->error = g_error_copy (error); - set_state_enabled (MM_GENERIC_CDMA (info->modem), MM_MODEM_STATE_REASON_NONE); + update_enabled_state (MM_GENERIC_CDMA (info->modem), FALSE, MM_MODEM_STATE_REASON_NONE); } else { /* Clear reg tries; we're obviously registered by this point */ registration_cleanup (self, 0, 0); @@ -511,8 +520,7 @@ disconnect_flash_done (MMSerialPort *port, } mm_port_set_connected (priv->data, FALSE); - - set_state_enabled (MM_GENERIC_CDMA (info->modem), MM_MODEM_STATE_REASON_NONE); + update_enabled_state (MM_GENERIC_CDMA (info->modem), TRUE, MM_MODEM_STATE_REASON_NONE); mm_callback_info_schedule (info); } @@ -527,6 +535,8 @@ disconnect (MMModem *modem, g_return_if_fail (priv->primary != NULL); + mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); + info = mm_callback_info_new (modem, callback, user_data); mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info); } @@ -1307,10 +1317,11 @@ reg_state_changed (MMModemCdma *self, #endif } -static void +static SimpleState set_simple_state (MMCallbackInfo *info, SimpleState state) { mm_callback_info_set_data (info, "simple-connect-state", GUINT_TO_POINTER (state), NULL); + return state; } static void @@ -1329,11 +1340,11 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) switch (state) { case SIMPLE_STATE_BEGIN: - set_simple_state (info, SIMPLE_STATE_ENABLE); + state = set_simple_state (info, SIMPLE_STATE_ENABLE); mm_modem_enable (modem, simple_state_machine, info); break; case SIMPLE_STATE_ENABLE: - set_simple_state (info, SIMPLE_STATE_REGISTER); + state = set_simple_state (info, SIMPLE_STATE_REGISTER); mm_modem_cdma_get_registration_state (MM_MODEM_CDMA (modem), simple_reg_callback, info); @@ -1345,14 +1356,14 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data) break; case SIMPLE_STATE_REGISTER: registration_cleanup (MM_GENERIC_CDMA (modem), 0, 0); - set_simple_state (info, SIMPLE_STATE_CONNECT); + state = set_simple_state (info, SIMPLE_STATE_CONNECT); mm_modem_set_state (modem, MM_MODEM_STATE_REGISTERED, MM_MODEM_STATE_REASON_NONE); str = simple_get_string_property (info, "number", &info->error); mm_modem_connect (modem, str, simple_state_machine, info); break; case SIMPLE_STATE_CONNECT: - set_simple_state (info, SIMPLE_STATE_DONE); + state = set_simple_state (info, SIMPLE_STATE_DONE); break; case SIMPLE_STATE_DONE: break; -- cgit v1.2.3-70-g09d2 From 02c7db7fcfc7af226c2677793685528928d6f7f5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 15:58:11 -0800 Subject: cdma: handle interim enabling/disabling states better Have to fall back to the previous state if the enable/disable operation fails since we cannot assume anything about the new modem state when a failure occurs. --- src/mm-generic-cdma.c | 36 ++++++++++++++++++++++++++++++++++-- src/mm-generic-cdma.h | 2 ++ 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index e948e32a..e29b1e9a 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -370,6 +370,10 @@ init_done (MMSerialPort *port, MMCallbackInfo *info = (MMCallbackInfo *) user_data; if (error) { + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); + info->error = g_error_copy (error); mm_callback_info_schedule (info); } else { @@ -388,6 +392,10 @@ flash_done (MMSerialPort *port, GError *error, gpointer user_data) MMCallbackInfo *info = (MMCallbackInfo *) user_data; if (error) { + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); + /* Flash failed for some reason */ info->error = g_error_copy (error); mm_callback_info_schedule (info); @@ -414,6 +422,10 @@ enable (MMModem *modem, return; } + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_ENABLING, + MM_MODEM_STATE_REASON_NONE); + mm_serial_port_flash (priv->primary, 100, flash_done, info); } @@ -425,9 +437,17 @@ disable_flash_done (MMSerialPort *port, MMCallbackInfo *info = user_data; MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); - if (error) + if (error) { + MMModemState prev_state; + + /* Reset old state since the operation failed */ + prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG)); + mm_modem_set_state (MM_MODEM (info->modem), + prev_state, + MM_MODEM_STATE_REASON_NONE); + info->error = g_error_copy (error); - else { + } else { mm_serial_port_close (port); mm_modem_set_state (MM_MODEM (info->modem), MM_MODEM_STATE_DISABLED, @@ -448,15 +468,27 @@ disable (MMModem *modem, MMGenericCdma *self = MM_GENERIC_CDMA (modem); MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self); MMCallbackInfo *info; + MMModemState state; /* Tear down any ongoing registration */ registration_cleanup (self, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL); info = mm_callback_info_new (modem, callback, user_data); + /* Cache the previous state so we can reset it if the operation fails */ + state = mm_modem_get_state (modem); + mm_callback_info_set_data (info, + MM_GENERIC_GSM_PREV_STATE_TAG, + GUINT_TO_POINTER (state), + NULL); + if (priv->secondary) mm_serial_port_close (priv->secondary); + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLING, + MM_MODEM_STATE_REASON_NONE); + if (mm_port_get_connected (MM_PORT (priv->primary))) mm_serial_port_flash (priv->primary, 1000, disable_flash_done, info); else diff --git a/src/mm-generic-cdma.h b/src/mm-generic-cdma.h index 8d85cb38..f870c35e 100644 --- a/src/mm-generic-cdma.h +++ b/src/mm-generic-cdma.h @@ -55,6 +55,8 @@ MMModem *mm_generic_cdma_new (const char *device, /* Private, for subclasses */ +#define MM_GENERIC_GSM_PREV_STATE_TAG "prev-state" + MMPort * mm_generic_cdma_grab_port (MMGenericCdma *self, const char *subsys, const char *name, -- cgit v1.2.3-70-g09d2 From d438012f63dac7e4819f09b520658abb42234082 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 16:01:20 -0800 Subject: cdma: s/GSM/CDMA Oops. --- src/mm-generic-cdma.c | 4 ++-- src/mm-generic-cdma.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index e29b1e9a..d57ae687 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -441,7 +441,7 @@ disable_flash_done (MMSerialPort *port, MMModemState prev_state; /* Reset old state since the operation failed */ - prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG)); + prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_CDMA_PREV_STATE_TAG)); mm_modem_set_state (MM_MODEM (info->modem), prev_state, MM_MODEM_STATE_REASON_NONE); @@ -478,7 +478,7 @@ disable (MMModem *modem, /* Cache the previous state so we can reset it if the operation fails */ state = mm_modem_get_state (modem); mm_callback_info_set_data (info, - MM_GENERIC_GSM_PREV_STATE_TAG, + MM_GENERIC_CDMA_PREV_STATE_TAG, GUINT_TO_POINTER (state), NULL); diff --git a/src/mm-generic-cdma.h b/src/mm-generic-cdma.h index f870c35e..e84182ad 100644 --- a/src/mm-generic-cdma.h +++ b/src/mm-generic-cdma.h @@ -55,7 +55,7 @@ MMModem *mm_generic_cdma_new (const char *device, /* Private, for subclasses */ -#define MM_GENERIC_GSM_PREV_STATE_TAG "prev-state" +#define MM_GENERIC_CDMA_PREV_STATE_TAG "prev-state" MMPort * mm_generic_cdma_grab_port (MMGenericCdma *self, const char *subsys, -- cgit v1.2.3-70-g09d2 From c169396c1bbb1238e3c405bb9c53eb12712acb9b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 16:19:27 -0800 Subject: cdma: correctly handle state update after disconnection We only want to ignore connected/connecting/disconnecting states and update the state based on registration for unsolicited registration changes. Basically, when disconnecting, the modem will be in DISCONNECTING state, but after the disconnect has finished we want to update the modem's state based on the current registration status. But the previous check for >= DISCONNECTING would prevent that from happening, so we need a slightly more specific check in update_enabled_state(). --- src/mm-generic-cdma.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index d57ae687..e446b3ca 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -36,6 +36,10 @@ static void simple_reg_callback (MMModemCdma *modem, static void simple_state_machine (MMModem *modem, GError *error, gpointer user_data); +static void update_enabled_state (MMGenericCdma *self, + gboolean stay_connected, + MMModemStateReason reason); + static void modem_init (MMModem *modem_class); static void modem_cdma_init (MMModemCdma *cdma_class); static void modem_simple_init (MMModemSimple *class); @@ -240,6 +244,7 @@ mm_generic_cdma_set_1x_registration_state (MMGenericCdma *self, if (priv->cdma_1x_reg_state != new_state) { priv->cdma_1x_reg_state = new_state; + update_enabled_state (self, TRUE, MM_MODEM_STATE_REASON_NONE); mm_modem_cdma_emit_registration_state_changed (MM_MODEM_CDMA (self), priv->cdma_1x_reg_state, priv->evdo_reg_state); @@ -266,6 +271,7 @@ mm_generic_cdma_set_evdo_registration_state (MMGenericCdma *self, || (new_state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN)) { priv->evdo_reg_state = new_state; + update_enabled_state (self, TRUE, MM_MODEM_STATE_REASON_NONE); mm_modem_cdma_emit_registration_state_changed (MM_MODEM_CDMA (self), priv->cdma_1x_reg_state, priv->evdo_reg_state); @@ -294,19 +300,22 @@ mm_generic_cdma_evdo_get_registration_state_sync (MMGenericCdma *self) static void update_enabled_state (MMGenericCdma *self, - gboolean just_disconnected, + gboolean stay_connected, MMModemStateReason reason) { MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self); - if ( just_disconnected - || (mm_modem_get_state (MM_MODEM (self)) < MM_MODEM_STATE_DISCONNECTING)) { - if ( priv->cdma_1x_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN - || priv->evdo_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) - mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); - else - mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_ENABLED, reason); - } + /* While connected we don't want registration status changes to change + * the modem's state away from CONNECTED. + */ + if (stay_connected && (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_DISCONNECTING)) + return; + + if ( priv->cdma_1x_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN + || priv->evdo_reg_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); + else + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_ENABLED, reason); } static void @@ -552,7 +561,7 @@ disconnect_flash_done (MMSerialPort *port, } mm_port_set_connected (priv->data, FALSE); - update_enabled_state (MM_GENERIC_CDMA (info->modem), TRUE, MM_MODEM_STATE_REASON_NONE); + update_enabled_state (MM_GENERIC_CDMA (info->modem), FALSE, MM_MODEM_STATE_REASON_NONE); mm_callback_info_schedule (info); } -- cgit v1.2.3-70-g09d2 From bf13b4698f8d94119f42e5cdf5df6a3dbfe354fd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 16:33:44 -0800 Subject: cdma: reset previous state if disconnect failed --- src/mm-generic-cdma.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c index e446b3ca..0e99ec77 100644 --- a/src/mm-generic-cdma.c +++ b/src/mm-generic-cdma.c @@ -555,6 +555,14 @@ disconnect_flash_done (MMSerialPort *port, MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (info->modem); if (error) { + MMModemState prev_state; + + /* Reset old state since the operation failed */ + prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_CDMA_PREV_STATE_TAG)); + mm_modem_set_state (MM_MODEM (info->modem), + prev_state, + MM_MODEM_STATE_REASON_NONE); + info->error = g_error_copy (error); mm_callback_info_schedule (info); return; @@ -573,12 +581,20 @@ disconnect (MMModem *modem, { MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem); MMCallbackInfo *info; + MMModemState state; g_return_if_fail (priv->primary != NULL); - mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); - info = mm_callback_info_new (modem, callback, user_data); + + /* Cache the previous state so we can reset it if the operation fails */ + state = mm_modem_get_state (modem); + mm_callback_info_set_data (info, + MM_GENERIC_CDMA_PREV_STATE_TAG, + GUINT_TO_POINTER (state), + NULL); + + mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info); } -- cgit v1.2.3-70-g09d2 From 7f1951fec867de5553b130c21df4eb5f447889a1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 16:44:07 -0800 Subject: core: fix ordering of DISABLING and DISABLED states --- src/mm-modem.c | 2 +- src/mm-modem.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mm-modem.c b/src/mm-modem.c index 10052fa4..b49c7070 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -134,7 +134,7 @@ mm_modem_disable (MMModem *self, g_return_if_fail (callback != NULL); state = mm_modem_get_state (self); - if (state <= MM_MODEM_STATE_DISABLED) { + if (state <= MM_MODEM_STATE_DISABLING) { MMCallbackInfo *info; info = mm_callback_info_new (self, callback, user_data); diff --git a/src/mm-modem.h b/src/mm-modem.h index 0af1e534..cf16f190 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -23,8 +23,8 @@ typedef enum { MM_MODEM_STATE_UNKNOWN = 0, - MM_MODEM_STATE_DISABLING = 10, - MM_MODEM_STATE_DISABLED = 20, + MM_MODEM_STATE_DISABLED = 10, + MM_MODEM_STATE_DISABLING = 20, MM_MODEM_STATE_ENABLING = 30, MM_MODEM_STATE_ENABLED = 40, MM_MODEM_STATE_SEARCHING = 50, -- cgit v1.2.3-70-g09d2 From bb6f997fb8b6acad6af62cae081b55e6d94cc1b6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 Dec 2009 16:46:23 -0800 Subject: gsm: update for new states and state flow fixes --- plugins/mm-modem-mbm.c | 1 + src/mm-generic-gsm.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++---- src/mm-generic-gsm.h | 10 +++++++ 3 files changed, 80 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c index eee85bda..f04d1287 100644 --- a/plugins/mm-modem-mbm.c +++ b/plugins/mm-modem-mbm.c @@ -327,6 +327,7 @@ mbm_enable_done (MMSerialPort *port, else { /* We're enabled; update our state */ mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (info->modem), + FALSE, MM_MODEM_STATE_REASON_NONE); } mm_callback_info_schedule (info); diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index f285672b..f9f87657 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -160,7 +160,7 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *modem, priv->oper_code, priv->oper_name); } - mm_generic_gsm_update_enabled_state (modem, MM_MODEM_STATE_REASON_NONE); + mm_generic_gsm_update_enabled_state (modem, TRUE, MM_MODEM_STATE_REASON_NONE); } } @@ -246,15 +246,22 @@ mm_generic_gsm_check_pin (MMGenericGsm *modem, /*****************************************************************************/ void -mm_generic_gsm_update_enabled_state (MMGenericGsm *self, MMModemStateReason reason) +mm_generic_gsm_update_enabled_state (MMGenericGsm *self, + gboolean stay_connected, + MMModemStateReason reason) { MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + /* While connected we don't want registration status changes to change + * the modem's state away from CONNECTED. + */ + if (stay_connected && (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_DISCONNECTING)) + return; + switch (priv->reg_status) { case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME: case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING: - if (mm_modem_get_state (MM_MODEM (self)) < MM_MODEM_STATE_CONNECTING) - mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); + mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_REGISTERED, reason); break; case MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING: mm_modem_set_state (MM_MODEM (self), MM_MODEM_STATE_SEARCHING, reason); @@ -409,6 +416,7 @@ enable_done (MMSerialPort *port, */ mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (info->modem), + FALSE, MM_MODEM_STATE_REASON_NONE); mm_callback_info_schedule (info); @@ -424,6 +432,10 @@ init_done (MMSerialPort *port, char *cmd = NULL; if (error) { + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); + info->error = g_error_copy (error); mm_callback_info_schedule (info); } else { @@ -457,6 +469,10 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data) char *cmd = NULL; if (error) { + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); + info->error = g_error_copy (error); mm_callback_info_schedule (info); return; @@ -486,6 +502,10 @@ enable (MMModem *modem, return; } + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_ENABLING, + MM_MODEM_STATE_REASON_NONE); + mm_serial_port_flash (priv->primary, 100, enable_flash_done, info); } @@ -513,6 +533,14 @@ disable_flash_done (MMSerialPort *port, char *cmd = NULL; if (error) { + MMModemState prev_state; + + /* Reset old state since the operation failed */ + prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG)); + mm_modem_set_state (MM_MODEM (info->modem), + prev_state, + MM_MODEM_STATE_REASON_NONE); + info->error = g_error_copy (error); mm_callback_info_schedule (info); return; @@ -533,6 +561,7 @@ disable (MMModem *modem, { MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); MMCallbackInfo *info; + MMModemState state; /* First, reset the previously used CID and clean up registration */ mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); @@ -540,6 +569,17 @@ disable (MMModem *modem, info = mm_callback_info_new (modem, callback, user_data); + /* Cache the previous state so we can reset it if the operation fails */ + state = mm_modem_get_state (modem); + mm_callback_info_set_data (info, + MM_GENERIC_GSM_PREV_STATE_TAG, + GUINT_TO_POINTER (state), + NULL); + + mm_modem_set_state (MM_MODEM (info->modem), + MM_MODEM_STATE_DISABLING, + MM_MODEM_STATE_REASON_NONE); + if (mm_port_get_connected (MM_PORT (priv->primary))) mm_serial_port_flash (priv->primary, 1000, disable_flash_done, info); else @@ -1163,6 +1203,7 @@ connect_report_done (MMSerialPort *port, info->error->message = g_strdup (response->str + 7); /* skip the "+CEER: " */ } + mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (info->modem), FALSE, MM_MODEM_STATE_REASON_NONE); mm_callback_info_schedule (info); } @@ -1183,6 +1224,7 @@ connect_done (MMSerialPort *port, } else { /* Done */ mm_port_set_connected (priv->data, TRUE); + mm_modem_set_state (info->modem, MM_MODEM_STATE_CONNECTED, MM_MODEM_STATE_REASON_NONE); mm_callback_info_schedule (info); } } @@ -1200,6 +1242,8 @@ connect (MMModem *modem, info = mm_callback_info_new (modem, callback, user_data); + mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE); + if (cid > 0) { GString *str; @@ -1224,15 +1268,25 @@ disconnect_flash_done (MMSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + MMGenericGsm *self = MM_GENERIC_GSM (info->modem); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); if (error) { + MMModemState prev_state; + + /* Reset old state since the operation failed */ + prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG)); + mm_modem_set_state (MM_MODEM (info->modem), + prev_state, + MM_MODEM_STATE_REASON_NONE); + info->error = g_error_copy (error); mm_callback_info_schedule (info); return; } mm_port_set_connected (priv->data, FALSE); + mm_generic_gsm_update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE); mm_callback_info_schedule (info); } @@ -1243,11 +1297,21 @@ disconnect (MMModem *modem, { MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); MMCallbackInfo *info; + MMModemState state; /* First, reset the previously used CID */ mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); info = mm_callback_info_new (modem, callback, user_data); + + /* Cache the previous state so we can reset it if the operation fails */ + state = mm_modem_get_state (modem); + mm_callback_info_set_data (info, + MM_GENERIC_GSM_PREV_STATE_TAG, + GUINT_TO_POINTER (state), + NULL); + + mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info); } diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index af71b17b..ea60ffbf 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -60,6 +60,10 @@ MMModem *mm_generic_gsm_new (const char *device, const char *driver, const char *plugin); +/* Private, for subclasses */ + +#define MM_GENERIC_GSM_PREV_STATE_TAG "prev-state" + void mm_generic_gsm_set_unsolicited_registration (MMGenericGsm *modem, gboolean enabled); @@ -85,7 +89,13 @@ MMPort *mm_generic_gsm_grab_port (MMGenericGsm *modem, MMPortType ptype, GError **error); +/* stay_connected should be TRUE for unsolicited registration updates, otherwise + * the registration update will clear connected/connecting/disconnecting state + * which we don't want. stay_connected should be FALSE for other cases like + * updating the state after disconnecting, or after a connect error occurs. + */ void mm_generic_gsm_update_enabled_state (MMGenericGsm *modem, + gboolean stay_connected, MMModemStateReason reason); #endif /* MM_GENERIC_GSM_H */ -- cgit v1.2.3-70-g09d2 From 5bdabaabec5ecb64986036bf783196eeee3756e7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 2 Dec 2009 14:43:09 -0800 Subject: gsm: implement enable/connecting/disconnecting state handling And consolidate generic port enable code in one place since pretty much every modem needs that. --- plugins/mm-modem-hso.c | 33 ++++---- plugins/mm-modem-mbm.c | 165 +++++++++++++++++++-------------------- plugins/mm-modem-novatel-gsm.c | 67 +++++++--------- plugins/mm-modem-option.c | 21 +++-- plugins/mm-modem-sierra-gsm.c | 25 +++--- plugins/mm-modem-zte.c | 58 +++++--------- src/mm-generic-gsm.c | 170 ++++++++++++++++++++++++++++------------- src/mm-generic-gsm.h | 28 +++++++ 8 files changed, 309 insertions(+), 258 deletions(-) (limited to 'src') diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c index a2e3b408..f1295e24 100644 --- a/plugins/mm-modem-hso.c +++ b/plugins/mm-modem-hso.c @@ -288,33 +288,30 @@ mm_hso_modem_authenticate (MMModemHso *self, /*****************************************************************************/ static void -generic_done (MMModem *modem, GError *error, gpointer user_data) +enable_done (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) - info->error = g_error_copy (error); - mm_callback_info_schedule (info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info); } static void parent_enable_done (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMGenericGsm *self = MM_GENERIC_GSM (modem); if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - /* HSO needs manual PIN checking */ - mm_generic_gsm_check_pin (MM_GENERIC_GSM (modem), generic_done, info); + mm_generic_gsm_enable_complete (self, error, info); + return; } + + /* HSO needs manual PIN checking */ + mm_generic_gsm_check_pin (self, enable_done, info); } static void -enable (MMModem *modem, - MMModemFn callback, - gpointer user_data) +enable (MMModem *modem, MMModemFn callback, gpointer user_data) { MMModem *parent_modem_iface; MMCallbackInfo *info; @@ -324,6 +321,16 @@ enable (MMModem *modem, parent_modem_iface->enable (info->modem, parent_enable_done, info); } +static void +parent_disable_done (MMModem *modem, GError *error, gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) + info->error = g_error_copy (error); + mm_callback_info_schedule (info); +} + static void disable_done (MMModem *modem, GError *error, @@ -334,7 +341,7 @@ disable_done (MMModem *modem, /* Do the normal disable stuff */ parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem)); - parent_modem_iface->disable (info->modem, generic_done, info); + parent_modem_iface->disable (info->modem, parent_disable_done, info); } static void diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c index f04d1287..386409ab 100644 --- a/plugins/mm-modem-mbm.c +++ b/plugins/mm-modem-mbm.c @@ -63,7 +63,7 @@ typedef struct { guint reg_id; gboolean have_emrdy; char *network_device; - MMCallbackInfo *do_connect_done_info; + MMCallbackInfo *pending_connect_info; int account_index; int network_mode; const char *username; @@ -322,15 +322,7 @@ mbm_enable_done (MMSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) - info->error = g_error_copy (error); - else { - /* We're enabled; update our state */ - mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (info->modem), - FALSE, - MM_MODEM_STATE_REASON_NONE); - } - mm_callback_info_schedule (info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); } static void @@ -345,6 +337,7 @@ mbm_enap0_done (MMSerialPort *port, if (!priv->network_mode) priv->network_mode = MBM_NETWORK_MODE_ANY; + command = g_strdup_printf ("+CFUN=%d", priv->network_mode); mm_serial_port_queue_command (port, command, 3, mbm_enable_done, info); g_free (command); @@ -360,19 +353,20 @@ mbm_init_done (MMSerialPort *port, MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem); if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - if (!priv->network_mode) - priv->network_mode = MBM_NETWORK_MODE_ANY; - mm_serial_port_queue_command (port, "*ENAP=0", 3, mbm_enap0_done, info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); + return; } + + if (!priv->network_mode) + priv->network_mode = MBM_NETWORK_MODE_ANY; + + mm_serial_port_queue_command (port, "*ENAP=0", 3, mbm_enap0_done, info); } static void -do_init (MMSerialPort *port, gpointer user_data) +do_init (MMSerialPort *port, MMCallbackInfo *info) { - mm_serial_port_queue_command (port, "&F E0 V1 X4 &C1 +CMEE=1", 3, mbm_init_done, user_data); + mm_serial_port_queue_command (port, "&F E0 V1 X4 &C1 +CMEE=1", 3, mbm_init_done, info); } static void @@ -391,31 +385,21 @@ mbm_emrdy_done (MMSerialPort *port, } else priv->have_emrdy = TRUE; - do_init (port, user_data); + do_init (port, info); } static void -enable (MMModem *modem, - MMModemFn callback, - gpointer user_data) +do_enable (MMGenericGsm *self, MMModemFn callback, gpointer user_data) { - MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (modem); + MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self); MMCallbackInfo *info; MMSerialPort *primary; - mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); - - info = mm_callback_info_new (modem, callback, user_data); + info = mm_callback_info_new (MM_MODEM (self), callback, user_data); - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); + primary = mm_generic_gsm_get_port (self, MM_PORT_TYPE_PRIMARY); g_assert (primary); - if (!mm_serial_port_open (primary, &info->error)) { - g_assert (info->error); - mm_callback_info_schedule (info); - return; - } - if (priv->have_emrdy) { /* Modem is ready, no need to check EMRDY */ do_init (primary, info); @@ -423,27 +407,14 @@ enable (MMModem *modem, mm_serial_port_queue_command (primary, "*EMRDY?", 5, mbm_emrdy_done, info); } -static void -parent_disable_done (MMModem *modem, GError *error, gpointer user_data) -{ - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - - if (error) - info->error = g_error_copy (error); - mm_callback_info_schedule (info); -} - static void disable (MMModem *modem, MMModemFn callback, gpointer user_data) { MMModem *parent_modem_iface; - MMCallbackInfo *info; MMSerialPort *primary; - info = mm_callback_info_new (modem, callback, user_data); - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); g_assert (primary); @@ -452,7 +423,7 @@ disable (MMModem *modem, mm_serial_port_queue_command (primary, "+CMER=0", 5, NULL, NULL); parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); - parent_modem_iface->disable (modem, parent_disable_done, info); + parent_modem_iface->disable (modem, callback, user_data); } static void @@ -464,8 +435,10 @@ do_connect (MMModem *modem, MMCallbackInfo *info; MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (modem); + mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE); + info = mm_callback_info_new (modem, callback, user_data); - priv->do_connect_done_info = info; + priv->pending_connect_info = info; mbm_modem_authenticate (MM_MODEM_MBM (modem), priv->username, priv->password, info); } @@ -478,10 +451,15 @@ disconnect (MMModem *modem, MMCallbackInfo *info; MMSerialPort *primary; - info = mm_callback_info_new (modem, callback, user_data); + mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); + primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); g_assert (primary); - mm_serial_port_queue_command (primary, "AT*ENAP=0", 3, NULL, info); + mm_serial_port_queue_command (primary, "*ENAP=0", 3, NULL, NULL); + + mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (modem), FALSE, MM_MODEM_STATE_REASON_NONE); + + info = mm_callback_info_new (modem, callback, user_data); mm_callback_info_schedule (info); } @@ -496,7 +474,7 @@ mbm_emrdy_received (MMSerialPort *port, } static void -mbm_pacsp0_received (MMSerialPort *port, +mbm_pacsp_received (MMSerialPort *port, GMatchInfo *info, gpointer user_data) { @@ -527,9 +505,12 @@ mbm_ciev_received (MMSerialPort *port, static void mbm_do_connect_done (MMModemMbm *self) { - /* unset the poll id which should remove the source in destroy func */ - g_return_if_fail (MM_MODEM_MBM_GET_PRIVATE (self)->do_connect_done_info); - mm_callback_info_schedule (MM_MODEM_MBM_GET_PRIVATE (self)->do_connect_done_info); + MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self); + + if (priv->pending_connect_info) { + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), NULL, priv->pending_connect_info); + priv->pending_connect_info = NULL; + } } static void @@ -559,10 +540,10 @@ mbm_e2nap_received (MMSerialPort *port, } static void -enap_poll_done (MMSerialPort *port, - GString *response, - GError *error, - gpointer user_data) +enap_poll_response (MMSerialPort *port, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; guint state; @@ -573,15 +554,20 @@ enap_poll_done (MMSerialPort *port, count = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "mbm-enap-poll-count")); if (sscanf (response->str, "*ENAP: %d", &state) == 1 && state == 1) { - mm_callback_info_schedule (info); - } else { - mm_callback_info_set_data (info, "mbm-enap-poll-count", GUINT_TO_POINTER (++count), NULL); - - /* lets give it about 50 seconds */ - if (count > 50) { - info -> error = mm_modem_connect_error_for_code (MM_MODEM_CONNECT_ERROR_BUSY); - mm_callback_info_schedule (info); - } + /* Success! Connected... */ + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), NULL, info); + return; + } + + mm_callback_info_set_data (info, "mbm-enap-poll-count", GUINT_TO_POINTER (++count), NULL); + + /* lets give it about 50 seconds */ + if (count > 50) { + GError *poll_error; + + poll_error = mm_modem_connect_error_for_code (MM_MODEM_CONNECT_ERROR_BUSY); + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), poll_error, info); + g_error_free (poll_error); } } @@ -593,8 +579,8 @@ enap_poll (gpointer user_data) g_assert (port); - mm_serial_port_queue_command (port, "AT*ENAP?", 3, enap_poll_done, user_data); - /* we cancle this in the _done function if all is fine */ + mm_serial_port_queue_command (port, "AT*ENAP?", 3, enap_poll_response, user_data); + /* we cancel this in the _done function if all is fine */ return TRUE; } @@ -605,16 +591,17 @@ enap_done (MMSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + guint tid; if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - guint tid = g_timeout_add_seconds (1, enap_poll, user_data); - /* remember poll id as callback info object, with source_remove as free func */ - mm_callback_info_set_data (info, "mbm-enap-poll-id", GUINT_TO_POINTER (tid), (GFreeFunc) g_source_remove); - mm_serial_port_queue_command (port, "AT*E2NAP=1", 3, NULL, NULL); + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info); + return; } + + tid = g_timeout_add_seconds (1, enap_poll, user_data); + /* remember poll id as callback info object, with source_remove as free func */ + mm_callback_info_set_data (info, "mbm-enap-poll-id", GUINT_TO_POINTER (tid), (GFreeFunc) g_source_remove); + mm_serial_port_queue_command (port, "AT*E2NAP=1", 3, NULL, NULL); } static void @@ -624,17 +611,19 @@ mbm_auth_done (MMSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMGenericGsm *modem = MM_GENERIC_GSM (info->modem); + char *command; + guint32 cid; if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - char *command; - guint32 cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (info->modem)); - command = g_strdup_printf ("AT*ENAP=1,%d", cid); - mm_serial_port_queue_command (port, command, 3, enap_done, user_data); - g_free (command); + mm_generic_gsm_connect_complete (modem, error, info); + return; } + + cid = mm_generic_gsm_get_cid (modem); + command = g_strdup_printf ("AT*ENAP=1,%d", cid); + mm_serial_port_queue_command (port, command, 3, enap_done, user_data); + g_free (command); } static void @@ -738,8 +727,8 @@ grab_port (MMModem *modem, mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_e2nap_received, modem, NULL); g_regex_unref (regex); - regex = g_regex_new ("\\r\\n\\+PACSP0\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_pacsp0_received, modem, NULL); + regex = g_regex_new ("\\r\\n\\+PACSP(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_pacsp_received, modem, NULL); g_regex_unref (regex); regex = g_regex_new ("\\r\\n\\+CIEV: (\\d),(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); @@ -779,7 +768,6 @@ static void modem_init (MMModem *modem_class) { modem_class->grab_port = grab_port; - modem_class->enable = enable; modem_class->disable = disable; modem_class->connect = do_connect; modem_class->disconnect = disconnect; @@ -807,11 +795,14 @@ static void mm_modem_mbm_class_init (MMModemMbmClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass); mm_modem_mbm_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (object_class, sizeof (MMModemMbmPrivate)); /* Virtual methods */ object_class->finalize = finalize; + + gsm_class->do_enable = do_enable; } diff --git a/plugins/mm-modem-novatel-gsm.c b/plugins/mm-modem-novatel-gsm.c index f4f21730..8189627d 100644 --- a/plugins/mm-modem-novatel-gsm.c +++ b/plugins/mm-modem-novatel-gsm.c @@ -56,27 +56,25 @@ init_modem_done (MMSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) - info->error = g_error_copy (error); - - mm_callback_info_schedule (info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); } static void pin_check_done (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMGenericGsm *self = MM_GENERIC_GSM (modem); MMSerialPort *primary; if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - /* Finish the initialization */ - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); - g_assert (primary); - mm_serial_port_queue_command (primary, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1", 10, init_modem_done, info); + mm_generic_gsm_enable_complete (self, error, info); + return; } + + /* Finish the initialization */ + primary = mm_generic_gsm_get_port (self, MM_PORT_TYPE_PRIMARY); + g_assert (primary); + mm_serial_port_queue_command (primary, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1", 10, init_modem_done, info); } static void @@ -88,13 +86,14 @@ pre_init_done (MMSerialPort *port, MMCallbackInfo *info = (MMCallbackInfo *) user_data; if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - /* Now check the PIN explicitly, novatel doesn't seem to report - that it needs it otherwise */ - mm_generic_gsm_check_pin (MM_GENERIC_GSM (info->modem), pin_check_done, info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); + return; } + + /* Now check the PIN explicitly, novatel doesn't seem to report + * that it needs it otherwise. + */ + mm_generic_gsm_check_pin (MM_GENERIC_GSM (info->modem), pin_check_done, info); } static void @@ -102,37 +101,22 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data) { MMCallbackInfo *info = user_data; - if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - return; - } - - mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data); + if (error) + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); + else + mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data); } static void -enable (MMModem *modem, - MMModemFn callback, - gpointer user_data) +do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data) { MMCallbackInfo *info; MMSerialPort *primary; - /* First, reset the previously used CID */ - mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); - - info = mm_callback_info_new (modem, callback, user_data); - - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); + primary = mm_generic_gsm_get_port (modem, MM_PORT_TYPE_PRIMARY); g_assert (primary); - if (!mm_serial_port_open (primary, &info->error)) { - g_assert (info->error); - mm_callback_info_schedule (info); - return; - } - + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); mm_serial_port_flash (primary, 100, enable_flash_done, info); } @@ -180,7 +164,6 @@ grab_port (MMModem *modem, static void modem_init (MMModem *modem_class) { - modem_class->enable = enable; modem_class->grab_port = grab_port; } @@ -192,6 +175,10 @@ mm_modem_novatel_gsm_init (MMModemNovatelGsm *self) static void mm_modem_novatel_gsm_class_init (MMModemNovatelGsmClass *klass) { + MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass); + mm_modem_novatel_gsm_parent_class = g_type_class_peek_parent (klass); + + gsm_class->do_enable = do_enable; } diff --git a/plugins/mm-modem-option.c b/plugins/mm-modem-option.c index e0ab0f18..2076ae66 100644 --- a/plugins/mm-modem-option.c +++ b/plugins/mm-modem-option.c @@ -53,9 +53,7 @@ pin_check_done (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) - info->error = g_error_copy (error); - mm_callback_info_schedule (info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info); } static gboolean @@ -64,9 +62,9 @@ option_enabled (gpointer data) MMCallbackInfo *info = (MMCallbackInfo *) data; /* Now check the PIN explicitly, option doesn't seem to report - that it needs it otherwise */ + * that it needs it otherwise. + */ mm_generic_gsm_check_pin (MM_GENERIC_GSM (info->modem), pin_check_done, info); - return FALSE; } @@ -76,13 +74,14 @@ parent_enable_done (MMModem *modem, GError *error, gpointer user_data) MMCallbackInfo *info = (MMCallbackInfo *) user_data; if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - /* Option returns OK on +CFUN=1 right away but needs some time - to finish initialization */ - g_timeout_add_seconds (10, option_enabled, info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info); + return; } + + /* Option returns OK on +CFUN=1 right away but needs some time + * to finish initialization + */ + g_timeout_add_seconds (10, option_enabled, info); } static void diff --git a/plugins/mm-modem-sierra-gsm.c b/plugins/mm-modem-sierra-gsm.c index ee477d86..ee82234a 100644 --- a/plugins/mm-modem-sierra-gsm.c +++ b/plugins/mm-modem-sierra-gsm.c @@ -53,9 +53,7 @@ pin_check_done (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) - info->error = g_error_copy (error); - mm_callback_info_schedule (info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info); } static gboolean @@ -64,9 +62,9 @@ sierra_enabled (gpointer data) MMCallbackInfo *info = (MMCallbackInfo *) data; /* Now check the PIN explicitly, sierra doesn't seem to report - that it needs it otherwise */ + * that it needs it otherwise. + */ mm_generic_gsm_check_pin (MM_GENERIC_GSM (info->modem), pin_check_done, info); - return FALSE; } @@ -76,19 +74,18 @@ parent_enable_done (MMModem *modem, GError *error, gpointer user_data) MMCallbackInfo *info = (MMCallbackInfo *) user_data; if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - /* Sierra returns OK on +CFUN=1 right away but needs some time - to finish initialization */ - g_timeout_add_seconds (10, sierra_enabled, info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info); + return; } + + /* Sierra returns OK on +CFUN=1 right away but needs some time + * to finish initialization. + */ + g_timeout_add_seconds (10, sierra_enabled, info); } static void -enable (MMModem *modem, - MMModemFn callback, - gpointer user_data) +enable (MMModem *modem, MMModemFn callback, gpointer user_data) { MMModem *parent_modem_iface; MMCallbackInfo *info; diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c index 95fb1b0a..24610738 100644 --- a/plugins/mm-modem-zte.c +++ b/plugins/mm-modem-zte.c @@ -62,10 +62,7 @@ init_modem_done (MMSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) - info->error = g_error_copy (error); - - mm_callback_info_schedule (info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); } static void @@ -75,14 +72,14 @@ pin_check_done (MMModem *modem, GError *error, gpointer user_data) MMSerialPort *primary; if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - /* Finish the initialization */ - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); - g_assert (primary); - mm_serial_port_queue_command (primary, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (modem), error, info); + return; } + + /* Finish the initialization */ + primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + mm_serial_port_queue_command (primary, "Z E0 V1 X4 &C1 +CMEE=1;+CFUN=1;", 10, init_modem_done, info); } static void enable_flash_done (MMSerialPort *port, @@ -104,10 +101,8 @@ pre_init_done (MMSerialPort *port, && g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_RESPONSE_TIMEOUT)) { priv->init_retried = TRUE; enable_flash_done (port, NULL, user_data); - } else { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } + } else + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); } else { /* Now check the PIN explicitly, zte doesn't seem to report that it needs it otherwise */ @@ -120,19 +115,14 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - return; - } - - mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data); + if (error) + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); + else + mm_serial_port_queue_command (port, "E0 V1", 3, pre_init_done, user_data); } static void -enable (MMModem *modem, - MMModemFn callback, - gpointer user_data) +do_enable (MMGenericGsm *modem, MMModemFn callback, gpointer user_data) { MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem); MMCallbackInfo *info; @@ -140,20 +130,10 @@ enable (MMModem *modem, priv->init_retried = FALSE; - /* First, reset the previously used CID */ - mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); - - info = mm_callback_info_new (modem, callback, user_data); - - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); + primary = mm_generic_gsm_get_port (modem, MM_PORT_TYPE_PRIMARY); g_assert (primary); - if (!mm_serial_port_open (primary, &info->error)) { - g_assert (info->error); - mm_callback_info_schedule (info); - return; - } - + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); mm_serial_port_flash (primary, 100, enable_flash_done, info); } @@ -224,7 +204,6 @@ grab_port (MMModem *modem, static void modem_init (MMModem *modem_class) { - modem_class->enable = enable; modem_class->disable = disable; modem_class->grab_port = grab_port; } @@ -238,8 +217,11 @@ static void mm_modem_zte_class_init (MMModemZteClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass); mm_modem_zte_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (object_class, sizeof (MMModemZtePrivate)); + + gsm_class->do_enable = do_enable; } diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index f9f87657..d351aca2 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -398,6 +398,29 @@ release_port (MMModem *modem, const char *subsys, const char *name) check_valid (MM_GENERIC_GSM (modem)); } +void +mm_generic_gsm_enable_complete (MMGenericGsm *modem, + GError *error, + MMCallbackInfo *info) +{ + g_return_if_fail (modem != NULL); + g_return_if_fail (MM_IS_GENERIC_GSM (modem)); + g_return_if_fail (info != NULL); + + if (error) { + mm_modem_set_state (MM_MODEM (modem), + MM_MODEM_STATE_DISABLED, + MM_MODEM_STATE_REASON_NONE); + + info->error = g_error_copy (error); + } else { + /* Modem is enabled; update the state */ + mm_generic_gsm_update_enabled_state (modem, FALSE, MM_MODEM_STATE_REASON_NONE); + } + + mm_callback_info_schedule (info); +} + static void enable_done (MMSerialPort *port, GString *response, @@ -415,11 +438,7 @@ enable_done (MMSerialPort *port, * errors or ignore them. */ - mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (info->modem), - FALSE, - MM_MODEM_STATE_REASON_NONE); - - mm_callback_info_schedule (info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), NULL, info); } static void @@ -432,34 +451,30 @@ init_done (MMSerialPort *port, char *cmd = NULL; if (error) { - mm_modem_set_state (MM_MODEM (info->modem), - MM_MODEM_STATE_DISABLED, - MM_MODEM_STATE_REASON_NONE); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); + return; + } - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else { - /* Ensure echo is off after the init command; some modems ignore the - * E0 when it's in the same like as ATZ (Option GIO322). - */ - mm_serial_port_queue_command (port, "E0 +CMEE=1", 2, NULL, NULL); + /* Ensure echo is off after the init command; some modems ignore the + * E0 when it's in the same like as ATZ (Option GIO322). + */ + mm_serial_port_queue_command (port, "E0 +CMEE=1", 2, NULL, NULL); - g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_INIT_CMD_OPTIONAL, &cmd, NULL); - mm_serial_port_queue_command (port, cmd, 2, NULL, NULL); - g_free (cmd); + g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_INIT_CMD_OPTIONAL, &cmd, NULL); + mm_serial_port_queue_command (port, cmd, 2, NULL, NULL); + g_free (cmd); - if (MM_GENERIC_GSM_GET_PRIVATE (info->modem)->unsolicited_registration) - mm_serial_port_queue_command (port, "+CREG=1", 5, NULL, NULL); - else - mm_serial_port_queue_command (port, "+CREG=0", 5, NULL, NULL); + if (MM_GENERIC_GSM_GET_PRIVATE (info->modem)->unsolicited_registration) + mm_serial_port_queue_command (port, "+CREG=1", 5, NULL, NULL); + else + mm_serial_port_queue_command (port, "+CREG=0", 5, NULL, NULL); - g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL); - if (cmd && strlen (cmd)) - mm_serial_port_queue_command (port, cmd, 5, enable_done, user_data); - else - enable_done (port, NULL, NULL, user_data); - g_free (cmd); - } + g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL); + if (cmd && strlen (cmd)) + mm_serial_port_queue_command (port, cmd, 5, enable_done, user_data); + else + enable_done (port, NULL, NULL, user_data); + g_free (cmd); } static void @@ -469,12 +484,7 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data) char *cmd = NULL; if (error) { - mm_modem_set_state (MM_MODEM (info->modem), - MM_MODEM_STATE_DISABLED, - MM_MODEM_STATE_REASON_NONE); - - info->error = g_error_copy (error); - mm_callback_info_schedule (info); + mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info); return; } @@ -483,30 +493,41 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data) g_free (cmd); } +static void +real_do_enable (MMGenericGsm *self, MMModemFn callback, gpointer user_data) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + MMCallbackInfo *info; + + info = mm_callback_info_new (MM_MODEM (self), callback, user_data); + mm_serial_port_flash (priv->primary, 100, enable_flash_done, info); +} + static void enable (MMModem *modem, MMModemFn callback, gpointer user_data) { MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); - MMCallbackInfo *info; + GError *error = NULL; /* First, reset the previously used CID */ mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); - info = mm_callback_info_new (modem, callback, user_data); + if (!mm_serial_port_open (priv->primary, &error)) { + MMCallbackInfo *info; - if (!mm_serial_port_open (priv->primary, &info->error)) { - g_assert (info->error); + g_assert (error); + info = mm_callback_info_new (modem, callback, user_data); + info->error = error; mm_callback_info_schedule (info); return; } - mm_modem_set_state (MM_MODEM (info->modem), - MM_MODEM_STATE_ENABLING, - MM_MODEM_STATE_REASON_NONE); + mm_modem_set_state (modem, MM_MODEM_STATE_ENABLING, MM_MODEM_STATE_REASON_NONE); - mm_serial_port_flash (priv->primary, 100, enable_flash_done, info); + g_assert (MM_GENERIC_GSM_GET_CLASS (modem)->do_enable); + MM_GENERIC_GSM_GET_CLASS (modem)->do_enable (MM_GENERIC_GSM (modem), callback, user_data); } static void @@ -1190,6 +1211,33 @@ get_registration_info (MMModemGsmNetwork *self, mm_callback_info_schedule (info); } +void +mm_generic_gsm_connect_complete (MMGenericGsm *modem, + GError *error, + MMCallbackInfo *info) +{ + MMGenericGsmPrivate *priv; + + g_return_if_fail (modem != NULL); + g_return_if_fail (MM_IS_GENERIC_GSM (modem)); + g_return_if_fail (info != NULL); + + priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + + if (error) { + mm_generic_gsm_update_enabled_state (modem, FALSE, MM_MODEM_STATE_REASON_NONE); + info->error = g_error_copy (error); + } else { + /* Modem is connected; update the state */ + mm_port_set_connected (priv->data, TRUE); + mm_modem_set_state (MM_MODEM (modem), + MM_MODEM_STATE_CONNECTED, + MM_MODEM_STATE_REASON_NONE); + } + + mm_callback_info_schedule (info); +} + static void connect_report_done (MMSerialPort *port, GString *response, @@ -1197,14 +1245,28 @@ connect_report_done (MMSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + GError *real_error; + + /* If the CEER command was successful, copy that error reason into the + * callback's error. If not, use the original error. + */ - if (!error && g_str_has_prefix (response->str, "+CEER: ")) { - g_free (info->error->message); - info->error->message = g_strdup (response->str + 7); /* skip the "+CEER: " */ + /* Have to do this little dance since mm_generic_gsm_connect_complete() + * copies the provided error into the callback info. + */ + real_error = info->error; + info->error = NULL; + + if ( !error + && g_str_has_prefix (response->str, "+CEER: ") + && (strlen (response->str) > 7)) { + /* copy the connect failure reason into the error */ + g_free (real_error->message); + real_error->message = g_strdup (response->str + 7); /* skip the "+CEER: " */ } - - mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (info->modem), FALSE, MM_MODEM_STATE_REASON_NONE); - mm_callback_info_schedule (info); + + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), real_error, info); + g_error_free (real_error); } static void @@ -1221,12 +1283,8 @@ connect_done (MMSerialPort *port, /* Try to get more information why it failed */ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); mm_serial_port_queue_command (priv->primary, "+CEER", 3, connect_report_done, info); - } else { - /* Done */ - mm_port_set_connected (priv->data, TRUE); - mm_modem_set_state (info->modem, MM_MODEM_STATE_CONNECTED, MM_MODEM_STATE_REASON_NONE); - mm_callback_info_schedule (info); - } + } else + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), NULL, info); } static void @@ -2155,6 +2213,8 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass) object_class->get_property = get_property; object_class->finalize = finalize; + klass->do_enable = real_do_enable; + /* Properties */ g_object_class_override_property (object_class, MM_MODEM_PROP_DATA_DEVICE, diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index ea60ffbf..de0b00b7 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -21,6 +21,7 @@ #include "mm-modem-gsm-network.h" #include "mm-modem-base.h" #include "mm-serial-port.h" +#include "mm-callback-info.h" #define MM_TYPE_GENERIC_GSM (mm_generic_gsm_get_type ()) #define MM_GENERIC_GSM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_GENERIC_GSM, MMGenericGsm)) @@ -52,6 +53,15 @@ typedef struct { typedef struct { MMModemBaseClass parent; + + /* Called after opening the primary serial port and updating the modem's + * state to ENABLING, but before sending any commands to the device. Modems + * that need to perform custom initialization sequences or other setup should + * generally override this method instead of the MMModem interface's enable() + * method, unless the customization must happen *after* the generic init + * sequence has completed. + */ + void (*do_enable) (MMGenericGsm *self, MMModemFn callback, gpointer user_data); } MMGenericGsmClass; GType mm_generic_gsm_get_type (void); @@ -98,4 +108,22 @@ void mm_generic_gsm_update_enabled_state (MMGenericGsm *modem, gboolean stay_connected, MMModemStateReason reason); +/* Called to complete the enable operation for custom enable() handling; if an + * error is passed in, it copies the error to the callback info. This function + * always schedules the callback info. It will also update the modem with the + * correct state for both failure and success of the enable operation. + */ +void mm_generic_gsm_enable_complete (MMGenericGsm *modem, + GError *error, + MMCallbackInfo *info); + +/* Called to complete the enable operation for custom connect() handling; if an + * error is passed in, it copies the error to the callback info. This function + * always schedules the callback info. It will also update the modem with the + * correct state for both failure and success of the connect operation. + */ +void mm_generic_gsm_connect_complete (MMGenericGsm *modem, + GError *error, + MMCallbackInfo *info); + #endif /* MM_GENERIC_GSM_H */ -- cgit v1.2.3-70-g09d2 From 1157b59a18ee4e5da109977947181f8596f100ff Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 2 Dec 2009 14:59:26 -0800 Subject: core: pretty-print state changes --- src/mm-manager.c | 2 -- src/mm-modem.c | 43 ++++++++++++++++++++++++++++++++++++++++++- src/mm-modem.h | 2 ++ 3 files changed, 44 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mm-manager.c b/src/mm-manager.c index 73189146..1a93170b 100644 --- a/src/mm-manager.c +++ b/src/mm-manager.c @@ -43,8 +43,6 @@ static guint signals[LAST_SIGNAL] = { 0 }; #define MM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MANAGER, MMManagerPrivate)) -#define DBUS_PATH_TAG "dbus-path" - typedef struct { DBusGConnection *connection; GUdevClient *udev; diff --git a/src/mm-modem.c b/src/mm-modem.c index b49c7070..af67864d 100644 --- a/src/mm-modem.c +++ b/src/mm-modem.c @@ -514,19 +514,60 @@ mm_modem_get_state (MMModem *self) return state; } +static const char * +state_to_string (MMModemState state) +{ + switch (state) { + case MM_MODEM_STATE_UNKNOWN: + return "unknown"; + case MM_MODEM_STATE_DISABLED: + return "disabled"; + case MM_MODEM_STATE_DISABLING: + return "disabling"; + case MM_MODEM_STATE_ENABLING: + return "enabling"; + case MM_MODEM_STATE_ENABLED: + return "enabled"; + case MM_MODEM_STATE_SEARCHING: + return "searching"; + case MM_MODEM_STATE_REGISTERED: + return "registered"; + case MM_MODEM_STATE_DISCONNECTING: + return "disconnecting"; + case MM_MODEM_STATE_CONNECTING: + return "connecting"; + case MM_MODEM_STATE_CONNECTED: + return "connected"; + default: + g_assert_not_reached (); + break; + } + + g_assert_not_reached (); + return "(invalid)"; +} + void mm_modem_set_state (MMModem *self, MMModemState new_state, MMModemStateReason reason) { MMModemState old_state = MM_MODEM_STATE_UNKNOWN; + const char *dbus_path; g_object_get (G_OBJECT (self), MM_MODEM_STATE, &old_state, NULL); if (new_state != old_state) { g_object_set (G_OBJECT (self), MM_MODEM_STATE, new_state, NULL); g_signal_emit_by_name (G_OBJECT (self), "state-changed", new_state, old_state, reason); -g_message ("%s: state %d -> %d", __func__, old_state, new_state); + + dbus_path = (const char *) g_object_get_data (G_OBJECT (self), DBUS_PATH_TAG); + if (dbus_path) { + g_message ("Modem %s: state changed (%s -> %s)", + dbus_path, + state_to_string (old_state), + state_to_string (new_state)); + } } } diff --git a/src/mm-modem.h b/src/mm-modem.h index cf16f190..1a379411 100644 --- a/src/mm-modem.h +++ b/src/mm-modem.h @@ -40,6 +40,8 @@ typedef enum { MM_MODEM_STATE_REASON_NONE = 0 } MMModemStateReason; +#define DBUS_PATH_TAG "dbus-path" + #define MM_TYPE_MODEM (mm_modem_get_type ()) #define MM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM, MMModem)) #define MM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM)) -- cgit v1.2.3-70-g09d2 From 5a4a9a6239ac771e8ddc343d041f643d848a7ad2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 7 Dec 2009 18:39:18 -0800 Subject: core: add refcounts to MMCallbackInfo --- src/mm-callback-info.c | 39 +++++++++++++++++++++++++++++++-------- src/mm-callback-info.h | 6 ++++++ 2 files changed, 37 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/mm-callback-info.c b/src/mm-callback-info.c index 089f0b73..b554f79b 100644 --- a/src/mm-callback-info.c +++ b/src/mm-callback-info.c @@ -72,14 +72,7 @@ callback_info_done (gpointer user_data) if (info->invoke_fn && info->callback) info->invoke_fn (info); - if (info->error) - g_error_free (info->error); - - if (info->modem) - g_object_weak_unref (G_OBJECT (info->modem), modem_destroyed_cb, info); - - g_datalist_clear (&info->qdata); - g_slice_free (MMCallbackInfo, info); + mm_callback_info_unref (info); } static gboolean @@ -117,6 +110,7 @@ mm_callback_info_new_full (MMModem *modem, info->invoke_fn = invoke_fn; info->callback = callback; info->user_data = user_data; + info->refcount = 1; return info; } @@ -184,3 +178,32 @@ mm_callback_info_get_data (MMCallbackInfo *info, const char *key) return quark ? g_datalist_id_get_data (&info->qdata, quark) : NULL; } + +MMCallbackInfo * +mm_callback_info_ref (MMCallbackInfo *info) +{ + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (info->refcount > 0, NULL); + + info->refcount++; + return info; +} + +void +mm_callback_info_unref (MMCallbackInfo *info) +{ + g_return_if_fail (info != NULL); + + info->refcount--; + if (info->refcount == 0) { + if (info->error) + g_error_free (info->error); + + if (info->modem) + g_object_weak_unref (G_OBJECT (info->modem), modem_destroyed_cb, info); + + g_datalist_clear (&info->qdata); + g_slice_free (MMCallbackInfo, info); + } +} + diff --git a/src/mm-callback-info.h b/src/mm-callback-info.h index 783e1282..66c20487 100644 --- a/src/mm-callback-info.h +++ b/src/mm-callback-info.h @@ -23,6 +23,8 @@ typedef struct _MMCallbackInfo MMCallbackInfo; typedef void (*MMCallbackInfoInvokeFn) (MMCallbackInfo *info); struct _MMCallbackInfo { + guint32 refcount; + GData *qdata; MMModem *modem; @@ -65,4 +67,8 @@ void mm_callback_info_set_data (MMCallbackInfo *info, gpointer mm_callback_info_get_data (MMCallbackInfo *info, const char *key); +MMCallbackInfo *mm_callback_info_ref (MMCallbackInfo *info); +void mm_callback_info_unref (MMCallbackInfo *info); + #endif /* MM_CALLBACK_INFO_H */ + -- cgit v1.2.3-70-g09d2 From a9e0624426632a38c2d208e7a28fac3bca51d857 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 7 Dec 2009 18:40:04 -0800 Subject: gsm: handle different +COPS response behavior Some modems delay the +COPS response until registration is complete, others return right away. Make sure that both behaviors work correctly. --- src/mm-generic-gsm.c | 61 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index d351aca2..55d75f6b 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -1020,11 +1020,24 @@ reg_state_changed (MMSerialPort *port, gpointer user_data) { MMGenericGsm *self = MM_GENERIC_GSM (user_data); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); char *str; + gboolean done; str = g_match_info_fetch (match_info, 1); - reg_status_updated (self, atoi (str), NULL); + done = reg_status_updated (self, atoi (str), NULL); g_free (str); + + if (done) { + /* If registration is finished (either registered or failed) but the + * registration query hasn't completed yet, just remove the timeout and + * let the registration query complete. + */ + if (priv->pending_reg_id) { + g_source_remove (priv->pending_reg_id); + priv->pending_reg_id = 0; + } + } } static gboolean @@ -1035,7 +1048,7 @@ reg_status_again (gpointer data) g_warn_if_fail (info == priv->pending_reg_info); - if (priv->pending_reg_id) + if (priv->pending_reg_info) get_registration_status (priv->primary, info); return FALSE; @@ -1102,7 +1115,7 @@ get_reg_status_done (MMSerialPort *port, if ( reg_status >= 0 && !reg_status_updated (self, reg_status, &info->error) - && priv->pending_reg_id) { + && priv->pending_reg_info) { g_clear_error (&info->error); /* Not registered yet; poll registration status again */ @@ -1134,8 +1147,23 @@ register_done (MMSerialPort *port, GError *error, gpointer user_data) { - /* Ignore errors here, get the actual registration status */ - get_registration_status (port, (MMCallbackInfo *) user_data); + MMCallbackInfo *info = user_data; + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + + mm_callback_info_unref (info); + + /* If the registration timed out (and thus pending_reg_info will be NULL) + * and the modem eventually got around to sending the response for the + * registration request then just ignore the response since the callback is + * already called. + */ + + if (priv->pending_reg_info) { + g_warn_if_fail (info == priv->pending_reg_info); + + /* Ignore errors here, get the actual registration status */ + get_registration_status (port, info); + } } static gboolean @@ -1146,12 +1174,11 @@ registration_timed_out (gpointer data) g_warn_if_fail (info == priv->pending_reg_info); - priv->pending_reg_id = 0; - priv->pending_reg_info = NULL; priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE; info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_NETWORK_TIMEOUT); - mm_callback_info_schedule (info); + mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (info->modem)); + return FALSE; } @@ -1178,6 +1205,24 @@ do_register (MMModemGsmNetwork *modem, else command = g_strdup ("+COPS=0,,"); + /* Ref the callback info to ensure it stays alive for register_done() even + * if the timeout triggers and ends registration (which calls the callback + * and unrefs the callback info). Some devices (hso) will delay the + * registration response until the registration is done (and thus + * unsolicited registration responses will arrive before the +COPS is + * complete). Most other devices will return the +COPS response immediately + * and the unsolicited response (if any) at a later time. + * + * To handle both these cases, unsolicited registration responses will just + * remove the pending registration timeout but we let the +COPS command + * complete. For those devices that delay the +COPS response (hso) the + * callback will be called from register_done(). For those devices that + * return the +COPS response immediately, we'll poll the registration state + * and call the callback from get_reg_status_done() in response to the + * polled response. The registration timeout will only be triggered when + * the +COPS response is never received. + */ + mm_callback_info_ref (info); mm_serial_port_queue_command (priv->primary, command, 120, register_done, info); g_free (command); } -- cgit v1.2.3-70-g09d2