diff options
author | Dan Williams <dcbw@redhat.com> | 2009-12-07 22:04:28 -0800 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2009-12-07 22:04:28 -0800 |
commit | dd057d28e4ab3812eebd41a7df1c2f80d90d8600 (patch) | |
tree | 46fa937720de3305ccc093f4741f0a25680fcba0 | |
parent | f715e0d498930409d97a8097b37731aadbc11a72 (diff) | |
parent | a9e0624426632a38c2d208e7a28fac3bca51d857 (diff) |
Merge commit 'origin/states'
-rw-r--r-- | marshallers/mm-marshal.list | 2 | ||||
-rw-r--r-- | plugins/mm-modem-hso.c | 33 | ||||
-rw-r--r-- | plugins/mm-modem-mbm.c | 159 | ||||
-rw-r--r-- | plugins/mm-modem-novatel-gsm.c | 67 | ||||
-rw-r--r-- | plugins/mm-modem-option.c | 21 | ||||
-rw-r--r-- | plugins/mm-modem-sierra-gsm.c | 25 | ||||
-rw-r--r-- | plugins/mm-modem-zte.c | 58 | ||||
-rw-r--r-- | src/mm-callback-info.c | 39 | ||||
-rw-r--r-- | src/mm-callback-info.h | 6 | ||||
-rw-r--r-- | src/mm-generic-cdma.c | 120 | ||||
-rw-r--r-- | src/mm-generic-cdma.h | 2 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 301 | ||||
-rw-r--r-- | src/mm-generic-gsm.h | 41 | ||||
-rw-r--r-- | src/mm-manager.c | 2 | ||||
-rw-r--r-- | src/mm-modem-base.c | 19 | ||||
-rw-r--r-- | src/mm-modem.c | 219 | ||||
-rw-r--r-- | src/mm-modem.h | 35 | ||||
-rwxr-xr-x | test/mm-test.py | 3 |
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) |