summaryrefslogtreecommitdiff
path: root/plugins/mm-modem-mbm.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/mm-modem-mbm.c')
-rw-r--r--plugins/mm-modem-mbm.c578
1 files changed, 379 insertions, 199 deletions
diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c
index 686b35c..7f6bc9c 100644
--- a/plugins/mm-modem-mbm.c
+++ b/plugins/mm-modem-mbm.c
@@ -1,11 +1,13 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
- * Copyright (C) 2008 Ericsson AB
+ * Copyright (C) 2008 - 2010 Ericsson AB
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
*
* Author: Per Hallsmark <per.hallsmark@ericsson.com>
* Bjorn Runaker <bjorn.runaker@ericsson.com>
* Torgny Johansson <torgny.johansson@ericsson.com>
* Jonas Sjöquist <jonas.sjoquist@ericsson.com>
+ * Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,10 +19,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
*/
#include <stdlib.h>
@@ -30,17 +28,20 @@
#include "mm-modem-mbm.h"
#include "mm-modem-simple.h"
+#include "mm-modem-gsm-card.h"
#include "mm-errors.h"
#include "mm-callback-info.h"
static void modem_init (MMModem *modem_class);
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
static void modem_simple_init (MMModemSimple *class);
+static void modem_gsm_card_init (MMModemGsmCard *class);
G_DEFINE_TYPE_EXTENDED (MMModemMbm, mm_modem_mbm, MM_TYPE_GENERIC_GSM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_CARD, modem_gsm_card_init))
#define MM_MODEM_MBM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_MBM, MMModemMbmPrivate))
@@ -54,11 +55,6 @@ G_DEFINE_TYPE_EXTENDED (MMModemMbm, mm_modem_mbm, MM_TYPE_GENERIC_GSM, 0,
#define MBM_NETWORK_MODE_2G 5
#define MBM_NETWORK_MODE_3G 6
-#define MBM_ERINFO_2G_GPRS 1
-#define MBM_ERINFO_2G_EGPRS 2
-#define MBM_ERINFO_3G_UMTS 1
-#define MBM_ERINFO_3G_HSDPA 2
-
typedef struct {
guint reg_id;
gboolean have_emrdy;
@@ -83,12 +79,6 @@ mbm_modem_authenticate (MMModemMbm *self,
const char *password,
gpointer user_data);
-static const char *
-mbm_simple_get_string_property (GHashTable *properties, const char *name, GError **error);
-
-static uint
-mbm_simple_get_uint_property (GHashTable *properties, const char *name, GError **error);
-
MMModem *
mm_modem_mbm_new (const char *device,
const char *driver,
@@ -124,16 +114,9 @@ register_done (gpointer user_data)
MMModemMbm *self = MM_MODEM_MBM (reg_data->modem);
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
MMModemGsmNetwork *parent_modem_iface;
- MMSerialPort *primary;
priv->reg_id = 0;
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
-
- mm_serial_port_queue_command (primary, "+CREG=1", 3, NULL, NULL);
- mm_serial_port_queue_command (primary, "+CMER=3,0,0,1", 3, NULL, NULL);
-
parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GSM_NETWORK_GET_INTERFACE (self));
parent_modem_iface->do_register (MM_MODEM_GSM_NETWORK (self),
reg_data->network_id,
@@ -167,21 +150,16 @@ do_register (MMModemGsmNetwork *modem,
}
static int
-mbm_parse_network_mode (MMModemGsmMode network_mode)
+mbm_parse_allowed_mode (MMModemGsmAllowedMode network_mode)
{
switch (network_mode) {
- case MM_MODEM_GSM_MODE_ANY:
- case MM_MODEM_GSM_MODE_3G_PREFERRED:
- case MM_MODEM_GSM_MODE_2G_PREFERRED:
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
return MBM_NETWORK_MODE_ANY;
- case MM_MODEM_GSM_MODE_GPRS:
- case MM_MODEM_GSM_MODE_EDGE:
- case MM_MODEM_GSM_MODE_2G_ONLY:
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
return MBM_NETWORK_MODE_2G;
- case MM_MODEM_GSM_MODE_3G_ONLY:
- case MM_MODEM_GSM_MODE_HSDPA:
- case MM_MODEM_GSM_MODE_HSUPA:
- case MM_MODEM_GSM_MODE_HSPA:
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
return MBM_NETWORK_MODE_3G;
default:
return MBM_NETWORK_MODE_ANY;
@@ -189,7 +167,7 @@ mbm_parse_network_mode (MMModemGsmMode network_mode)
}
static void
-mbm_set_network_mode_done (MMSerialPort *port,
+mbm_set_allowed_mode_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -203,92 +181,144 @@ mbm_set_network_mode_done (MMSerialPort *port,
}
static void
-set_network_mode (MMModemGsmNetwork *modem,
- MMModemGsmMode mode,
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
char *command;
- MMSerialPort *primary;
+ MMAtSerialPort *port;
- info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
+ info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
- command = g_strdup_printf ("+CFUN=%d", mbm_parse_network_mode (mode));
- mm_serial_port_queue_command (primary, command, 3, mbm_set_network_mode_done, info);
+ command = g_strdup_printf ("+CFUN=%d", mbm_parse_allowed_mode (mode));
+ mm_at_serial_port_queue_command (port, command, 3, mbm_set_allowed_mode_done, info);
g_free (command);
}
static void
-get_network_mode_done (MMSerialPort *port,
+mbm_erinfo_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+ char *str;
+
+ str = g_match_info_fetch (info, 2);
+ if (str) {
+ switch (atoi (str)) {
+ case 1:
+ act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
+ break;
+ case 2:
+ act = MM_MODEM_GSM_ACCESS_TECH_EDGE;
+ break;
+ default:
+ break;
+ }
+ }
+ g_free (str);
+
+ /* 3G modes take precedence */
+ str = g_match_info_fetch (info, 3);
+ if (str) {
+ switch (atoi (str)) {
+ case 1:
+ act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
+ break;
+ case 2:
+ act = MM_MODEM_GSM_ACCESS_TECH_HSDPA;
+ break;
+ default:
+ break;
+ }
+ }
+ g_free (str);
+
+ mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
+}
+
+static void
+get_allowed_mode_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- char *erinfo;
- int mode = 0, gsm = 0, umts = 0;
gboolean parsed = FALSE;
- if (error) {
+ if (error)
info->error = g_error_copy (error);
- goto done;
- }
-
- erinfo = strstr (response->str, "*ERINFO:");
- if (!erinfo)
- goto done;
-
- if (sscanf (erinfo + 8, "%d,%d,%d", &mode, &gsm, &umts) != 3)
- goto done;
+ else if (!g_str_has_prefix (response->str, "CFUN: ")) {
+ MMModemGsmAllowedMode mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ int a;
- if (gsm || umts) {
- MMModemGsmMode mm_mode = MM_MODEM_GSM_MODE_ANY;
-
- if (gsm == MBM_ERINFO_2G_GPRS)
- mm_mode = MM_MODEM_GSM_MODE_GPRS;
- else if (gsm == MBM_ERINFO_2G_EGPRS)
- mm_mode = MM_MODEM_GSM_MODE_EDGE;
- else if (umts == MBM_ERINFO_3G_UMTS)
- mm_mode = MM_MODEM_GSM_MODE_UMTS;
- else if (umts == MBM_ERINFO_3G_HSDPA)
- mm_mode = MM_MODEM_GSM_MODE_HSDPA;
- else
- g_debug ("%s unknown network mode %d,%d", __FUNCTION__, gsm, umts);
+ a = atoi (response->str + 6);
+ if (a == MBM_NETWORK_MODE_2G)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ else if (a == MBM_NETWORK_MODE_3G)
+ mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
- mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_mode), NULL);
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (mode), NULL);
parsed = TRUE;
}
-done:
- if (!error && !parsed) {
+ if (!error && !parsed)
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Could not parse network mode results");
- }
+ "Could not parse allowed mode results");
mm_callback_info_schedule (info);
}
static void
-get_network_mode (MMModemGsmNetwork *modem,
+get_allowed_mode (MMGenericGsm *gsm,
MMModemUIntFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *port;
- info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
- g_assert (primary);
- mm_serial_port_queue_command (primary, "*ERINFO?", 3, get_network_mode_done, info);
+ info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
+
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "+CFUN?", 3, get_allowed_mode_done, info);
}
/*****************************************************************************/
/* Simple Modem class override functions */
/*****************************************************************************/
+static const char *
+mbm_simple_get_string_property (GHashTable *properties, const char *name, GError **error)
+{
+ GValue *value;
+
+ value = (GValue *) g_hash_table_lookup (properties, name);
+ if (!value)
+ return NULL;
+
+ if (G_VALUE_HOLDS_STRING (value))
+ return g_value_get_string (value);
+
+ g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
+ "Invalid property type for '%s': %s (string expected)",
+ name, G_VALUE_TYPE_NAME (value));
+
+ return NULL;
+}
+
static void
simple_connect (MMModemSimple *simple,
GHashTable *properties,
@@ -298,14 +328,10 @@ simple_connect (MMModemSimple *simple,
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (simple);
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
MMModemSimple *parent_iface;
- uint network_mode = 0;
priv->username = mbm_simple_get_string_property (properties, "username", &info->error);
priv->password = mbm_simple_get_string_property (properties, "password", &info->error);
- network_mode = mbm_simple_get_uint_property (properties, "network_mode", &info->error);
- priv->network_mode = mbm_parse_network_mode (network_mode);
-
parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple));
parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info);
}
@@ -315,18 +341,22 @@ simple_connect (MMModemSimple *simple,
/*****************************************************************************/
static void
-mbm_enable_done (MMSerialPort *port,
+mbm_enable_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ /* Start unsolicited signal strength and access technology responses */
+ mm_at_serial_port_queue_command (port, "+CMER=3,0,0,1", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "*ERINFO=1", 3, NULL, NULL);
+
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
}
static void
-mbm_enap0_done (MMSerialPort *port,
+mbm_enap0_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -339,12 +369,12 @@ mbm_enap0_done (MMSerialPort *port,
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);
+ mm_at_serial_port_queue_command (port, command, 3, mbm_enable_done, info);
g_free (command);
}
static void
-mbm_init_done (MMSerialPort *port,
+mbm_init_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -360,17 +390,17 @@ mbm_init_done (MMSerialPort *port,
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_at_serial_port_queue_command (port, "*ENAP=0", 3, mbm_enap0_done, info);
}
static void
-do_init (MMSerialPort *port, MMCallbackInfo *info)
+do_init (MMAtSerialPort *port, MMCallbackInfo *info)
{
- mm_serial_port_queue_command (port, "&F E0 V1 X4 &C1 +CMEE=1", 3, mbm_init_done, info);
+ mm_at_serial_port_queue_command (port, "&F E0 V1 X4 &C1 +CMEE=1", 3, mbm_init_done, info);
}
static void
-mbm_emrdy_done (MMSerialPort *port,
+mbm_emrdy_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -378,11 +408,9 @@ mbm_emrdy_done (MMSerialPort *port,
MMCallbackInfo *info = user_data;
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
- if ( error
- && error->domain == MM_SERIAL_ERROR
- && error->code == MM_SERIAL_RESPONSE_TIMEOUT) {
+ if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT))
g_warning ("%s: timed out waiting for EMRDY response.", __func__);
- } else
+ else
priv->have_emrdy = TRUE;
do_init (port, info);
@@ -393,18 +421,18 @@ do_enable (MMGenericGsm *self, MMModemFn callback, gpointer user_data)
{
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
MMCallbackInfo *info;
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
- primary = mm_generic_gsm_get_port (self, MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
if (priv->have_emrdy) {
/* Modem is ready, no need to check EMRDY */
do_init (primary, info);
} else
- mm_serial_port_queue_command (primary, "*EMRDY?", 5, mbm_emrdy_done, info);
+ mm_at_serial_port_queue_command (primary, "*EMRDY?", 5, mbm_emrdy_done, info);
}
typedef struct {
@@ -414,10 +442,10 @@ typedef struct {
} DisableInfo;
static void
-disable_creg_cmer_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+disable_unsolicited_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMModem *parent_modem_iface;
@@ -433,7 +461,7 @@ disable (MMModem *modem,
MMModemFn callback,
gpointer user_data)
{
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
DisableInfo *info;
info = g_malloc0 (sizeof (DisableInfo));
@@ -441,11 +469,11 @@ disable (MMModem *modem,
info->user_data = user_data;
info->modem = modem;
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
g_assert (primary);
- /* Turn off unsolicited +CIEV signal strength indicator */
- mm_serial_port_queue_command (primary, "+CREG=0;+CMER=0", 5, disable_creg_cmer_done, info);
+ /* Turn off unsolicited responses */
+ mm_at_serial_port_queue_command (primary, "+CMER=0;*ERINFO=0", 5, disable_unsolicited_done, info);
}
static void
@@ -466,29 +494,77 @@ do_connect (MMModem *modem,
}
static void
-disconnect (MMModem *modem,
- MMModemFn callback,
- gpointer user_data)
+do_disconnect (MMGenericGsm *gsm,
+ gint cid,
+ MMModemFn callback,
+ gpointer user_data)
{
- MMCallbackInfo *info;
- MMSerialPort *primary;
-
- mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE);
+ MMAtSerialPort *primary;
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
- mm_serial_port_queue_command (primary, "*ENAP=0", 3, NULL, NULL);
+ mm_at_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);
+ MM_GENERIC_GSM_CLASS (mm_modem_mbm_parent_class)->do_disconnect (gsm, cid, callback, user_data);
+}
- info = mm_callback_info_new (modem, callback, user_data);
+static void
+factory_reset_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+
+ mm_serial_port_close (MM_SERIAL_PORT (port));
mm_callback_info_schedule (info);
}
+static void
+factory_reset (MMModem *self,
+ const char *code,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMAtSerialPort *port;
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (self, callback, user_data);
+
+ /* Ensure we have a usable port to use for the command */
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (self), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* Modem may not be enabled yet, which sometimes can't be done until
+ * the device has been unlocked. In this case we have to open the port
+ * ourselves.
+ */
+ if (!mm_serial_port_open (MM_SERIAL_PORT (port), &info->error)) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_at_serial_port_queue_command (port, "&F +CMEE=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+COPS=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CR=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CRC=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CREG=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CMER=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "*EPEE=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CNMI=2, 0, 0, 0, 0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CGREG=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "*EIAD=0", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CGSMS=3", 3, NULL, NULL);
+ mm_at_serial_port_queue_command (port, "+CSCA=\"\",129", 3, factory_reset_done, info);
+}
+
/*****************************************************************************/
static void
-mbm_emrdy_received (MMSerialPort *port,
+mbm_emrdy_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
@@ -496,7 +572,7 @@ mbm_emrdy_received (MMSerialPort *port,
}
static void
-mbm_pacsp_received (MMSerialPort *port,
+mbm_pacsp_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
@@ -504,65 +580,78 @@ mbm_pacsp_received (MMSerialPort *port,
}
static void
-mbm_ciev_received (MMSerialPort *port,
+mbm_ciev_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
int quality = 0, ind = 0;
- const char *str;
+ char *str;
str = g_match_info_fetch (info, 1);
if (str)
ind = atoi (str);
+ g_free (str);
if (ind == MBM_SIGNAL_INDICATOR) {
str = g_match_info_fetch (info, 2);
if (str) {
quality = atoi (str);
- mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (user_data), quality * 20);
+ mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (user_data), quality * 20);
}
+ g_free (str);
}
}
static void
-mbm_do_connect_done (MMModemMbm *self)
+mbm_do_connect_done (MMModemMbm *self, gboolean success)
{
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
- if (priv->pending_connect_info) {
+ if (!priv->pending_connect_info)
+ return;
+
+ if (success)
mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), NULL, priv->pending_connect_info);
- priv->pending_connect_info = NULL;
+ else {
+ GError *connect_error;
+
+ connect_error = mm_modem_connect_error_for_code (MM_MODEM_CONNECT_ERROR_BUSY);
+ mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), connect_error, priv->pending_connect_info);
+ g_error_free (connect_error);
}
+ priv->pending_connect_info = NULL;
}
static void
-mbm_e2nap_received (MMSerialPort *port,
+mbm_e2nap_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
int state = 0;
- const char *str;
+ char *str;
str = g_match_info_fetch (info, 1);
if (str)
state = atoi (str);
-
- if (MBM_E2NAP_DISCONNECTED == state)
- g_debug ("%s, disconnected", __func__);
- else if (MBM_E2NAP_CONNECTED == state) {
- g_debug ("%s, connected", __func__);
- mbm_do_connect_done (MM_MODEM_MBM (user_data));
+ g_free (str);
+
+ if (MBM_E2NAP_DISCONNECTED == state) {
+ g_debug ("%s: disconnected", __func__);
+ mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE);
+ } else if (MBM_E2NAP_CONNECTED == state) {
+ g_debug ("%s: connected", __func__);
+ mbm_do_connect_done (MM_MODEM_MBM (user_data), TRUE);
} else if (MBM_E2NAP_CONNECTING == state)
- g_debug("%s, connecting", __func__);
+ g_debug("%s: connecting", __func__);
else {
/* Should not happen */
- g_debug("%s, undefined e2nap status",__FUNCTION__);
- g_assert_not_reached ();
+ g_debug("%s: unhandled E2NAP state %d", __func__, state);
+ mbm_do_connect_done (MM_MODEM_MBM (user_data), FALSE);
}
}
static void
-enap_poll_response (MMSerialPort *port,
+enap_poll_response (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
@@ -597,20 +686,21 @@ static gboolean
enap_poll (gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
- MMSerialPort *port = mm_generic_gsm_get_port (MM_GENERIC_GSM (info->modem), MM_PORT_TYPE_PRIMARY);
+ MMAtSerialPort *port;
+ port = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (info->modem), MM_PORT_TYPE_PRIMARY);
g_assert (port);
- mm_serial_port_queue_command (port, "AT*ENAP?", 3, enap_poll_response, user_data);
+ mm_at_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;
}
static void
-enap_done (MMSerialPort *port,
- GString *response,
- GError *error,
- gpointer user_data)
+enap_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
guint tid;
@@ -623,12 +713,11 @@ enap_done (MMSerialPort *port,
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
mbm_auth_done (MMSerialPort *port,
- GString *response,
+ GByteArray *response,
GError *error,
gpointer user_data)
{
@@ -643,8 +732,11 @@ mbm_auth_done (MMSerialPort *port,
}
cid = mm_generic_gsm_get_cid (modem);
+
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "AT*E2NAP=1", 3, NULL, NULL);
+
command = g_strdup_printf ("AT*ENAP=1,%d", cid);
- mm_serial_port_queue_command (port, command, 3, enap_done, user_data);
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), command, 3, enap_done, user_data);
g_free (command);
}
@@ -654,61 +746,133 @@ mbm_modem_authenticate (MMModemMbm *self,
const char *password,
gpointer user_data)
{
- MMSerialPort *primary;
+ MMAtSerialPort *primary;
- primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
g_assert (primary);
if (username || password) {
- char *command;
+ GByteArray *command;
+ MMModemCharset cur_set;
+ char *tmp;
+
+ /* F3507g at least wants the username and password to be sent in the
+ * modem's current character set.
+ */
+ cur_set = mm_generic_gsm_get_charset (MM_GENERIC_GSM (self));
+
+ command = g_byte_array_sized_new (75);
+ tmp = g_strdup_printf ("AT*EIAAUW=%d,1,", mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)));
+ g_byte_array_append (command, (const guint8 *) tmp, strlen (tmp));
+ g_free (tmp);
+
+ if (username)
+ mm_modem_charset_byte_array_append (command, username, TRUE, cur_set);
+ else
+ g_byte_array_append (command, (const guint8 *) "\"\"", 2);
- command = g_strdup_printf ("*EIAAUW=%d,1,\"%s\",\"%s\"",
- mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)),
- username ? username : "",
- password ? password : "");
+ g_byte_array_append (command, (const guint8 *) ",", 1);
- mm_serial_port_queue_command (primary, command, 3, mbm_auth_done, user_data);
- g_free (command);
+ if (password)
+ mm_modem_charset_byte_array_append (command, password, TRUE, cur_set);
+ else
+ g_byte_array_append (command, (const guint8 *) "\"\"", 2);
+
+ g_byte_array_append (command, (const guint8 *) "\r", 1);
+
+ mm_serial_port_queue_command (MM_SERIAL_PORT (primary),
+ command,
+ TRUE,
+ 3,
+ mbm_auth_done,
+ user_data);
} else
- mbm_auth_done (primary, NULL, NULL, user_data);
+ mbm_auth_done (MM_SERIAL_PORT (primary), NULL, NULL, user_data);
}
-static const char *
-mbm_simple_get_string_property (GHashTable *properties, const char *name, GError **error)
+/*****************************************************************************/
+
+static void
+send_epin_done (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
{
- GValue *value;
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *pin_type;
+ int attempts_left = 0;
- value = (GValue *) g_hash_table_lookup (properties, name);
- if (!value)
- return NULL;
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
- if (G_VALUE_HOLDS_STRING (value))
- return g_value_get_string (value);
+ pin_type = mm_callback_info_get_data (info, "pin_type");
- g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Invalid property type for '%s': %s (string expected)",
- name, G_VALUE_TYPE_NAME (value));
+ if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN))
+ sscanf (response->str, "*EPIN: %d", &attempts_left);
+ else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PUK))
+ sscanf (response->str, "*EPIN: %*d, %d", &attempts_left);
+ else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PIN2))
+ sscanf (response->str, "*EPIN: %*d, %*d, %d", &attempts_left);
+ else if (strstr (pin_type, MM_MODEM_GSM_CARD_SIM_PUK2))
+ sscanf (response->str, "*EPIN: %*d, %*d, %*d, %d", &attempts_left);
+ else {
+ g_debug ("%s: unhandled pin type '%s'", __func__, pin_type);
- return NULL;
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unhandled PIN type");
+ }
+
+ if (attempts_left < 0 || attempts_left > 998) {
+ info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Invalid PIN attempts left %d", attempts_left);
+ attempts_left = 0;
+ }
+
+ mm_callback_info_set_result (info, GUINT_TO_POINTER (attempts_left), NULL);
+
+done:
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+ mm_callback_info_schedule (info);
}
-static uint
-mbm_simple_get_uint_property (GHashTable *properties, const char *name, GError **error)
+static void
+mbm_get_unlock_retries (MMModemGsmCard *modem,
+ const char *pin_type,
+ MMModemUIntFn callback,
+ gpointer user_data)
{
- GValue *value;
+ MMAtSerialPort *port;
+ char *command;
+ MMCallbackInfo *info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
- value = (GValue *) g_hash_table_lookup (properties, name);
- if (!value)
- return 0;
+ g_debug ("%s: pin type '%s'", __func__, pin_type);
- if (G_VALUE_HOLDS_UINT (value))
- return g_value_get_uint (value);
+ /* Ensure we have a usable port to use for the command */
+ port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
- g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
- "Invalid property type for '%s': %s (uint expected)",
- name, G_VALUE_TYPE_NAME (value));
+ /* Modem may not be enabled yet, which sometimes can't be done until
+ * the device has been unlocked. In this case we have to open the port
+ * ourselves.
+ */
+ if (!mm_serial_port_open (MM_SERIAL_PORT (port), &info->error)) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* if the modem have not yet been enabled we need to make sure echoing is turned off */
+ command = g_strdup_printf ("E0");
+ mm_at_serial_port_queue_command (port, command, 3, NULL, NULL);
+ g_free (command);
- return 0;
+ mm_callback_info_set_data (info, "pin_type", g_strdup (pin_type), g_free);
+
+ command = g_strdup_printf ("*EPIN?");
+ mm_at_serial_port_queue_command (port, command, 3, send_epin_done, info);
+ g_free (command);
}
/*****************************************************************************/
@@ -727,43 +891,52 @@ grab_port (MMModem *modem,
if (!strcmp (subsys, "tty")) {
if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
- if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY))
+ if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
ptype = MM_PORT_TYPE_PRIMARY;
- else if (!mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_SECONDARY))
+ else if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_SECONDARY))
ptype = MM_PORT_TYPE_SECONDARY;
} else
ptype = suggested_type;
}
port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
- if (port && MM_IS_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) {
+ if (port && MM_IS_AT_SERIAL_PORT (port)) {
GRegex *regex;
- mm_generic_gsm_set_unsolicited_registration (MM_GENERIC_GSM (modem), TRUE);
+ if (ptype == MM_PORT_TYPE_PRIMARY) {
+ regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_e2nap_received, modem, NULL);
+ g_regex_unref (regex);
- regex = g_regex_new ("\\r\\n\\*EMRDY: \\d\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_emrdy_received, modem, NULL);
- g_regex_unref (regex);
+ /* Catch the extended error status bit of the command too */
+ regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d),.*\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_e2nap_received, modem, NULL);
+ g_regex_unref (regex);
+ }
- regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_e2nap_received, modem, NULL);
+ regex = g_regex_new ("\\r\\n\\*EMRDY: \\d\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_emrdy_received, modem, NULL);
g_regex_unref (regex);
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);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_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);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_ciev_received, modem, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_ciev_received, modem, NULL);
g_regex_unref (regex);
/* also consume unsolicited mbm messages we are not interested in them - see LP: #416418 */
- regex = g_regex_new ("\\R\\*ESTKSMENU:.*\\R", G_REGEX_RAW | G_REGEX_OPTIMIZE | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF, G_REGEX_MATCH_NEWLINE_CRLF, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, modem, NULL);
+ regex = g_regex_new ("\\R\\*ESTKSMENU:.*\\R", G_REGEX_RAW | G_REGEX_OPTIMIZE | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF, G_REGEX_MATCH_NEWLINE_CRLF, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
g_regex_unref (regex);
regex = g_regex_new ("\\r\\n\\*EMWI: (\\d),(\\d).*\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
- mm_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
+ g_regex_unref (regex);
+
+ regex = g_regex_new ("\\r\\n\\*ERINFO:\\s*(\\d),(\\d),(\\d).*\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_erinfo_received, modem, NULL);
g_regex_unref (regex);
}
@@ -773,11 +946,15 @@ grab_port (MMModem *modem,
/*****************************************************************************/
static void
+modem_gsm_card_init (MMModemGsmCard *class)
+{
+ class->get_unlock_retries = mbm_get_unlock_retries;
+}
+
+static void
modem_gsm_network_init (MMModemGsmNetwork *class)
{
class->do_register = do_register;
- class->get_network_mode = get_network_mode;
- class->set_network_mode = set_network_mode;
}
static void
@@ -792,7 +969,7 @@ modem_init (MMModem *modem_class)
modem_class->grab_port = grab_port;
modem_class->disable = disable;
modem_class->connect = do_connect;
- modem_class->disconnect = disconnect;
+ modem_class->factory_reset = factory_reset;
}
static void
@@ -826,5 +1003,8 @@ mm_modem_mbm_class_init (MMModemMbmClass *klass)
object_class->finalize = finalize;
gsm_class->do_enable = do_enable;
+ gsm_class->do_disconnect = do_disconnect;
+ gsm_class->get_allowed_mode = get_allowed_mode;
+ gsm_class->set_allowed_mode = set_allowed_mode;
}