diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mm-modem-hso.c | 105 | ||||
-rw-r--r-- | plugins/mm-modem-huawei-cdma.c | 67 | ||||
-rw-r--r-- | plugins/mm-modem-zte.c | 44 | ||||
-rw-r--r-- | plugins/mm-plugin-huawei.c | 1 |
4 files changed, 173 insertions, 44 deletions
diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c index 26dc17d6..a2e3b408 100644 --- a/plugins/mm-modem-hso.c +++ b/plugins/mm-modem-hso.c @@ -47,10 +47,23 @@ G_DEFINE_TYPE_EXTENDED (MMModemHso, mm_modem_hso, MM_TYPE_GENERIC_GSM, 0, #define MM_MODEM_HSO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_HSO, MMModemHsoPrivate)) +static void _internal_hso_modem_authenticate (MMModemHso *self, MMCallbackInfo *info); + +const char *auth_commands[] = { + "$QCPDPP", + /* Icera-based devices (GI0322/Quicksilver, iCON 505) don't implement + * $QCPDPP, but instead use _OPDPP with the same arguments. + */ + "_OPDPP", + NULL +}; + typedef struct { /* Pending connection attempt */ MMCallbackInfo *connect_pending_data; guint connect_pending_id; + + guint32 auth_idx; } MMModemHsoPrivate; #define OWANDATA_TAG "_OWANDATA: " @@ -72,6 +85,8 @@ mm_modem_hso_new (const char *device, NULL)); } +#define IGNORE_ERRORS_TAG "ignore-errors" + static void hso_call_control_done (MMSerialPort *port, GString *response, @@ -80,7 +95,7 @@ hso_call_control_done (MMSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error && !mm_callback_info_get_data (info, "ignore-errors")) + if (error && !mm_callback_info_get_data (info, IGNORE_ERRORS_TAG)) info->error = g_error_copy (error); mm_callback_info_schedule (info); @@ -110,7 +125,7 @@ hso_call_control (MMModemHso *self, MMSerialPort *primary; info = mm_callback_info_new (MM_MODEM (self), callback, user_data); - mm_callback_info_set_data (info, "ignore-error", GUINT_TO_POINTER (ignore_errors), NULL); + mm_callback_info_set_data (info, IGNORE_ERRORS_TAG, GUINT_TO_POINTER (ignore_errors), NULL); command = g_strdup_printf ("AT_OWANCALL=%d,%d,1", hso_get_cid (self), activate ? 1 : 0); primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); @@ -172,9 +187,9 @@ hso_enabled (MMModem *modem, } static void -hso_disabled (MMModem *modem, - GError *error, - gpointer user_data) +clear_old_context (MMModem *modem, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; @@ -195,13 +210,58 @@ auth_done (MMSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMModemHso *self = MM_MODEM_HSO (info->modem); + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } else + priv->auth_idx++; + if (auth_commands[priv->auth_idx]) { + /* Try the next auth command */ + _internal_hso_modem_authenticate (self, info); + } else { + /* Reset to 0 so that something gets tried for the next connection */ + priv->auth_idx = 0; + + info->error = g_error_copy (error); + mm_callback_info_schedule (info); + } + } else { + priv->auth_idx = 0; + /* success, kill any existing connections first */ - hso_call_control (self, FALSE, FALSE, hso_disabled, info); + hso_call_control (self, FALSE, TRUE, clear_old_context, info); + } +} + +static void +_internal_hso_modem_authenticate (MMModemHso *self, MMCallbackInfo *info) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + MMSerialPort *primary; + guint32 cid; + char *command; + const char *username, *password; + + primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + cid = hso_get_cid (self); + + username = mm_callback_info_get_data (info, "username"); + password = mm_callback_info_get_data (info, "password"); + + if (!username && !password) + command = g_strdup_printf ("%s=%d,0", auth_commands[priv->auth_idx], cid); + else { + command = g_strdup_printf ("%s=%d,1,\"%s\",\"%s\"", + auth_commands[priv->auth_idx], + cid, + password ? password : "", + username ? username : ""); + + } + + mm_serial_port_queue_command (primary, command, 3, auth_done, info); + g_free (command); } void @@ -212,32 +272,17 @@ mm_hso_modem_authenticate (MMModemHso *self, gpointer user_data) { MMCallbackInfo *info; - MMSerialPort *primary; g_return_if_fail (MM_IS_MODEM_HSO (self)); g_return_if_fail (callback != NULL); info = mm_callback_info_new (MM_MODEM (self), callback, user_data); + if (username) + mm_callback_info_set_data (info, "username", g_strdup (username), g_free); + if (password) + mm_callback_info_set_data (info, "password", g_strdup (password), g_free); - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); - g_assert (primary); - - if (username || password) { - char *command; - - // FIXME: if QCPDPP fails, try OPDPP. AT&T Quicksilver uses a different - // chipset (ie, not Qualcomm) and the auth command is OPDPP instead of - // the Qualcomm-specific QCPDPP. - - command = g_strdup_printf ("AT$QCPDPP=%d,1,\"%s\",\"%s\"", - hso_get_cid (self), - password ? password : "", - username ? username : ""); - - mm_serial_port_queue_command (primary, command, 3, auth_done, info); - g_free (command); - } else - auth_done (primary, NULL, NULL, info); + _internal_hso_modem_authenticate (self, info); } /*****************************************************************************/ @@ -304,7 +349,7 @@ disable (MMModem *modem, info = mm_callback_info_new (modem, callback, user_data); /* Kill any existing connection */ - hso_call_control (MM_MODEM_HSO (modem), FALSE, FALSE, disable_done, info); + hso_call_control (MM_MODEM_HSO (modem), FALSE, TRUE, disable_done, info); } static void diff --git a/plugins/mm-modem-huawei-cdma.c b/plugins/mm-modem-huawei-cdma.c index 25c7b373..cc0aa4ef 100644 --- a/plugins/mm-modem-huawei-cdma.c +++ b/plugins/mm-modem-huawei-cdma.c @@ -56,25 +56,53 @@ mm_modem_huawei_cdma_new (const char *device, /* Unsolicited message handlers */ -static void -handle_signal_quality_change (MMSerialPort *port, - GMatchInfo *match_info, - gpointer user_data) +static gint +parse_quality (const char *str, const char *detail) { - MMModemHuaweiCdma *self = MM_MODEM_HUAWEI_CDMA (user_data); - char *str; - long int quality; - - str = g_match_info_fetch (match_info, 1); + long int quality = 0; errno = 0; quality = strtol (str, NULL, 10); if (errno == 0) { quality = CLAMP (quality, 0, 100); - g_debug ("Signal quality: %ld", quality); - mm_generic_cdma_update_signal_quality (MM_GENERIC_CDMA (self), (guint32) quality); + g_debug ("%s: %ld", detail, quality); + return (gint) quality; } + return -1; +} + +static void +handle_1x_quality_change (MMSerialPort *port, + GMatchInfo *match_info, + gpointer user_data) +{ + MMModemHuaweiCdma *self = MM_MODEM_HUAWEI_CDMA (user_data); + char *str; + gint quality; + + str = g_match_info_fetch (match_info, 1); + quality = parse_quality (str, "1X signal quality"); + g_free (str); + + if (quality >= 0) + mm_generic_cdma_update_cdma1x_quality (MM_GENERIC_CDMA (self), (guint32) quality); +} + +static void +handle_evdo_quality_change (MMSerialPort *port, + GMatchInfo *match_info, + gpointer user_data) +{ + MMModemHuaweiCdma *self = MM_MODEM_HUAWEI_CDMA (user_data); + char *str; + gint quality; + + str = g_match_info_fetch (match_info, 1); + quality = parse_quality (str, "EVDO signal quality"); g_free (str); + + if (quality >= 0) + mm_generic_cdma_update_evdo_quality (MM_GENERIC_CDMA (self), (guint32) quality); } /*****************************************************************************/ @@ -233,11 +261,26 @@ grab_port (MMModem *modem, port = mm_generic_cdma_grab_port (MM_GENERIC_CDMA (modem), subsys, name, suggested_type, user_data, error); if (port && MM_IS_SERIAL_PORT (port)) { + gboolean evdo0 = FALSE, evdoA = FALSE; + g_object_set (G_OBJECT (port), MM_PORT_CARRIER_DETECT, FALSE, NULL); + /* 1x signal level */ regex = g_regex_new ("\\r\\n\\^RSSILVL:(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, handle_signal_quality_change, modem, NULL); + mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, handle_1x_quality_change, modem, NULL); g_regex_unref (regex); + + g_object_get (G_OBJECT (modem), + MM_GENERIC_CDMA_EVDO_REV0, &evdo0, + MM_GENERIC_CDMA_EVDO_REVA, &evdoA, + NULL); + + if (evdo0 || evdoA) { + /* EVDO signal level */ + regex = g_regex_new ("\\r\\n\\^HRSSILVL:(\\d+)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, handle_evdo_quality_change, modem, NULL); + g_regex_unref (regex); + } } return !!port; diff --git a/plugins/mm-modem-zte.c b/plugins/mm-modem-zte.c index 536de0ec..95fb1b0a 100644 --- a/plugins/mm-modem-zte.c +++ b/plugins/mm-modem-zte.c @@ -28,6 +28,12 @@ static void modem_init (MMModem *modem_class); G_DEFINE_TYPE_EXTENDED (MMModemZte, mm_modem_zte, MM_TYPE_GENERIC_GSM, 0, G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)) +#define MM_MODEM_ZTE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_ZTE, MMModemZtePrivate)) + +typedef struct { + gboolean init_retried; +} MMModemZtePrivate; + MMModem * mm_modem_zte_new (const char *device, const char *driver, @@ -79,6 +85,10 @@ pin_check_done (MMModem *modem, GError *error, gpointer user_data) } } +static void enable_flash_done (MMSerialPort *port, + GError *error, + gpointer user_data); + static void pre_init_done (MMSerialPort *port, GString *response, @@ -86,10 +96,18 @@ pre_init_done (MMSerialPort *port, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (info->modem); if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); + /* Retry the init string one more time; the modem sometimes throws it away */ + if ( !priv->init_retried + && 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 { /* Now check the PIN explicitly, zte doesn't seem to report that it needs it otherwise */ @@ -116,9 +134,12 @@ enable (MMModem *modem, MMModemFn callback, gpointer user_data) { + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem); MMCallbackInfo *info; MMSerialPort *primary; + priv->init_retried = FALSE; + /* First, reset the previously used CID */ mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); @@ -136,6 +157,21 @@ enable (MMModem *modem, mm_serial_port_flash (primary, 100, enable_flash_done, info); } +static void +disable (MMModem *modem, + MMModemFn callback, + gpointer user_data) +{ + MMModemZtePrivate *priv = MM_MODEM_ZTE_GET_PRIVATE (modem); + MMModem *parent_modem_iface; + + priv->init_retried = FALSE; + + /* Do the normal disable stuff */ + parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); + parent_modem_iface->disable (modem, callback, user_data); +} + static gboolean grab_port (MMModem *modem, const char *subsys, @@ -189,6 +225,7 @@ static void modem_init (MMModem *modem_class) { modem_class->enable = enable; + modem_class->disable = disable; modem_class->grab_port = grab_port; } @@ -200,6 +237,9 @@ mm_modem_zte_init (MMModemZte *self) static void mm_modem_zte_class_init (MMModemZteClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + mm_modem_zte_parent_class = g_type_class_peek_parent (klass); + g_type_class_add_private (object_class, sizeof (MMModemZtePrivate)); } diff --git a/plugins/mm-plugin-huawei.c b/plugins/mm-plugin-huawei.c index b8d8424b..ad799f0a 100644 --- a/plugins/mm-plugin-huawei.c +++ b/plugins/mm-plugin-huawei.c @@ -220,6 +220,7 @@ supports_port (MMPluginBase *base, add_regex (info->serial, "\\r\\n\\^MODE:(\\d),(\\d)\\r\\n", task); add_regex (info->serial, "\\r\\n\\^DSFLOWRPT:(.+)\\r\\n", task); add_regex (info->serial, "\\r\\n\\^BOOT:.+\\r\\n", task); + add_regex (info->serial, "\\r\\r\\^BOOT:.+\\r\\r", task); info->id = g_timeout_add (5000, probe_secondary_timeout, task); |