aboutsummaryrefslogtreecommitdiff
path: root/plugins/mm-modem-wavecom-gsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/mm-modem-wavecom-gsm.c')
-rw-r--r--plugins/mm-modem-wavecom-gsm.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/plugins/mm-modem-wavecom-gsm.c b/plugins/mm-modem-wavecom-gsm.c
index 480afbe3..b76d81d9 100644
--- a/plugins/mm-modem-wavecom-gsm.c
+++ b/plugins/mm-modem-wavecom-gsm.c
@@ -61,6 +61,8 @@ typedef struct {
guint8 supported_ms_classes;
/* Current MS class */
WavecomMSClass current_ms_class;
+ /* Current allowed mode, only for 3G devices */
+ MMModemGsmAllowedMode allowed_mode;
} MMModemWavecomGsmPrivate;
MMModem *
@@ -246,6 +248,225 @@ get_access_technology (MMGenericGsm *gsm,
}
static void
+get_allowed_mode_cb (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = user_data;
+ MMModemWavecomGsmPrivate *priv = MM_MODEM_WAVECOM_GSM_GET_PRIVATE (info->modem);
+ gint read_mode = -1;
+ gchar *mode_str = NULL;
+ gchar *prefer_str = NULL;
+ GRegex *r = NULL;
+ GMatchInfo *match_info = NULL;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ /* Possible responses:
+ * +WWSM: 0 (2G only)
+ * +WWSM: 1 (3G only)
+ * +WWSM: 2,0 (Any)
+ * +WWSM: 2,1 (2G preferred)
+ * +WWSM: 2,2 (3G preferred)
+ */
+ r = g_regex_new ("\\r\\n\\+WWSM: ([0-2])(,([0-2]))?.*$", 0, 0, NULL);
+ if (r && g_regex_match_full (r, response->str, response->len, 0, 0, &match_info, NULL)) {
+ mode_str = g_match_info_fetch (match_info, 1);
+ prefer_str = g_match_info_fetch (match_info, 3); /* 3, to avoid the comma */
+
+ if (mode_str) {
+ switch (atoi (mode_str)) {
+ case 0:
+ if (!prefer_str)
+ read_mode = MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY;
+ break;
+ case 1:
+ if (!prefer_str)
+ read_mode = MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY;
+ break;
+ case 2:
+ if (prefer_str) {
+ switch (atoi (prefer_str)) {
+ case 0:
+ read_mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
+ break;
+ case 1:
+ read_mode = MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED;
+ break;
+ case 2:
+ read_mode = MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED;
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+ }
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+ }
+ }
+
+ if (read_mode < 0) {
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Unexpected wireless data service reply: '%s' "
+ "(mode: '%s', prefer: '%s')",
+ response->str,
+ mode_str ? mode_str : "none",
+ prefer_str ? prefer_str : "none");
+ } else {
+ priv->allowed_mode = (guint)read_mode;
+ mm_callback_info_set_result (info,
+ GUINT_TO_POINTER (priv->allowed_mode),
+ NULL);
+ }
+
+ if (r)
+ g_regex_unref (r);
+ if (match_info)
+ g_match_info_free (match_info);
+ g_free (mode_str);
+ g_free (prefer_str);
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+get_allowed_mode (MMGenericGsm *gsm,
+ MMModemUIntFn callback,
+ gpointer user_data)
+{
+ MMModemWavecomGsmPrivate *priv = MM_MODEM_WAVECOM_GSM_GET_PRIVATE (gsm);
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
+
+ /* For 3G devices, query WWSM status */
+ if (priv->supported_ms_classes & WAVECOM_MS_CLASS_A) {
+ MMAtSerialPort *port;
+
+ 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, "+WWSM?", 3, get_allowed_mode_cb, info);
+ return;
+ }
+
+ /* For 2G devices, just return cached value */
+ mm_callback_info_set_result (info,
+ GUINT_TO_POINTER (priv->allowed_mode),
+ NULL);
+ mm_callback_info_schedule (info);
+}
+
+static void
+set_allowed_mode_cb (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemWavecomGsmPrivate *priv = MM_MODEM_WAVECOM_GSM_GET_PRIVATE (info->modem);
+
+ if (error)
+ info->error = g_error_copy (error);
+ else
+ priv->allowed_mode = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "new-mode"));
+
+ mm_callback_info_schedule (info);
+}
+
+static void
+set_allowed_mode (MMGenericGsm *gsm,
+ MMModemGsmAllowedMode mode,
+ MMModemFn callback,
+ gpointer user_data)
+{
+ MMModemWavecomGsmPrivate *priv = MM_MODEM_WAVECOM_GSM_GET_PRIVATE (gsm);
+ MMCallbackInfo *info;
+
+ info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data);
+
+ /* For 3G devices, go on with WWSM */
+ if (priv->supported_ms_classes & WAVECOM_MS_CLASS_A) {
+ MMAtSerialPort *port;
+ GString *cmd;
+ gint net = -1;
+ gint prefer = -1;
+
+ /* Get port */
+ port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
+ if (!port) {
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_callback_info_set_data (info,
+ "new-mode",
+ GUINT_TO_POINTER (mode),
+ NULL);
+
+ switch (mode) {
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ net = 2;
+ prefer = 0;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ net = 2;
+ prefer = 1;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_PREFERRED:
+ net = 2;
+ prefer = 2;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
+ net = 0;
+ break;
+ case MM_MODEM_GSM_ALLOWED_MODE_3G_ONLY:
+ net = 1;
+ break;
+ }
+
+ cmd = g_string_new ("+WWSM=");
+ g_string_append_printf (cmd, "%d", net);
+ if (net == 2)
+ g_string_append_printf (cmd, ",%d", prefer);
+ mm_at_serial_port_queue_command (port, cmd->str, 3, set_allowed_mode_cb, info);
+ g_string_free (cmd, TRUE);
+
+ return;
+ }
+
+ /* For non-3G devices, allow only 2G-related allowed modes */
+ switch (mode) {
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_PREFERRED:
+ case MM_MODEM_GSM_ALLOWED_MODE_2G_ONLY:
+ case MM_MODEM_GSM_ALLOWED_MODE_ANY:
+ priv->allowed_mode = mode;
+ break;
+ default:
+ info->error = g_error_new (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Cannot set desired allowed mode, "
+ "not a 3G device");
+ break;
+ }
+
+ mm_callback_info_schedule (info);
+}
+
+static void
enable_complete (MMGenericGsm *gsm,
GError *error,
MMCallbackInfo *info)
@@ -479,6 +700,7 @@ mm_modem_wavecom_gsm_init (MMModemWavecomGsm *self)
/* Set defaults */
priv->supported_ms_classes = 0; /* This is a bitmask, so empty */
priv->current_ms_class = WAVECOM_MS_CLASS_UNKNOWN;
+ priv->allowed_mode = MM_MODEM_GSM_ALLOWED_MODE_ANY;
}
static void
@@ -501,6 +723,8 @@ mm_modem_wavecom_gsm_class_init (MMModemWavecomGsmClass *klass)
MM_GENERIC_GSM_FLOW_CONTROL_CMD);
gsm_class->do_enable_power_up_done = do_enable_power_up_done;
+ gsm_class->set_allowed_mode = set_allowed_mode;
+ gsm_class->get_allowed_mode = get_allowed_mode;
gsm_class->get_access_technology = get_access_technology;
}