aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/Makefile.am4
-rw-r--r--plugins/mm-modem-sierra-cdma.c298
-rw-r--r--plugins/mm-modem-sierra-cdma.h45
-rw-r--r--plugins/mm-plugin-sierra.c12
4 files changed, 352 insertions, 7 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index e571191b..571c6de3 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -147,7 +147,9 @@ libmm_plugin_sierra_la_SOURCES = \
mm-plugin-sierra.c \
mm-plugin-sierra.h \
mm-modem-sierra-gsm.c \
- mm-modem-sierra-gsm.h
+ mm-modem-sierra-gsm.h \
+ mm-modem-sierra-cdma.c \
+ mm-modem-sierra-cdma.h
libmm_plugin_sierra_la_CPPFLAGS = \
$(MM_CFLAGS) \
diff --git a/plugins/mm-modem-sierra-cdma.c b/plugins/mm-modem-sierra-cdma.c
new file mode 100644
index 00000000..897c8648
--- /dev/null
+++ b/plugins/mm-modem-sierra-cdma.c
@@ -0,0 +1,298 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
+#include <gudev/gudev.h>
+
+#include "mm-modem-sierra-cdma.h"
+#include "mm-errors.h"
+#include "mm-callback-info.h"
+#include "mm-serial-port.h"
+#include "mm-serial-parsers.h"
+
+static gpointer mm_modem_sierra_cdma_parent_class = NULL;
+
+#define MM_MODEM_SIERRA_CDMA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_SIERRA_CDMA, MMModemSierraCdmaPrivate))
+
+typedef enum {
+ SYS_MODE_UNKNOWN,
+ SYS_MODE_CDMA_1X,
+ SYS_MODE_EVDO_REV0,
+ SYS_MODE_EVDO_REVA
+} SysMode;
+
+typedef struct {
+ SysMode sys_mode;
+} MMModemSierraCdmaPrivate;
+
+MMModem *
+mm_modem_sierra_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ gboolean evdo_rev0,
+ gboolean evdo_revA)
+{
+ g_return_val_if_fail (device != NULL, NULL);
+ g_return_val_if_fail (driver != NULL, NULL);
+ g_return_val_if_fail (plugin != NULL, NULL);
+
+ return MM_MODEM (g_object_new (MM_TYPE_MODEM_SIERRA_CDMA,
+ MM_MODEM_MASTER_DEVICE, device,
+ MM_MODEM_DRIVER, driver,
+ MM_MODEM_PLUGIN, plugin,
+ MM_GENERIC_CDMA_EVDO_REV0, evdo_rev0,
+ MM_GENERIC_CDMA_EVDO_REVA, evdo_revA,
+ NULL));
+}
+
+/*****************************************************************************/
+
+#define MODEM_REG_TAG "Modem has registered"
+#define ROAM_1X_TAG "1xRoam:"
+#define ROAM_EVDO_TAG "HDRRoam:"
+#define SYS_MODE_TAG "Sys Mode:"
+#define SYS_MODE_NO_SERVICE_TAG "NO SRV"
+#define SYS_MODE_EVDO_TAG "HDR"
+#define SYS_MODE_1X_TAG "1x"
+#define EVDO_REV_TAG "HDR Revision:"
+
+static gboolean
+get_roam_value (const char *reply, const char *tag, gboolean *roaming)
+{
+ char *p;
+
+ p = strstr (reply, tag);
+ if (!p)
+ return FALSE;
+
+ p += strlen (tag);
+ while (*p && isspace (*p))
+ p++;
+ if (*p == '1') {
+ *roaming = TRUE;
+ return TRUE;
+ } else if (*p == '0') {
+ *roaming = FALSE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+status_done (MMSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemSierraCdmaPrivate *priv = MM_MODEM_SIERRA_CDMA_GET_PRIVATE (info->modem);
+ char **lines, **iter;
+ gboolean registered = FALSE;
+ SysMode evdo_mode = SYS_MODE_UNKNOWN;
+ SysMode sys_mode = SYS_MODE_UNKNOWN;
+ gboolean cdma_1x_set = FALSE, evdo_set = FALSE;
+
+ if (error) {
+ info->error = g_error_copy (error);
+ goto done;
+ }
+
+ lines = g_strsplit_set (response->str, "\n\r", 0);
+ if (!lines) {
+ /* Whatever, just use default registration state */
+ goto done;
+ }
+
+ /* Sierra CDMA parts have two general formats depending on whether they
+ * support EVDO or not. EVDO parts report both 1x and EVDO roaming status
+ * while of course 1x parts only report 1x status. Some modems also do not
+ * report the Roaming information (MP 555 GPS).
+ *
+ *
+ * Unregistered MC5725:
+ * -----------------------
+ * at!status
+ * Current band: PCS CDMA
+ * Current channel: 350
+ * SID: 0 NID: 0 1xRoam: 0 HDRRoam: 0
+ * Temp: 33 State: 100 Sys Mode: NO SRV
+ * Pilot NOT acquired
+ * Modem has NOT registered
+ *
+ * OK
+ *
+ * Registered MC5725:
+ * -----------------------
+ * Current band: Cellular Sleep
+ * Current channel: 775
+ * SID: 30 NID: 2 1xRoam: 0 HDRRoam: 0
+ * Temp: 29 State: 200 Sys Mode: HDR
+ * Pilot acquired
+ * Modem has registered
+ * HDR Revision: A
+ */
+
+ for (iter = lines; iter && *iter; iter++) {
+ gboolean bool_val = FALSE;
+ char *p;
+
+ if (!strncmp (*iter, MODEM_REG_TAG, strlen (MODEM_REG_TAG))) {
+ registered = TRUE;
+ continue;
+ }
+
+ /* Roaming */
+ if (get_roam_value (*iter, ROAM_1X_TAG, &bool_val)) {
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info,
+ bool_val ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
+ MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
+ cdma_1x_set = TRUE;
+ }
+ if (get_roam_value (*iter, ROAM_EVDO_TAG, &bool_val)) {
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info,
+ bool_val ? MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING :
+ MM_MODEM_CDMA_REGISTRATION_STATE_HOME);
+ evdo_set = TRUE;
+ }
+
+ /* Current system mode */
+ p = strstr (*iter, SYS_MODE_TAG);
+ if (p) {
+ p += strlen (SYS_MODE_TAG);
+ while (*p && isspace (*p))
+ p++;
+ if (!strncmp (p, SYS_MODE_NO_SERVICE_TAG, strlen (SYS_MODE_NO_SERVICE_TAG)))
+ sys_mode = SYS_MODE_UNKNOWN;
+ else if (!strncmp (p, SYS_MODE_EVDO_TAG, strlen (SYS_MODE_EVDO_TAG)))
+ sys_mode = SYS_MODE_EVDO_REV0;
+ else if (!strncmp (p, SYS_MODE_1X_TAG, strlen (SYS_MODE_1X_TAG)))
+ sys_mode = SYS_MODE_CDMA_1X;
+ }
+
+ /* Current EVDO revision if system mode is EVDO */
+ p = strstr (*iter, EVDO_REV_TAG);
+ if (p) {
+ p += strlen (EVDO_REV_TAG);
+ while (*p && isspace (*p))
+ p++;
+ if (*p == 'A')
+ evdo_mode = SYS_MODE_EVDO_REVA;
+ else if (*p == '0')
+ evdo_mode = SYS_MODE_EVDO_REV0;
+ }
+ }
+
+ if (!registered) {
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+ mm_generic_cdma_query_reg_state_set_callback_evdo_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN);
+ } else {
+ /* Update current system mode */
+ if (sys_mode == SYS_MODE_EVDO_REV0 || sys_mode == SYS_MODE_EVDO_REVA) {
+ /* Prefer the explicit EVDO mode from EVDO_REV_TAG */
+ sys_mode = evdo_mode;
+ }
+ priv->sys_mode = sys_mode;
+
+ /* As a backup, if for some reason the registration states didn't get
+ * figured out by parsing the status info, set some generic registration
+ * states here.
+ */
+ if (!cdma_1x_set)
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED);
+
+ /* Ensure EVDO registration mode is set if we're at least in EVDO mode */
+ if (!evdo_set && (sys_mode == SYS_MODE_EVDO_REV0 || sys_mode == SYS_MODE_EVDO_REVA))
+ mm_generic_cdma_query_reg_state_set_callback_1x_state (info, MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED);
+ }
+
+done:
+ mm_callback_info_schedule (info);
+}
+
+static void
+query_registration_state (MMGenericCdma *cdma,
+ MMModemCdmaRegistrationStateFn callback,
+ gpointer user_data)
+{
+ MMCallbackInfo *info;
+ MMSerialPort *primary, *secondary;
+
+ primary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_PRIMARY);
+ secondary = mm_generic_cdma_get_port (cdma, MM_PORT_TYPE_SECONDARY);
+
+ info = mm_generic_cdma_query_reg_state_callback_info_new (cdma, callback, user_data);
+
+ if (mm_port_get_connected (MM_PORT (primary)) && !secondary) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_CONNECTED,
+ "Cannot get query registration state while connected");
+ mm_callback_info_schedule (info);
+ return;
+ }
+
+ mm_serial_port_queue_command (secondary ? secondary : primary,
+ "!STATUS", 3,
+ status_done, info);
+}
+
+/*****************************************************************************/
+
+static void
+mm_modem_sierra_cdma_init (MMModemSierraCdma *self)
+{
+}
+
+static void
+mm_modem_sierra_cdma_class_init (MMModemSierraCdmaClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMGenericCdmaClass *cdma_class = MM_GENERIC_CDMA_CLASS (klass);
+
+ mm_modem_sierra_cdma_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (object_class, sizeof (MMModemSierraCdmaPrivate));
+
+ cdma_class->query_registration_state = query_registration_state;
+}
+
+GType
+mm_modem_sierra_cdma_get_type (void)
+{
+ static GType modem_sierra_cdma_type = 0;
+
+ if (G_UNLIKELY (modem_sierra_cdma_type == 0)) {
+ static const GTypeInfo modem_sierra_cdma_type_info = {
+ sizeof (MMModemSierraCdmaClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mm_modem_sierra_cdma_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (MMModemSierraCdma),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mm_modem_sierra_cdma_init,
+ };
+
+ modem_sierra_cdma_type = g_type_register_static (MM_TYPE_GENERIC_CDMA, "MMModemSierraCdma", &modem_sierra_cdma_type_info, 0);
+ }
+
+ return modem_sierra_cdma_type;
+}
diff --git a/plugins/mm-modem-sierra-cdma.h b/plugins/mm-modem-sierra-cdma.h
new file mode 100644
index 00000000..9111b739
--- /dev/null
+++ b/plugins/mm-modem-sierra-cdma.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2008 - 2009 Novell, Inc.
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef MM_MODEM_SIERRA_CDMA_H
+#define MM_MODEM_SIERRA_CDMA_H
+
+#include "mm-generic-cdma.h"
+
+#define MM_TYPE_MODEM_SIERRA_CDMA (mm_modem_sierra_cdma_get_type ())
+#define MM_MODEM_SIERRA_CDMA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_SIERRA_CDMA, MMModemSierraCdma))
+#define MM_MODEM_SIERRA_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_MODEM_SIERRA_CDMA, MMModemSierraCdmaClass))
+#define MM_IS_MODEM_SIERRA_CDMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_SIERRA_CDMA))
+#define MM_IS_MODEM_SIERRA_CDMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_MODEM_SIERRA_CDMA))
+#define MM_MODEM_SIERRA_CDMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_MODEM_SIERRA_CDMA, MMModemSierraCdmaClass))
+
+typedef struct {
+ MMGenericCdma parent;
+} MMModemSierraCdma;
+
+typedef struct {
+ MMGenericCdmaClass parent;
+} MMModemSierraCdmaClass;
+
+GType mm_modem_sierra_cdma_get_type (void);
+
+MMModem *mm_modem_sierra_cdma_new (const char *device,
+ const char *driver,
+ const char *plugin,
+ gboolean evdo_rev0,
+ gboolean evdo_revA);
+
+#endif /* MM_MODEM_SIERRA_CDMA_H */
diff --git a/plugins/mm-plugin-sierra.c b/plugins/mm-plugin-sierra.c
index 3a1a182b..637f46d5 100644
--- a/plugins/mm-plugin-sierra.c
+++ b/plugins/mm-plugin-sierra.c
@@ -18,7 +18,7 @@
#include <gmodule.h>
#include "mm-plugin-sierra.h"
#include "mm-modem-sierra-gsm.h"
-#include "mm-generic-cdma.h"
+#include "mm-modem-sierra-cdma.h"
G_DEFINE_TYPE (MMPluginSierra, mm_plugin_sierra, MM_TYPE_PLUGIN_BASE)
@@ -160,11 +160,11 @@ grab_port (MMPluginBase *base,
mm_plugin_base_supports_task_get_driver (task),
mm_plugin_get_name (MM_PLUGIN (base)));
} else if (caps & CAP_CDMA) {
- modem = mm_generic_cdma_new (sysfs_path,
- mm_plugin_base_supports_task_get_driver (task),
- mm_plugin_get_name (MM_PLUGIN (base)),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
- !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
+ modem = mm_modem_sierra_cdma_new (sysfs_path,
+ mm_plugin_base_supports_task_get_driver (task),
+ mm_plugin_get_name (MM_PLUGIN (base)),
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856),
+ !!(caps & MM_PLUGIN_BASE_PORT_CAP_IS856_A));
}
if (modem) {