diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 3693a4b..9621de9 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -53,6 +53,7 @@ pkglib_LTLIBRARIES = \
libmm-plugin-motorola.la \
libmm-plugin-novatel.la \
libmm-plugin-novatel-lte.la \
+ libmm-plugin-altair-lte.la \
libmm-plugin-samsung.la \
libmm-plugin-option.la \
libmm-plugin-hso.la \
@@ -315,6 +316,17 @@ libmm_plugin_novatel_la_SOURCES = \
libmm_plugin_novatel_la_CPPFLAGS = $(PLUGIN_COMMON_COMPILER_FLAGS)
libmm_plugin_novatel_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
+# Altair LTE modem
+libmm_plugin_altair_lte_la_SOURCES = \
+ altair/mm-plugin-altair-lte.c \
+ altair/mm-plugin-altair-lte.h \
+ altair/mm-broadband-modem-altair-lte.c \
+ altair/mm-broadband-modem-altair-lte.h \
+ altair/mm-broadband-bearer-altair-lte.c \
+ altair/mm-broadband-bearer-altair-lte.h
+libmm_plugin_altair_lte_la_CPPFLAGS = $(PLUGIN_COMMON_COMPILER_FLAGS)
+libmm_plugin_altair_lte_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
+
# VIA modem
libmm_plugin_via_la_SOURCES = \
via/mm-plugin-via.c \
diff --git a/plugins/altair/mm-broadband-bearer-altair-lte.c
b/plugins/altair/mm-broadband-bearer-altair-lte.c
new file mode 100644
index 0000000..6303a8c
--- /dev/null
+++ b/plugins/altair/mm-broadband-bearer-altair-lte.c
@@ -0,0 +1,383 @@
+/* -*- 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 - 2012 Red Hat, Inc.
+ * Copyright (C) 2013 Altair Semiconductor
+ *
+ * Author: Ori Inbar <ori inbar altair-semi com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <ModemManager.h>
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-base-modem-at.h"
+#include "mm-broadband-bearer-altair-lte.h"
+#include "mm-log.h"
+#include "mm-modem-helpers.h"
+
+#define CONNECTION_CHECK_TIMEOUT_SEC 5
+#define STATCM_TAG "%STATCM:"
+
+G_DEFINE_TYPE (MMBroadbandBearerAltairLte, mm_broadband_bearer_altair_lte, MM_TYPE_BROADBAND_BEARER);
+
+/*****************************************************************************/
+/* 3GPP Connect sequence */
+
+typedef struct {
+ MMBroadbandBearerAltairLte *self;
+ MMBaseModem *modem;
+ MMAtSerialPort *primary;
+ MMPort *data;
+ GCancellable *cancellable;
+ GSimpleAsyncResult *result;
+} DetailedConnectContext;
+
+static DetailedConnectContext *
+detailed_connect_context_new (MMBroadbandBearer *self,
+ MMBroadbandModem *modem,
+ MMAtSerialPort *primary,
+ MMPort *data,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ DetailedConnectContext *ctx;
+
+ ctx = g_new0 (DetailedConnectContext, 1);
+ ctx->self = g_object_ref (self);
+ ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
+ ctx->primary = g_object_ref (primary);
+ ctx->data = data;
+ /* NOTE:
+ * We don't currently support cancelling AT commands, so we'll just check
+ * whether the operation is to be cancelled at each step. */
+ ctx->cancellable = g_object_ref (cancellable);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ detailed_connect_context_new);
+ return ctx;
+}
+
+static void
+detailed_connect_context_complete_and_free (DetailedConnectContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->cancellable);
+ if (ctx->data)
+ g_object_unref (ctx->data);
+ g_object_unref (ctx->primary);
+ g_object_unref (ctx->modem);
+ g_object_unref (ctx->self);
+ g_free (ctx);
+}
+
+static MMBearerConnectResult *
+connect_3gpp_finish (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return NULL;
+
+ return mm_bearer_connect_result_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT
(res)));
+}
+
+static void
+connect_3gpp_connect_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ DetailedConnectContext *ctx)
+{
+ const gchar *result;
+ GError *error = NULL;
+ MMBearerIpConfig *config;
+
+ result = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem),
+ res,
+ &error);
+ if (!result) {
+ mm_warn ("connect failed: %s", error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
+ return;
+ }
+
+ mm_dbg("Connected");
Whitespace before the parenthesis.
+
+ config = mm_bearer_ip_config_new ();
+
+ mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP);
+
+ /* Set operation result */
+ g_simple_async_result_set_op_res_gpointer (
+ ctx->result,
+ mm_bearer_connect_result_new (ctx->data,
+ config,
+ config),
+ (GDestroyNotify)mm_bearer_connect_result_unref);
+
+ g_object_unref (config);
+
+ detailed_connect_context_complete_and_free (ctx);
Explicit return and whitelines afterwards not needed.
+ return;
+
+
+}
+
+static void
+connect_3gpp_apnsettings_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ DetailedConnectContext *ctx)
+{
+ const gchar *result;
+ GError *error = NULL;
+
+ result = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem),
+ res,
+ &error);
+ if (!result) {
+ mm_warn ("setting APN failed: %s", error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ detailed_connect_context_complete_and_free (ctx);
+ return;
+ }
+
+ mm_dbg ("APN set - connecting bearer");
+ mm_base_modem_at_command (
+ ctx->modem,
+ "%DPDNACT=1",
+ 10, /* timeout */
+ FALSE, /* allow_cached */
+ (GAsyncReadyCallback)connect_3gpp_connect_ready, /* callback */
+ ctx); /* user_data */
+}
+
+static void
+connect_3gpp (MMBroadbandBearer *bearer,
+ MMBroadbandModem *modem,
+ MMAtSerialPort *primary,
+ MMAtSerialPort *secondary,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ DetailedConnectContext *ctx;
+ gchar *command, *apn;
+ MMBearerProperties *config;
+
+ ctx = detailed_connect_context_new (
+ bearer,
+ modem,
+ primary,
+ /* Get a 'net' data port */
+ mm_base_modem_get_best_data_port (MM_BASE_MODEM (modem),
+ MM_PORT_TYPE_NET),
+ cancellable,
+ callback,
+ user_data);
+
+ if (!ctx->data) {
+ g_simple_async_result_set_error (
+ ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_CONNECTED,
+ "Couldn't connect: no available net port available");
+ detailed_connect_context_complete_and_free (ctx);
+ return;
+ }
+
+ config = mm_bearer_peek_config (MM_BEARER (bearer));
+ apn = mm_at_serial_port_quote_string (mm_bearer_properties_get_apn (config));
+ command = g_strdup_printf ("%%APNN=%s",apn);
+ g_free (apn);
+ mm_base_modem_at_command (
+ ctx->modem,
+ command,
+ 6, /* timeout */
+ FALSE, /* allow_cached */
+ (GAsyncReadyCallback)connect_3gpp_apnsettings_ready,
+ ctx); /* user_data */
+ g_free (command);
+}
+
+/*****************************************************************************/
+/* 3GPP Disconnect sequence */
+
+typedef struct {
+ MMBroadbandBearer *self;
+ MMBaseModem *modem;
+ MMAtSerialPort *primary;
+ MMAtSerialPort *secondary;
+ MMPort *data;
+ GSimpleAsyncResult *result;
+} DetailedDisconnectContext;
+
+static DetailedDisconnectContext *
+detailed_disconnect_context_new (MMBroadbandBearer *self,
+ MMBroadbandModem *modem,
+ MMAtSerialPort *primary,
+ MMAtSerialPort *secondary,
+ MMPort *data,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ DetailedDisconnectContext *ctx;
+
+ ctx = g_new0 (DetailedDisconnectContext, 1);
+ ctx->self = g_object_ref (self);
+ ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
+ ctx->primary = g_object_ref (primary);
+ ctx->secondary = (secondary ? g_object_ref (secondary) : NULL);
+ ctx->data = g_object_ref (data);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ detailed_disconnect_context_new);
+ return ctx;
+}
+
+static gboolean
+disconnect_3gpp_finish (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+detailed_disconnect_context_complete_and_free (DetailedDisconnectContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->data);
+ if (ctx->secondary)
+ g_object_unref (ctx->secondary);
+ g_object_unref (ctx->primary);
+ g_object_unref (ctx->modem);
+ g_object_unref (ctx->self);
+ g_free (ctx);
+}
+
+static void
+disconnect_3gpp_check_status (MMBaseModem *modem,
+ GAsyncResult *res,
+ DetailedDisconnectContext *ctx)
+{
+
+ const gchar *result;
+ GError *error = NULL;
+
+ result = mm_base_modem_at_command_finish (MM_BASE_MODEM (modem),
+ res,
+ &error);
+ if (!result) {
+ mm_warn ("Disconnect failed: %s", error->message);
+ g_simple_async_result_take_error (ctx->result, error);
+ }
+ else
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+
+ detailed_disconnect_context_complete_and_free (ctx);
Explicit return not needed here.
+ return;
+}
+
+static void
+disconnect_3gpp (MMBroadbandBearer *self,
+ MMBroadbandModem *modem,
+ MMAtSerialPort *primary,
+ MMAtSerialPort *secondary,
+ MMPort *data,
+ guint cid,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ DetailedDisconnectContext *ctx;
+
+ ctx = detailed_disconnect_context_new (self, modem, primary, secondary,
+ data, callback, user_data);
+
+ mm_base_modem_at_command (
+ ctx->modem,
+ "%DPDNACT=0",
+ 10, /* timeout */
+ FALSE, /* allow_cached */
+ (GAsyncReadyCallback)disconnect_3gpp_check_status,
+ ctx); /* user_data */
+}
+
+/*****************************************************************************/
+
+MMBearer *
+mm_broadband_bearer_altair_lte_new_finish (GAsyncResult *res,
+ GError **error)
+{
+ GObject *bearer;
+ GObject *source;
+
+ source = g_async_result_get_source_object (res);
+ bearer = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, error);
+ g_object_unref (source);
+
+ if (!bearer)
+ return NULL;
+
+ /* Only export valid bearers */
+ mm_bearer_export (MM_BEARER (bearer));
+
+ return MM_BEARER (bearer);
+}
+
+void
+mm_broadband_bearer_altair_lte_new (MMBroadbandModemAltairLte *modem,
+ MMBearerProperties *config,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_async_initable_new_async (
+ MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ callback,
+ user_data,
+ MM_BEARER_MODEM, modem,
+ MM_BEARER_CONFIG, config,
+ NULL);
+}
+
+static void
+mm_broadband_bearer_altair_lte_init (MMBroadbandBearerAltairLte *self)
+{
+
+}
+
+static void
+mm_broadband_bearer_altair_lte_class_init (MMBroadbandBearerAltairLteClass *klass)
+{
+ MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass);
+
+ broadband_bearer_class->connect_3gpp = connect_3gpp;
+ broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish;
+ broadband_bearer_class->disconnect_3gpp = disconnect_3gpp;
+ broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish;
+}
diff --git a/plugins/altair/mm-broadband-bearer-altair-lte.h
b/plugins/altair/mm-broadband-bearer-altair-lte.h
new file mode 100644
index 0000000..891c0f9
--- /dev/null
+++ b/plugins/altair/mm-broadband-bearer-altair-lte.h
@@ -0,0 +1,60 @@
+/* -*- 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) 2013 Altair Semiconductor
+ *
+ * Author: Ori Inbar <ori inbar altair-semi com>
+ */
+
+#ifndef MM_BROADBAND_BEARER_ALTAIR_LTE_H
+#define MM_BROADBAND_BEARER_ALTAIR_LTE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-broadband-bearer.h"
+#include "mm-broadband-modem-altair-lte.h"
+
+#define MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE (mm_broadband_bearer_altair_lte_get_type ())
+#define MM_BROADBAND_BEARER_ALTAIR_LTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE, MMBroadbandBearerAltairLte))
+#define MM_BROADBAND_BEARER_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE, MMBroadbandBearerAltairLteClass))
+#define MM_IS_BROADBAND_BEARER_ALTAIR_LTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE))
+#define MM_IS_BROADBAND_BEARER_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE))
+#define MM_BROADBAND_BEARER_ALTAIR_LTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE, MMBroadbandBearerAltairLteClass))
+
+typedef struct _MMBroadbandBearerAltairLte MMBroadbandBearerAltairLte;
+typedef struct _MMBroadbandBearerAltairLteClass MMBroadbandBearerAltairLteClass;
+
+struct _MMBroadbandBearerAltairLte {
+ MMBroadbandBearer parent;
+};
+
+struct _MMBroadbandBearerAltairLteClass {
+ MMBroadbandBearerClass parent;
+};
+
+GType mm_broadband_bearer_altair_lte_get_type (void);
+
+/* Default 3GPP bearer creation implementation */
+void mm_broadband_bearer_altair_lte_new (MMBroadbandModemAltairLte *modem,
+ MMBearerProperties *properties,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+MMBearer *mm_broadband_bearer_altair_lte_new_finish (GAsyncResult *res,
+ GError **error);
+
+
+#endif /* MM_BROADBAND_BEARER_ALTAIR_LTE_H */
diff --git a/plugins/altair/mm-broadband-modem-altair-lte.c
b/plugins/altair/mm-broadband-modem-altair-lte.c
new file mode 100644
index 0000000..4eb1489
--- /dev/null
+++ b/plugins/altair/mm-broadband-modem-altair-lte.c
@@ -0,0 +1,1096 @@
+/* -*- 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) 2013 Altair Semiconductor
+ *
+ * Author: Ori Inbar <ori inbar altair-semi com>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "ModemManager.h"
+#include "mm-base-modem-at.h"
+#include "mm-broadband-bearer-altair-lte.h"
+#include "mm-broadband-modem-altair-lte.h"
+#include "mm-errors-types.h"
+#include "mm-iface-modem.h"
+#include "mm-iface-modem-3gpp.h"
+#include "mm-iface-modem-3gpp-ussd.h"
+#include "mm-iface-modem-messaging.h"
+#include "mm-log.h"
+#include "mm-modem-helpers.h"
+#include "mm-serial-parsers.h"
+#include "mm-bearer-list.h"
+
+static void iface_modem_init (MMIfaceModem *iface);
+static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
+static void iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface);
+static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
+
+G_DEFINE_TYPE_EXTENDED (MMBroadbandModemAltairLte, mm_broadband_modem_altair_lte,
MM_TYPE_BROADBAND_MODEM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP_USSD, iface_modem_3gpp_ussd_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING,
iface_modem_messaging_init));
+
+struct _MMBroadbandModemAltairLtePrivate {
+ /* Regex for bearer related notifications */
+ GRegex *statcm_regex;
+};
+
+static MMIfaceModem3gpp *iface_modem_3gpp_parent;
+
+
+/*****************************************************************************/
+/* Modem power down (Modem interface) */
+
+static gboolean
+modem_power_down_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
+}
+
+static void
+modem_power_down (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "+CFUN=4",
+ 6,
+ FALSE,
+ callback,
+ user_data);
+}
+
+/*****************************************************************************/
+/* Create Bearer (Modem interface) */
+
+static MMBearer *
+modem_create_bearer_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ MMBearer *bearer;
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return NULL;
+
+ bearer = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+
+ return g_object_ref (bearer);
+}
+
+static void
+broadband_bearer_new_ready (GObject *source,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ MMBearer *bearer = NULL;
+ GError *error = NULL;
+
+ bearer = mm_broadband_bearer_altair_lte_new_finish (res, &error);
+ if (!bearer)
+ g_simple_async_result_take_error (simple, error);
+ else
+ g_simple_async_result_set_op_res_gpointer (simple,
+ bearer,
+ (GDestroyNotify)g_object_unref);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+modem_create_bearer (MMIfaceModem *self,
+ MMBearerProperties *properties,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ /* Set a new ref to the bearer object as result */
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_create_bearer);
+
+ /* We just create a MMBroadbandBearer */
+ mm_broadband_bearer_altair_lte_new (MM_BROADBAND_MODEM_ALTAIR_LTE (self),
+ properties,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)broadband_bearer_new_ready,
+ result);
+}
+
+/*****************************************************************************/
+/* Load current capabilities (Modem interface) */
+
+static MMModemCapability
+load_current_capabilities_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ MMModemCapability caps;
+ gchar *caps_str;
+
+ /* This modem is LTE only.*/
+ caps = MM_MODEM_CAPABILITY_LTE;
+ caps_str = mm_modem_capability_build_string_from_mask (caps);
+ mm_dbg ("Loaded current capabilities: %s", caps_str);
+ g_free (caps_str);
+ return caps;
+}
+
+static void
+load_current_capabilities (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ mm_dbg ("Loading (Altair LTE) current capabilities...");
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ load_current_capabilities);
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+/*****************************************************************************/
+/* supported/current Bands helpers*/
+
+static GArray *
+parse_bands_response(const gchar *response)
Whitespace before parenthesis.
+{
+ guint32 bandval;
+ MMModemBand band;
+ gchar **split;
+ guint i,num_of_bands;
+ GArray *bands;
+
+ split = g_strsplit_set (response, ",", -1);
+ if (!split)
+ return NULL;
+
+ for (num_of_bands = 0; split[num_of_bands]; num_of_bands++);
Better just:
num_of_bands = g_strv_length (split);
+
+ bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), num_of_bands);
+
+ for (i = 0; split[i]; i++) {
+ bandval = (guint32)strtoul (split[i], NULL, 10);
+ band = MM_MODEM_BAND_EUTRAN_I - 1 + bandval;
+ g_array_append_val(bands, band);
+ }
+
+ g_strfreev (split);
+
+ return bands;
+}
+/*****************************************************************************/
+/* Load supported bands (Modem interface) */
+
+static GArray *
+load_supported_bands_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ /* Never fails */
+ return (GArray *) g_array_ref (g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (res)));
+}
+
+#define BANDCAP_TAG "%BANDCAP: "
+
+static void
+load_supported_bands_done (MMIfaceModem *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *operation_result)
+{
+ GArray *bands;
+ const gchar *response;
+ GError *error = NULL;
+
+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
+ if (!response) {
+ mm_dbg ("Couldn't query supported bands: '%s'", error->message);
+ g_simple_async_result_take_error (operation_result, error);
+ g_simple_async_result_complete_in_idle (operation_result);
+ g_object_unref (operation_result);
+ return;
+ }
+
+ /*
+ * Response is "%BANDCAP: <band>,[<band>...]"
+ */
+ response = mm_strip_tag (response, BANDCAP_TAG);
+
+ bands = parse_bands_response(response);
Whitespace before parenthesis.
+ if (!bands) {
+ mm_dbg ("Failed to parse supported bands response");
+ g_simple_async_result_set_error (
+ operation_result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Failed to parse supported bands response");
+ g_simple_async_result_complete_in_idle (operation_result);
+ g_object_unref (operation_result);
+ return;
+ }
+
+ g_simple_async_result_set_op_res_gpointer (operation_result,
+ bands,
+ (GDestroyNotify)g_array_unref);
+ g_simple_async_result_complete_in_idle (operation_result);
+ g_object_unref (operation_result);
+}
+
+static void
+load_supported_bands (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ load_supported_bands);
Good! Querying supported bands is much better than hardcoding them.
+
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ "%BANDCAP=",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)load_supported_bands_done,
+ result);
+}
+/*****************************************************************************/
+/* Load current bands (Modem interface) */
+
+static GArray *
+load_current_bands_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ /* Never fails */
+ return (GArray *) g_array_ref (g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (res)));
+}
+
+#define CFGBANDS_TAG "Bands: "
+
+static void
+load_current_bands_done (MMIfaceModem *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *operation_result)
+{
+ GArray *bands;
+ const gchar *response;
+ GError *error = NULL;
+
+ response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
+ if (!response) {
+ mm_dbg ("Couldn't query current bands: '%s'", error->message);
+ g_simple_async_result_take_error (operation_result, error);
+ g_simple_async_result_complete_in_idle (operation_result);
+ g_object_unref (operation_result);
+ return;
+ }
+
+ /*
+ * Response is "Bands: <band>,[<band>...]"
+ */
+ response = mm_strip_tag (response, CFGBANDS_TAG);
+
+ bands = parse_bands_response(response);
+ if (!bands) {
+ mm_dbg ("Failed to parse current bands response");
+ g_simple_async_result_set_error (
+ operation_result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Failed to parse current bands response");
+ g_simple_async_result_complete_in_idle (operation_result);
+ g_object_unref (operation_result);
+ return;
+ }
+
+ g_simple_async_result_set_op_res_gpointer (operation_result,
+ bands,
+ (GDestroyNotify)g_array_unref);
+ g_simple_async_result_complete_in_idle (operation_result);
+ g_object_unref (operation_result);
+}
+
+static void
+load_current_bands (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ load_current_bands);
+
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ "%GETCFG=\"BAND\"",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)load_current_bands_done,
+ result);
+}
+
+/*****************************************************************************/
+/* Reset (Modem interface) */
+
+static gboolean
+reset_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
+}
+
+static void
+reset (MMIfaceModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "ATZ",
+ 3,
+ FALSE,
+ callback,
+ user_data);
+}
+
+/*****************************************************************************/
+/* Register in network (3GPP interface) */
+
+static void
+modem_3gpp_register_in_network (MMIfaceModem3gpp *self,
+ const gchar *operator_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ if (operator_id) {
+ /* Currently only VZW is supported */
+ g_simple_async_report_error_in_idle (G_OBJECT (self),
+ callback,
+ user_data,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Setting a specific operator Id is not supported");
+ return;
+ }
+
+ mm_base_modem_at_command_full (MM_BASE_MODEM (self),
+ mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
+ "%CMATT=1",
+ 3,
+ FALSE,
+ FALSE, /* raw */
+ cancellable,
+ callback,
+ user_data);
+}
+
+static gboolean
+modem_3gpp_register_in_network_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !!mm_base_modem_at_command_full_finish (MM_BASE_MODEM (self), res, error);
+}
+
+/*****************************************************************************/
+/* Setup/Cleanup unsolicited events (3GPP interface) */
+
+typedef enum {
+ MM_STATCM_ALTAIR_LTE_DEREGISTERED = 0,
+ MM_STATCM_ALTAIR_LTE_REGISTERED = 1,
+ MM_STATCM_ALTAIR_PDN_CONNECTED = 3,
+ MM_STATCM_ALTAIR_PDN_DISCONNECTED = 4,
+} MMStatcmAltair;
+
+static void
+bearer_list_report_diconnect_status_foreach (MMBearer *bearer,
+ gpointer *user_data)
+{
+ mm_bearer_report_disconnection (bearer);
+}
+
+static void
+altair_statcm_changed (MMAtSerialPort *port,
+ GMatchInfo *match_info,
+ MMBroadbandModemAltairLte *self)
+{
+ gint pdn_event = 0;
+ MMBearerList *list = NULL;
+
+ mm_get_int_from_match_info (match_info, 1, &pdn_event);
+
+ mm_dbg ("altair_statcm_changed %d",pdn_event);
Whitespace after comma.
+
+ /* Currently we only care about bearer disconnection */
+
+ if (pdn_event == MM_STATCM_ALTAIR_PDN_DISCONNECTED) {
+ /* If empty bearer list, nothing else to do */
+ g_object_get (self,
+ MM_IFACE_MODEM_BEARER_LIST, &list,
+ NULL);
+ if (!list)
+ return;
+
+ mm_bearer_list_foreach (list,
+ (MMBearerListForeachFunc)bearer_list_report_diconnect_status_foreach,
+ NULL);
+
+ g_object_unref (list);
+ }
+
+}
+
+static void
+set_3gpp_unsolicited_events_handlers (MMBroadbandModemAltairLte *self,
+ gboolean enable)
+{
+ MMAtSerialPort *ports[2];
+ guint i;
+
+ ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
+ ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
+
+ /* Enable/disable unsolicited events in given port */
+ for (i = 0; i < 2; i++) {
+ if (!ports[i])
+ continue;
+
+ /* bearer mode related */
+ mm_at_serial_port_add_unsolicited_msg_handler (
+ ports[i],
+ self->priv->statcm_regex,
+ enable ? (MMAtSerialUnsolicitedMsgFn)altair_statcm_changed : NULL,
+ enable ? self : NULL,
+ NULL);
+ }
+}
+
+static gboolean
+modem_3gpp_setup_cleanup_unsolicited_events_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+parent_3gpp_setup_unsolicited_events_ready (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ GError *error = NULL;
+
+ if (!iface_modem_3gpp_parent->setup_unsolicited_events_finish (self, res, &error))
+ g_simple_async_result_take_error (simple, error);
+ else {
+ /* Our own setup now */
+ set_3gpp_unsolicited_events_handlers (MM_BROADBAND_MODEM_ALTAIR_LTE (self), TRUE);
+ g_simple_async_result_set_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res), TRUE);
+ }
+
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+modem_3gpp_setup_unsolicited_events (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_3gpp_setup_unsolicited_events);
+
+ /* Chain up parent's setup */
+ iface_modem_3gpp_parent->setup_unsolicited_events (
+ self,
+ (GAsyncReadyCallback)parent_3gpp_setup_unsolicited_events_ready,
+ result);
+}
+
+static void
+parent_3gpp_cleanup_unsolicited_events_ready (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ GError *error = NULL;
+
+ if (!iface_modem_3gpp_parent->cleanup_unsolicited_events_finish (self, res, &error))
+ g_simple_async_result_take_error (simple, error);
+ else
+ g_simple_async_result_set_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (res), TRUE);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_3gpp_cleanup_unsolicited_events);
+
+ /* Our own cleanup first */
+ set_3gpp_unsolicited_events_handlers (MM_BROADBAND_MODEM_ALTAIR_LTE (self), FALSE);
+
+ /* And now chain up parent's cleanup */
+ iface_modem_3gpp_parent->cleanup_unsolicited_events (
+ self,
+ (GAsyncReadyCallback)parent_3gpp_cleanup_unsolicited_events_ready,
+ result);
+}
Whiteline here between sections.
+/*****************************************************************************/
+/* Enabling unsolicited events (3GPP interface) */
+
+static gboolean
+modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+own_enable_unsolicited_events_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ GError *error = NULL;
+
+ mm_base_modem_at_sequence_full_finish (self, res, NULL, &error);
+ if (error)
+ g_simple_async_result_take_error (simple, error);
+ else
+ g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ GError *error = NULL;
+
+ if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, &error)) {
+ g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ }
+
+ /* Our own enable now */
+ mm_base_modem_at_command_full (
+ MM_BASE_MODEM (self),
+ mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
+ "%STATCM=1",
+ 6,
+ FALSE, /* allow_cached */
+ FALSE, /* raw */
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)own_enable_unsolicited_events_ready,
+ simple);
+}
+
+static void
+modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_3gpp_enable_unsolicited_events);
+
+ /* Chain up parent's enable */
+ iface_modem_3gpp_parent->enable_unsolicited_events (
+ self,
+ (GAsyncReadyCallback)parent_enable_unsolicited_events_ready,
+ result);
+}
+
+/*****************************************************************************/
+/* Disabling unsolicited events (3GPP interface) */
+
+static gboolean
+modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ GError *error = NULL;
+
+ if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error))
+ g_simple_async_result_take_error (simple, error);
+ else
+ g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+own_disable_unsolicited_events_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ GError *error = NULL;
+
+ mm_base_modem_at_command_full_finish (self, res, &error);
+ if (error) {
+ g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ /* Next, chain up parent's disable */
+ iface_modem_3gpp_parent->disable_unsolicited_events (
+ MM_IFACE_MODEM_3GPP (self),
+ (GAsyncReadyCallback)parent_disable_unsolicited_events_ready,
+ simple);
+}
+
+static void
+modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_3gpp_disable_unsolicited_events);
+
+ /* Our own disable first */
+ mm_base_modem_at_command_full (
+ MM_BASE_MODEM (self),
+ mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
+ "%STATCM=0",
+ 5,
+ FALSE, /* allow_cached */
+ FALSE, /* raw */
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)own_disable_unsolicited_events_ready,
+ result);
+}
+
+/*****************************************************************************/
+/* Facility locks status loading (3GPP interface) */
+
+typedef struct {
+ MMBroadbandModem *self;
+ GSimpleAsyncResult *result;
+ guint current;
+ MMModem3gppFacility facilities;
+ MMModem3gppFacility locks;
+} LoadEnabledFacilityLocksContext;
+
+static void get_next_facility_lock_status (LoadEnabledFacilityLocksContext *ctx);
+
+static void
+load_enabled_facility_locks_context_complete_and_free (LoadEnabledFacilityLocksContext *ctx)
+{
+ g_simple_async_result_complete (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->self);
+ g_free (ctx);
+}
+
+static MMModem3gppFacility
+modem_3gpp_load_enabled_facility_locks_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return MM_MODEM_3GPP_FACILITY_NONE;
+
+ return ((MMModem3gppFacility) GPOINTER_TO_UINT (
+ g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))));
+}
+
+static void
+clck_single_query_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ LoadEnabledFacilityLocksContext *ctx)
+{
+ const gchar *response;
+ gboolean enabled = FALSE;
+
+ response = mm_base_modem_at_command_finish (self, res, NULL);
+ if (response &&
+ mm_3gpp_parse_clck_write_response (response, &enabled) &&
+ enabled) {
+ ctx->locks |= (1 << ctx->current);
+ } else {
+ /* On errors, we'll just assume disabled */
+ ctx->locks &= ~(1 << ctx->current);
+ }
+
+ /* And go on with the next one */
+ ctx->current++;
+ get_next_facility_lock_status (ctx);
+}
+
+static void
+get_next_facility_lock_status (LoadEnabledFacilityLocksContext *ctx)
+{
+ guint i;
+
+ for (i = ctx->current; i < sizeof (MMModem3gppFacility) * 8; i++) {
+ guint32 facility = 1 << i;
+
+ /* Found the next one to query! */
+ if (ctx->facilities & facility) {
+ gchar *cmd;
+
+ /* Keep the current one */
+ ctx->current = i;
+
+ /* Query current */
+ cmd = g_strdup_printf ("+CLCK=\"%s\",2",
+ mm_3gpp_facility_to_acronym (facility));
+ mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
+ cmd,
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)clck_single_query_ready,
+ ctx);
+ g_free (cmd);
+ return;
+ }
+ }
+
+ /* No more facilities to query, all done */
+ g_simple_async_result_set_op_res_gpointer (ctx->result,
+ GUINT_TO_POINTER (ctx->locks),
+ NULL);
+ load_enabled_facility_locks_context_complete_and_free (ctx);
+}
+
+static void
+modem_3gpp_load_enabled_facility_locks (MMIfaceModem3gpp *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ LoadEnabledFacilityLocksContext *ctx;
+
+ ctx = g_new (LoadEnabledFacilityLocksContext, 1);
+ ctx->self = g_object_ref (self);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ modem_3gpp_load_enabled_facility_locks);
+ ctx->facilities = MM_MODEM_3GPP_FACILITY_SIM;
What's the problem with the generic method doing "AT+CLCK=?"? Why not
ask for which are the supported facilities and then query each of them
(which is what the generic method is doing)?
If you only really need to report about the SIM lock, you better
simplify the logic of this method, you don't need to have a
ctx->facilities and then query each enabled facility in the flags mask,
as there will only be one. So just a single AT+CLCK="xx",2 will be needed.
If the problem is that you don't want certain facilities to be checked,
you can set the new "MM_IFACE_MODEM_3GPP_IGNORED_FACILITY_LOCKS" to
contain a mask of flags with the facilities to ignore. See commits
d9cf4fe91 and e33fc37e.