aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2009-12-07 22:04:28 -0800
committerDan Williams <dcbw@redhat.com>2009-12-07 22:04:28 -0800
commitdd057d28e4ab3812eebd41a7df1c2f80d90d8600 (patch)
tree46fa937720de3305ccc093f4741f0a25680fcba0
parentf715e0d498930409d97a8097b37731aadbc11a72 (diff)
parenta9e0624426632a38c2d208e7a28fac3bca51d857 (diff)
Merge commit 'origin/states'
-rw-r--r--marshallers/mm-marshal.list2
-rw-r--r--plugins/mm-modem-hso.c33
-rw-r--r--plugins/mm-modem-mbm.c159
-rw-r--r--plugins/mm-modem-novatel-gsm.c67
-rw-r--r--plugins/mm-modem-option.c21
-rw-r--r--plugins/mm-modem-sierra-gsm.c25
-rw-r--r--plugins/mm-modem-zte.c58
-rw-r--r--src/mm-callback-info.c39
-rw-r--r--src/mm-callback-info.h6
-rw-r--r--src/mm-generic-cdma.c120
-rw-r--r--src/mm-generic-cdma.h2
-rw-r--r--src/mm-generic-gsm.c301
-rw-r--r--src/mm-generic-gsm.h41
-rw-r--r--src/mm-manager.c2
-rw-r--r--src/mm-modem-base.c19
-rw-r--r--src/mm-modem.c219
-rw-r--r--src/mm-modem.h35
-rwxr-xr-xtest/mm-test.py3
18 files changed, 882 insertions, 270 deletions
diff --git a/marshallers/mm-marshal.list b/marshallers/mm-marshal.list
index ccf8605b..12c22c22 100644
--- a/marshallers/mm-marshal.list
+++ b/marshallers/mm-marshal.list
@@ -3,3 +3,5 @@ VOID:STRING,STRING,UINT
VOID:OBJECT,UINT
VOID:UINT,BOOLEAN
VOID:UINT,UINT
+VOID:UINT,UINT,UINT
+
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;
@@ -325,6 +322,16 @@ enable (MMModem *modem,
}
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,
gpointer user_data)
@@ -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 cb0ba816..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,9 +322,7 @@ mbm_enable_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
@@ -339,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);
@@ -354,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
@@ -385,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 (MM_MODEM (self), callback, user_data);
- 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 (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);
@@ -418,26 +408,13 @@ enable (MMModem *modem,
}
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);
@@ -446,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
@@ -458,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);
}
@@ -472,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);
}
@@ -490,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)
{
@@ -521,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
@@ -553,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;
@@ -567,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);
}
}
@@ -587,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;
}
@@ -599,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
@@ -618,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
@@ -732,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);
@@ -773,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;
@@ -801,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-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 */
+
diff --git a/src/mm-generic-cdma.c b/src/mm-generic-cdma.c
index be4e0524..0e99ec77 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);
@@ -293,6 +299,26 @@ mm_generic_cdma_evdo_get_registration_state_sync (MMGenericCdma *self)
/*****************************************************************************/
static void
+update_enabled_state (MMGenericCdma *self,
+ gboolean stay_connected,
+ MMModemStateReason reason)
+{
+ MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_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;
+
+ 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)
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (self);
@@ -338,6 +364,8 @@ enable_error_reporting_done (MMSerialPort *port,
g_assert (info->error);
}
+ 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);
}
@@ -351,6 +379,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 {
@@ -369,6 +401,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);
@@ -395,6 +431,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);
}
@@ -404,11 +444,27 @@ disable_flash_done (MMSerialPort *port,
gpointer user_data)
{
MMCallbackInfo *info = user_data;
+ 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);
- 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);
+
+ 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);
}
@@ -421,15 +477,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_CDMA_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
@@ -446,13 +514,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 {
+ 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);
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);
@@ -468,6 +538,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);
@@ -483,12 +555,22 @@ 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;
}
mm_port_set_connected (priv->data, FALSE);
+ update_enabled_state (MM_GENERIC_CDMA (info->modem), FALSE, MM_MODEM_STATE_REASON_NONE);
+
mm_callback_info_schedule (info);
}
@@ -499,10 +581,20 @@ disconnect (MMModem *modem,
{
MMGenericCdmaPrivate *priv = MM_GENERIC_CDMA_GET_PRIVATE (modem);
MMCallbackInfo *info;
+ MMModemState state;
g_return_if_fail (priv->primary != NULL);
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);
}
@@ -1282,6 +1374,13 @@ reg_state_changed (MMModemCdma *self,
#endif
}
+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
simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
{
@@ -1298,11 +1397,11 @@ simple_state_machine (MMModem *modem, GError *error, gpointer user_data)
switch (state) {
case SIMPLE_STATE_BEGIN:
- state = SIMPLE_STATE_ENABLE;
+ state = set_simple_state (info, SIMPLE_STATE_ENABLE);
mm_modem_enable (modem, simple_state_machine, info);
break;
case SIMPLE_STATE_ENABLE:
- state = 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);
@@ -1314,12 +1413,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;
+ 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:
- state = SIMPLE_STATE_DONE;
+ state = set_simple_state (info, SIMPLE_STATE_DONE);
break;
case SIMPLE_STATE_DONE:
break;
@@ -1329,8 +1430,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-cdma.h b/src/mm-generic-cdma.h
index 8d85cb38..e84182ad 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_CDMA_PREV_STATE_TAG "prev-state"
+
MMPort * mm_generic_cdma_grab_port (MMGenericCdma *self,
const char *subsys,
const char *name,
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 06b785b3..55d75f6b 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, TRUE, MM_MODEM_STATE_REASON_NONE);
}
}
@@ -243,6 +245,36 @@ mm_generic_gsm_check_pin (MMGenericGsm *modem,
/*****************************************************************************/
+void
+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:
+ 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)
{
@@ -366,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,
@@ -382,7 +437,8 @@ enable_done (MMSerialPort *port,
* on the phone and let the subclass decided whether it wants to handle
* errors or ignore them.
*/
- mm_callback_info_schedule (info);
+
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), NULL, info);
}
static void
@@ -395,30 +451,30 @@ init_done (MMSerialPort *port,
char *cmd = NULL;
if (error) {
- 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);
+ mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
+ return;
+ }
- 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);
+ /* 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);
- 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_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_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);
- }
+ 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);
}
static void
@@ -428,8 +484,7 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
char *cmd = NULL;
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);
return;
}
@@ -439,25 +494,40 @@ enable_flash_done (MMSerialPort *port, GError *error, gpointer user_data)
}
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_serial_port_flash (priv->primary, 100, enable_flash_done, info);
+ mm_modem_set_state (modem, MM_MODEM_STATE_ENABLING, MM_MODEM_STATE_REASON_NONE);
+
+ 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
@@ -466,8 +536,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
@@ -479,6 +554,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;
@@ -499,6 +582,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);
@@ -506,6 +590,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
@@ -925,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
@@ -940,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;
@@ -1007,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 */
@@ -1039,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
@@ -1051,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;
}
@@ -1083,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);
}
@@ -1116,6 +1256,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,
@@ -1123,13 +1290,28 @@ connect_report_done (MMSerialPort *port,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ GError *real_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: " */
+ /* If the CEER command was successful, copy that error reason into the
+ * callback's error. If not, use the original error.
+ */
+
+ /* 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_callback_info_schedule (info);
+
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), real_error, info);
+ g_error_free (real_error);
}
static void
@@ -1146,11 +1328,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_callback_info_schedule (info);
- }
+ } else
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), NULL, info);
}
static void
@@ -1166,6 +1345,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;
@@ -1190,15 +1371,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);
}
@@ -1209,11 +1400,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);
}
@@ -2057,6 +2258,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 7cfd6253..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);
@@ -60,6 +70,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,4 +99,31 @@ 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);
+
+/* 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 */
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-base.c b/src/mm-modem-base.c
index 1df965f8..d50d7517 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;
@@ -147,6 +148,14 @@ mm_modem_base_set_valid (MMModemBase *self, gboolean new_valid)
if (priv->valid != new_valid) {
priv->valid = new_valid;
+
+ /* 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);
+
g_object_notify (G_OBJECT (self), MM_MODEM_VALID);
}
}
@@ -181,6 +190,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 +224,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;
@@ -266,6 +281,10 @@ mm_modem_base_class_init (MMModemBaseClass *klass)
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..af67864d 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,27 +58,109 @@ 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) {
+ MMCallbackInfo *info;
+
+ 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;
+ }
+
if (MM_MODEM_GET_INTERFACE (self)->enable)
MM_MODEM_GET_INTERFACE (self)->enable (self, callback, user_data);
else
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,
gpointer user_data)
{
+ MMModemState state;
+
g_return_if_fail (MM_IS_MODEM (self));
g_return_if_fail (callback != NULL);
- 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);
+ state = mm_modem_get_state (self);
+ if (state <= MM_MODEM_STATE_DISABLING) {
+ MMCallbackInfo *info;
+
+ 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 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
@@ -97,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
@@ -211,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
@@ -381,11 +505,78 @@ 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;
+}
+
+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);
+
+ 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));
+ }
+ }
+}
+
/*****************************************************************************/
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 +641,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..1a379411 100644
--- a/src/mm-modem.h
+++ b/src/mm-modem.h
@@ -21,6 +21,27 @@
#include "mm-port.h"
+typedef enum {
+ MM_MODEM_STATE_UNKNOWN = 0,
+ 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,
+ 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;
+
+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))
@@ -33,6 +54,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 +74,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 +149,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 +203,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 */
diff --git a/test/mm-test.py b/test/mm-test.py
index cb9ecf0a..e1d68b0f 100755
--- a/test/mm-test.py
+++ b/test/mm-test.py
@@ -17,6 +17,7 @@
import sys
import dbus
+import time
DBUS_INTERFACE_PROPERTIES='org.freedesktop.DBus.Properties'
MM_DBUS_SERVICE='org.freedesktop.ModemManager'
@@ -310,5 +311,7 @@ for m in modems:
cdma_connect(proxy, user, password)
print
+ time.sleep(5)
+
modem.Enable(False)