Re: [MM][PATCH] altair-lte: initial altair lte plugin



hello Aleksander.

i'm working on implementing all the comments below - a new patch will be sent soon.

i do have a couple of questions - see below

regards
ori inbar


On Wed, Mar 20, 2013 at 4:47 AM, Aleksander Morgado <aleksander lanedo com> wrote:
Hey!

Good to see new plugins coming in :)

Some comments below.


On 03/19/2013 09:00 PM, ori inbar wrote:
> ---
>  plugins/Makefile.am                             |   12 +
>  plugins/altair/mm-broadband-bearer-altair-lte.c |  373 ++++++++
>  plugins/altair/mm-broadband-bearer-altair-lte.h |   60 ++
>  plugins/altair/mm-broadband-modem-altair-lte.c  | 1162 +++++++++++++++++++++++
>  plugins/altair/mm-broadband-modem-altair-lte.h  |   51 +
>  plugins/altair/mm-plugin-altair-lte.c           |   95 ++
>  plugins/altair/mm-plugin-altair-lte.h           |   48 +
>  src/77-mm-usb-device-blacklist.rules            |    3 +
>  8 files changed, 1804 insertions(+)
>  create mode 100644 plugins/altair/mm-broadband-bearer-altair-lte.c
>  create mode 100644 plugins/altair/mm-broadband-bearer-altair-lte.h
>  create mode 100644 plugins/altair/mm-broadband-modem-altair-lte.c
>  create mode 100644 plugins/altair/mm-broadband-modem-altair-lte.h
>  create mode 100644 plugins/altair/mm-plugin-altair-lte.c
>  create mode 100644 plugins/altair/mm-plugin-altair-lte.h
>
> 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..3f218e8
> --- /dev/null
> +++ b/plugins/altair/mm-broadband-bearer-altair-lte.c
> @@ -0,0 +1,373 @@
> +/* -*- 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);
> +    g_object_unref (ctx->data);
> +    g_object_unref (ctx->primary);
> +    g_object_unref (ctx->modem);
> +    g_object_unref (ctx->self);
> +    g_free (ctx);
> +}
> +
> +static gboolean
> +connect_3gpp_finish (MMBroadbandBearer *self,
> +                     GAsyncResult *res,
> +                     MMPort **data,
> +                     MMBearerIpConfig **ipv4_config,
> +                     MMBearerIpConfig **ipv6_config,
> +                     GError **error)


Please rebase on top of git master; the connect_3gpp_finish() method was
updated to use a new MMBearerConnectResult type, which makes it easier
to bundle all values being returned all together.


> +{
> +    MMBearerIpConfig *config;
> +
> +    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
> +        return FALSE;
> +
> +    config = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
> +
> +    *ipv4_config = g_object_ref (config);
> +    *ipv6_config = mm_bearer_ip_config_new ();
> +    mm_bearer_ip_config_set_method (*ipv6_config, MM_BEARER_IP_METHOD_DHCP);

Does it really support IPv6? If not, be aware that NULL can be returned
safely as IPv6 config.

yes it supports IPv6 - so that is why i created this config. 
i hope i wrote it correctly. 

> +    /* We used the input suggested data port */
> +    *data = "">
With the new MMBearerConnectResult, you must specify the data port to
use. You can always get it from the input values stored in the context data:
  mm_bearer_connect_result_new (ctx->data, config, NULL),

> +
> +    return TRUE;
> +}
> +
> +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");

A whitespace needed before the parenthesis.

> +    config = mm_bearer_ip_config_new ();
> +    mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP);
> +    g_simple_async_result_set_op_res_gpointer (ctx->result,
> +                                               config,
> +                                               (GDestroyNotify)g_object_unref);

As said before, you can use the new MMBearerConnectResult type and add
it as result pointer.

> +    detailed_connect_context_complete_and_free (ctx);
> +    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,
> +              MMPort *data,
> +              GCancellable *cancellable,
> +              GAsyncReadyCallback callback,
> +              gpointer user_data)
> +{
> +    DetailedConnectContext *ctx;
> +    gchar *command, *apn;
> +    MMBearerProperties *config;
> +
> +    ctx = detailed_connect_context_new (bearer,
> +                                        modem,
> +                                        primary,
> +                                        data,
> +                                        cancellable,
> +                                        callback,
> +                                        user_data);
> +
> +    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,
> +        3, /* 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 = "" (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);
> +    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..d2c25c2
> --- /dev/null
> +++ b/plugins/altair/mm-broadband-modem-altair-lte.c
> @@ -0,0 +1,1162 @@
> +/* -*- 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-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_messaging_init (MMIfaceModemMessaging *iface);
> +
> +typedef struct _PortsContext PortsContext;
> +
> +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_MESSAGING, iface_modem_messaging_init));
> +
> +struct _MMBroadbandModemAltairLtePrivate {
> +    /* Regex for bearer related notifications */
> +    GRegex *statcm_regex;
> +};
> +
> +static MMIfaceModem3gpp *iface_modem_3gpp_parent;
> +
> +/*****************************************************************************/
> +/* Initializing the modem (Modem interface) */
> +
> +static gboolean
> +modem_init_finish (MMIfaceModem *self,
> +                   GAsyncResult *res,
> +                   GError **error)
> +{
> +    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
> +}
> +
> +static void
> +modem_init_sequence_ready (MMBaseModem *self,
> +                           GAsyncResult *res,
> +                           GSimpleAsyncResult *simple)
> +{
> +    GError *error = NULL;
> +
> +    mm_base_modem_at_sequence_full_finish (MM_BASE_MODEM (self), res, NULL, &error);
> +    if (error)
> +        g_simple_async_result_take_error (simple, error);
> +
> +    g_simple_async_result_complete (simple);
> +    g_object_unref (simple);
> +}
> +
> +static const MMBaseModemAtCommand modem_init_sequence[] = {
> +    { "+CMEE=1", 3, FALSE, NULL },
> +    { NULL }
> +};


This also got changed not long ago. The 'modem_init' sequence was split
into two different things:

 * MM_AT_SERIAL_PORT_INIT_SEQUENCE property: whenever an AT serial port
is open, a set of commands is sent to initialize it. You would configure
this property in setup_ports() usually; just check how the
MMBroadbandModem does it. Your +CMEE=1 should go there instead, and
therefore you won't need this modem_init().

 * enabling_modem_init: basically, ATZ, to be run only when the modem
wasn't hotplugged.

> +
> +static void
> +modem_init (MMIfaceModem *self,
> +            GAsyncReadyCallback callback,
> +            gpointer user_data)
> +{
> +    MMAtSerialPort *primary;
> +    GSimpleAsyncResult *result;
> +
> +    result = g_simple_async_result_new (G_OBJECT (self),
> +                                        callback,
> +                                        user_data,
> +                                        modem_init);
> +
> +    primary = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
> +    if (!primary) {
> +        g_simple_async_result_set_error (
> +            result,
> +            MM_CORE_ERROR,
> +            MM_CORE_ERROR_FAILED,
> +            "Need primary AT port to run modem init sequence");
> +        g_simple_async_result_complete_in_idle (result);
> +        g_object_unref (result);
> +        return;
> +    }
> +
> +    mm_base_modem_at_sequence_full (MM_BASE_MODEM (self),
> +                                    primary,
> +                                    modem_init_sequence,
> +                                    NULL,  /* response_processor_context */
> +                                    NULL,  /* response_processor_context_free */
> +                                    NULL, /* cancellable */
> +                                    (GAsyncReadyCallback)modem_init_sequence_ready,
> +                                    result);
> +}
> +
> +/*****************************************************************************/
> +/* Modem power up (Modem interface) */
> +
> +static gboolean
> +modem_power_up_finish (MMIfaceModem *self,
> +                       GAsyncResult *res,
> +                       GError **error)
> +{
> +    return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
> +}
> +
> +
> +static const MMBaseModemAtCommand modem_powerup_sequence[] = {
> +
> +    { "+CFUN=1", 6, FALSE, NULL },
> +    { "%CMATT=1", 10, FALSE, mm_base_modem_response_processor_no_result_continue },
> +    { NULL }
> +};
> +
> +static void
> +modem_power_up (MMIfaceModem *self,
> +                  GAsyncReadyCallback callback,
> +                  gpointer user_data)
> +{
> +    mm_base_modem_at_sequence (MM_BASE_MODEM (self),
> +                               modem_powerup_sequence,
> +                               NULL,  /* response_processor_context */
> +                               NULL,  /* response_processor_context_free */
> +                               callback,
> +                               user_data);
> +}
> +
> +/*****************************************************************************/
> +/* 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);
> +}


Did you make sure that the generic load_power_state() method is also
valid for your case?


> +
> +/*****************************************************************************/
> +/* 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;
> +
> +    /* Constrain the modem capabilities to LTE only.*/
> +    caps = MM_MODEM_CAPABILITY_LTE;

So this is a LTE-only modem? No HSPA, no EV-DO?
correct. 

> +    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);
> +}
> +
> +
> +
> +/*****************************************************************************/
> +/* 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)));
> +}
> +
> +static void
> +load_supported_bands (MMIfaceModem *self,
> +                      GAsyncReadyCallback callback,
> +                      gpointer user_data)
> +{
> +    GSimpleAsyncResult *result;
> +    GArray *bands;
> +    MMModemBand band;
> +
> +    result = g_simple_async_result_new (G_OBJECT (self),
> +                                        callback,
> +                                        user_data,
> +                                        load_supported_bands);
> +
> +    /*
> +     * The modem doesn't support telling us what bands are supported;
> +     * list everything we know about.
> +     */
> +    bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 1);
> +
> +    band = MM_MODEM_BAND_EUTRAN_XIII;
> +    g_array_append_val(bands, band);
> +
> +    g_simple_async_result_set_op_res_gpointer (result,
> +                                               bands,
> +                                               (GDestroyNotify)g_array_unref);
> +    g_simple_async_result_complete_in_idle (result);
> +    g_object_unref (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)));
> +}
> +
> +static void
> +load_current_bands_done (MMIfaceModem *self,
> +                         GAsyncResult *res,
> +                         GSimpleAsyncResult *operation_result)
> +{
> +    GArray *bands;
> +    const gchar *response;
> +    const gchar *p;
> +    GError *error = NULL;
> +    guint32 bandval;
> +    MMModemBand band;
> +
> +    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 "Bands: <band>,[<band>...]"
> +     * we assume there should be only one band.
> +     * but if there is more than one , we'll just use the last band.
> +     */

Not sure how this happens. 'Current' bands must be a subset of
'Supported' bands, and looking at the code I see that supported bands is
limited to just MM_MODEM_BAND_EUTRAN_XIII. So, how is it that the
current band value can be different to that one?

this is a VZW only implementation. so i made an effort to support VZW bands only. 


> +    p = strrchr( response + 7, ',');

The whitespace goes before the parenthesis, not after.

Also, instead of response + 7, just use mm_strip_tag() to get rid of the
prefix safely.

> +    if (!p) {
> +        p = response + 7;
> +    } else {
> +        p++;
> +    }
> +
> +    bandval = (guint32)strtoul(p, NULL, 10);
> +
> +    bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 1);
> +
> +    mm_dbg ("Query supported bands: '%d'", bandval);
> +
> +    band = MM_MODEM_BAND_EUTRAN_I-1 + bandval;
> +
> +    g_array_append_val(bands, band);
> +
> +    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);
> +}
> +
> +/*****************************************************************************/
> +/* Load access technologies (Modem interface) */
> +
> +static gboolean
> +load_access_technologies_finish (MMIfaceModem *self,
> +                                 GAsyncResult *res,
> +                                 MMModemAccessTechnology *access_technologies,
> +                                 guint *mask,
> +                                 GError **error)
> +{
> +    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
> +        return FALSE;
> +
> +    *access_technologies = (MMModemAccessTechnology) GPOINTER_TO_UINT (
> +        g_simple_async_result_get_op_res_gpointer (
> +            G_SIMPLE_ASYNC_RESULT (res)));
> +    *mask = MM_MODEM_ACCESS_TECHNOLOGY_LTE;
> +    return TRUE;
> +}
> +
> +static void
> +load_access_technologies (MMIfaceModem *self,
> +                          GAsyncReadyCallback callback,
> +                          gpointer user_data)
> +{
> +    GSimpleAsyncResult *operation_result;
> +    MMModemAccessTechnology act;
> +
> +    operation_result = g_simple_async_result_new (G_OBJECT (self),
> +                                                  callback,
> +                                                  user_data,
> +                                                  load_access_technologies);
> +
> +
> +    act = MM_MODEM_ACCESS_TECHNOLOGY_LTE;
> +
> +    g_simple_async_result_set_op_res_gpointer (operation_result,
> +                                               GUINT_TO_POINTER (act),
> +                                               NULL);
> +    g_simple_async_result_complete_in_idle (operation_result);
> +    g_object_unref (operation_result);

Is this modem really LTE-only? Is there no way to query for the current
access tech at all? When the modem is neither registered nor searching
it will still say "LTE" in access tech...

I have tried looking into this issue.
I actually thought this function is redundant since the access technology is already
reported in CEREG , but then i found a bug / behavior that causes CEREG ACT not to be considered.

when CEREG first notifies Home (registered) - it sends the ACT with it - (and it will keep sending it in 
unsolicited responses). but the modem manager doesn't consider this Home state until it reads the operator data.
it is kept in some sort of "registering" state.

so when CEREG reports HOME+ correct ACT it is being thrown away since the 
mm_iface_modem_3gpp_update_access_technologies being called from registration_state_changed
only regards the ACT if the state is either HOME or ROAMING. but we are in the twilight zone ("registering") which isn't 
an official state.

and only after the loading of the operator code is over the state is changed to HOME (which is done after the call to 
mm_iface_modem_3gpp_update_access_technologies is over)

i think we should consider Adding this "registering" state as a valid state and have 
mm_iface_modem_3gpp_update_access_technologies accept this state for updating access tech.

i also think that the periodic_access_technologies_check_enable is redundant if we have CEREG unsolicited
to report a change of ACT.

if we are not making the above change and since we have no other method to get the ACT apart from CEREG - and 
periodic_access_technologies_check_enable is only done in REGISTERED state - i see no problem in reporting LTE 
all the time (since we are LTE only) as the code above is doing.

let me know your thoughts.



> +
> +}
> +
> +/*****************************************************************************/
> +/* 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)
> +{
> +    gchar *command;
> +    GError *error = NULL;
> +
> +    /* If the user sent a specific network to use, lock it in. */
> +    if (operator_id) {
> +        /* Currently only VZW is supported */
> +        g_set_error (&error,
> +                     MM_CORE_ERROR,
> +                     MM_CORE_ERROR_UNSUPPORTED,
> +                     "Setting a specific opretaror Id is not supported");

"opretaror" looks like a typo :)

> +
> +        g_simple_async_report_take_gerror_in_idle (G_OBJECT (self),
> +                                                   callback,
> +                                                   user_data,
> +                                                   error);

Use g_simple_async_report_error_in_idle() instead here, no need to
create the GError yourself.

> +        return;
> +    }
> +    else {
> +        command = g_strdup ("%CMATT=1");

No need to g_strdup() the command here (which actually was leaking),
just pass it to at_command_full().

> +    }
> +
> +    mm_base_modem_at_command_full (MM_BASE_MODEM (self),
> +                                   mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
> +                                   command,
> +                                   120,
> +                                   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,
> +} MMStatusConnectionManagerEventAlatir;

"Alatir" seems a typo. Also, we would usually name the enum as the
values of the enum, so the enum name here would be "MMStatcmAltair".

> +
> +static void
> +bearer_list_report_diconnect_status_foreach (MMBearer *bearer,
> +                                             gpointer *user_data)
> +{
> +    mm_bearer_report_disconnection(bearer);

Whitespace before the parenthesis.

> +}
> +
> +static void
> +altair_statcm_changed (MMAtSerialPort *port,
> +                       GMatchInfo *match_info,
> +                       MMBroadbandModemAltairLte *self)
> +{
> +    gchar *str;
> +    gint pdn_event;
> +    MMBearerList *list = NULL;
> +
> +    str = g_match_info_fetch (match_info, 1);
> +    pdn_event = atoi (str);
> +    g_free (str);

You can use mm_get_int_from_match_info() here.

> +
> +    mm_dbg("altair_statcm_changed %d",pdn_event);

Whitespace before the parenthesis.

> +
> +    /* 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)
> +{
> +    const int num_ports = 2;

No need for this 'num_ports' variable here, just use '2' in the code below.

> +    MMAtSerialPort *ports[num_ports];
> +    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 < num_ports; 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);
> +}
> +
> +/*****************************************************************************/
> +/* 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 const MMBaseModemAtCommand unsolicited_enable_sequence[] = {
> +    /* With ^PORTSEL we specify whether we want the PCUI port (0) or the
> +     * modem port (1) to receive the unsolicited messages */

What's this comment about ^PORTSEL?

> +    { "%STATCM=1", 5, FALSE, NULL },

If only one command in the sequence, just use
mm_base_modem_at_command_full() instead.

> +    { NULL }
> +};
> +
> +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_sequence_full (
> +        MM_BASE_MODEM (self),
> +        mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
> +        unsolicited_enable_sequence,
> +        NULL, /* response_processor_context */
> +        NULL, /* response_processor_context_free */
> +        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);
> +}
> +
> +
> +
> +/*****************************************************************************/
> +/* Operator Code loading (3GPP interface) */

You're missing modem_3gpp_load_operator_code_finish(). Don't assume that
the generic one will always be valid for you.

> +
> +static void
> +modem_3gpp_load_operator_code (MMIfaceModem3gpp *self,
> +                               GAsyncReadyCallback callback,
> +                               gpointer user_data)
> +{
> +    mm_dbg ("loading Operator Code...");
> +
> +    mm_base_modem_at_command (MM_BASE_MODEM (self),
> +                              "+COPS=3,2",
> +                              6,
> +                              FALSE,
> +                              NULL,
> +                              NULL);
> +
> +    mm_base_modem_at_command (MM_BASE_MODEM (self),
> +                              "+COPS?",
> +                              6,
> +                              FALSE,
> +                              callback,
> +                              user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Operator Name loading (3GPP interface) */

You're missing modem_3gpp_load_operator_name_finish(). Don't assume that
the generic one will always be valid for you.

> +
> +static void
> +modem_3gpp_load_operator_name (MMIfaceModem3gpp *self,
> +                               GAsyncReadyCallback callback,
> +                               gpointer user_data)
> +{
> +    mm_dbg ("Loading Operator Name...");
> +
> +    mm_base_modem_at_command (MM_BASE_MODEM (self),
> +                              "+COPS=3,0",
> +                              6,
> +                              FALSE,
> +                              NULL,
> +                              NULL);
> +
> +    mm_base_modem_at_command (MM_BASE_MODEM (self),
> +                              "+COPS?",
> +                              6,
> +                              FALSE,
> +                              callback,
> +                              user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Generic ports open/close context */


I truly believe you don't need to implement all this PortsContext stuff.


> +
> +struct _PortsContext {
> +    volatile gint ref_count;
> +
> +    MMAtSerialPort *primary;
> +    gboolean primary_open;
> +    MMAtSerialPort *secondary;
> +    gboolean secondary_open;
> +    MMQcdmSerialPort *qcdm;
> +    gboolean qcdm_open;
> +};
> +
> +static PortsContext *
> +ports_context_ref (PortsContext *ctx)
> +{
> +    g_atomic_int_inc (&ctx->ref_count);
> +    return ctx;
> +}
> +
> +static void
> +ports_context_unref (PortsContext *ctx)
> +{
> +    if (g_atomic_int_dec_and_test (&ctx->ref_count)) {
> +        if (ctx->primary) {
> +            if (ctx->primary_open)
> +                mm_serial_port_close (MM_SERIAL_PORT (ctx->primary));
> +            g_object_unref (ctx->primary);
> +        }
> +        if (ctx->secondary) {
> +            if (ctx->secondary_open)
> +                mm_serial_port_close (MM_SERIAL_PORT (ctx->secondary));
> +            g_object_unref (ctx->secondary);
> +        }
> +        if (ctx->qcdm) {
> +            if (ctx->qcdm_open)
> +                mm_serial_port_close (MM_SERIAL_PORT (ctx->qcdm));
> +            g_object_unref (ctx->qcdm);
> +        }
> +        g_free (ctx);
> +    }
> +}

You do need setup_ports(), though. You'll also need it to setup the
+CMEE call in the new MM_AT_SERIAL_PORT_INIT_SEQUENCE property.

> +
> +static void
> +setup_ports (MMBroadbandModem *self)
> +{
> +    /* Call parent's setup ports first always */
> +    MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_altair_lte_parent_class)->setup_ports (self);
> +
> +    g_object_set (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)),
> +                  MM_AT_SERIAL_PORT_SEND_LF, TRUE,
> +                  NULL);
> +
> +}


And I also believe you don't need all the initialization_started() and
initialization_stopped() logic, the generic implementation should be
more than enough.


> +/*****************************************************************************/
> +/* Initialization started/stopped */
> +
> +static gboolean
> +initialization_stopped (MMBroadbandModem *self,
> +                        gpointer user_data,
> +                        GError **error)
> +{
> +    PortsContext *ctx = (PortsContext *)user_data;
> +
> +    if (ctx)
> +        ports_context_unref (ctx);
> +    return TRUE;
> +}
> +
> +typedef struct {
> +    MMBroadbandModem *self;
> +    GSimpleAsyncResult *result;
> +    PortsContext *ports;
> +} InitializationStartedContext;
> +
> +static void
> +initialization_started_context_complete_and_free (InitializationStartedContext *ctx)
> +{
> +    g_simple_async_result_complete_in_idle (ctx->result);
> +    ports_context_unref (ctx->ports);
> +    g_object_unref (ctx->result);
> +    g_object_unref (ctx->self);
> +    g_free (ctx);
> +}
> +
> +static gpointer
> +initialization_started_finish (MMBroadbandModem *self,
> +                               GAsyncResult *res,
> +                               GError **error)
> +{
> +    gpointer ref;
> +
> +    if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
> +        return NULL;
> +
> +    ref = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
> +    return ref ? ports_context_ref (ref) : NULL;
> +}
> +
> +static gboolean
> +open_ports_initialization (MMBroadbandModem *self,
> +                           PortsContext *ctx,
> +                           GError **error)
> +{
> +    ctx->primary = mm_base_modem_get_port_primary (MM_BASE_MODEM (self));
> +    if (!ctx->primary) {
> +        g_set_error (error,
> +                     MM_CORE_ERROR,
> +                     MM_CORE_ERROR_FAILED,
> +                     "Couldn't get primary port");
> +        return FALSE;
> +    }
> +
> +    /* Open and send first commands to the primary serial port.
> +     * We do keep the primary port open during the whole initialization
> +     * sequence. Note that this port is not really passed to the interfaces,
> +     * they will get the primary port themselves. */
> +    if (!mm_serial_port_open (MM_SERIAL_PORT (ctx->primary), error)) {
> +        g_prefix_error (error, "Couldn't open primary port: ");
> +        return FALSE;
> +    }
> +
> +    ctx->primary_open = TRUE;
> +
> +    /* Try to get extended errors */
> +    mm_base_modem_at_command_full (MM_BASE_MODEM (self),
> +                                   ctx->primary,
> +                                   "+CMEE=1", 3,
> +                                   FALSE, FALSE, NULL, NULL, NULL);
> +
> +    return TRUE;
> +}
> +
> +static void
> +initialization_started (MMBroadbandModem *self,
> +                        GAsyncReadyCallback callback,
> +                        gpointer user_data)
> +{
> +    GError *error = NULL;
> +    InitializationStartedContext *ctx;
> +
> +    ctx = g_new0 (InitializationStartedContext, 1);
> +    ctx->self = g_object_ref (self);
> +    ctx->result = g_simple_async_result_new (G_OBJECT (self),
> +                                             callback,
> +                                             user_data,
> +                                             initialization_started);
> +    ctx->ports = g_new0 (PortsContext, 1);
> +    ctx->ports->ref_count = 1;
> +
> +    if (!open_ports_initialization (self, ctx->ports, &error)) {
> +        g_prefix_error (&error, "Couldn't open ports during modem initialization: ");
> +        g_simple_async_result_take_error (ctx->result, error);
> +    } else
> +        g_simple_async_result_set_op_res_gpointer (ctx->result,
> +                                                   ports_context_ref (ctx->ports),
> +                                                   (GDestroyNotify)ports_context_unref);
> +
> +    initialization_started_context_complete_and_free (ctx);
> +}
> +/*****************************************************************************/
> +
> +MMBroadbandModemAltairLte *
> +mm_broadband_modem_altair_lte_new (const gchar *device,
> +                                    const gchar **drivers,
> +                                    const gchar *plugin,
> +                                    guint16 vendor_id,
> +                                    guint16 product_id)
> +{
> +    return g_object_new (MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE,
> +                         MM_BASE_MODEM_DEVICE, device,
> +                         MM_BASE_MODEM_DRIVERS, drivers,
> +                         MM_BASE_MODEM_PLUGIN, plugin,
> +                         MM_BASE_MODEM_VENDOR_ID, vendor_id,
> +                         MM_BASE_MODEM_PRODUCT_ID, product_id,
> +                         /*Temporarily allows only EPS network registration status */
> +                         /* TODO(orii): Remove this constraint once the CGREG bug is fixed*/

So it seems you're currently making the modem LTE-only while it really
isn't? :)

my bad - this is not temporary - we are LTE only. 
 

> +                         MM_IFACE_MODEM_3GPP_CS_NETWORK_SUPPORTED, FALSE,
> +                         MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED, FALSE,
> +                         MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED, TRUE,
> +                         NULL);
> +}
> +
> +static void
> +mm_broadband_modem_altair_lte_init (MMBroadbandModemAltairLte *self)
> +{
> +
> +    /* Initialize private data */
> +    self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
> +                                              MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE,
> +                                              MMBroadbandModemAltairLtePrivate);
> +
> +    self->priv->statcm_regex = g_regex_new ("\\r\\n\\%STATCM:\\s*(\\d*),?(\\d*)\\r+\\n",
> +                                            G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
> +}
> +
> +static void
> +iface_modem_init (MMIfaceModem *iface)
> +{
> +    iface->modem_init = modem_init;
> +    iface->modem_init_finish = modem_init_finish;
> +
> +    iface->modem_power_up = modem_power_up;
> +    iface->modem_power_up_finish = modem_power_up_finish;
> +
> +    iface->modem_power_down = modem_power_down;
> +    iface->modem_power_down_finish = modem_power_down_finish;
> +    iface->create_bearer = modem_create_bearer;
> +    iface->create_bearer_finish = modem_create_bearer_finish;
> +    iface->load_current_capabilities = load_current_capabilities;
> +    iface->load_current_capabilities_finish = load_current_capabilities_finish;
> +    iface->load_supported_bands = load_supported_bands;
> +    iface->load_supported_bands_finish = load_supported_bands_finish;
> +    iface->load_current_bands = load_current_bands;
> +    iface->load_current_bands_finish = load_current_bands_finish;
> +
> +    iface->load_access_technologies = load_access_technologies;
> +    iface->load_access_technologies_finish = load_access_technologies_finish;
> +    iface->reset = reset;
> +    iface->reset_finish = reset_finish;
> +
> +    iface->load_supported_charsets = NULL;
> +    iface->load_supported_charsets_finish = NULL;
> +    iface->setup_charset = NULL;
> +    iface->setup_charset_finish = NULL;
> +
> +}
> +
> +static void
> +iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
> +{
> +
> +    iface_modem_3gpp_parent = g_type_interface_peek_parent (iface);
> +
> +    iface->setup_unsolicited_events = modem_3gpp_setup_unsolicited_events;
> +    iface->setup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish;
> +    iface->cleanup_unsolicited_events = modem_3gpp_cleanup_unsolicited_events;
> +    iface->cleanup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish;
> +    iface->enable_unsolicited_events = modem_3gpp_enable_unsolicited_events;
> +    iface->enable_unsolicited_events_finish = modem_3gpp_enable_unsolicited_events_finish;
> +    iface->disable_unsolicited_events = modem_3gpp_disable_unsolicited_events;
> +    iface->disable_unsolicited_events_finish = modem_3gpp_disable_unsolicited_events_finish;
> +
> +    iface->register_in_network = modem_3gpp_register_in_network;
> +    iface->register_in_network_finish = modem_3gpp_register_in_network_finish;
> +
> +    /* currently only VZW is supported - so we disable the scan network feature */
> +    iface->scan_networks = NULL;
> +    iface->scan_networks_finish = NULL;

Is this really the way to go? Why not just leave it there?

since this is VZW only implementation currently - i don;t want to allow scanning. 

> +
> +    /* Additional actions */
> +    iface->load_operator_code = modem_3gpp_load_operator_code;
> +    iface->load_operator_name = modem_3gpp_load_operator_name;
> +
> +}
> +
> +static void
> +iface_modem_messaging_init (MMIfaceModemMessaging *iface)
> +{
> +    /* Currently no messaging is implemented - so skip checking*/
> +    iface->check_support = NULL;
> +    iface->check_support_finish = NULL;
> +}
> +
> +static void
> +mm_broadband_modem_altair_lte_class_init (MMBroadbandModemAltairLteClass *klass)
> +{
> +    GObjectClass *object_class = G_OBJECT_CLASS (klass);
> +    MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
> +
> +    g_type_class_add_private (object_class, sizeof (MMBroadbandModemAltairLtePrivate));
> +
> +    broadband_modem_class->setup_ports = setup_ports;
> +
> +    broadband_modem_class->initialization_started = initialization_started;
> +    broadband_modem_class->initialization_started_finish = initialization_started_finish;
> +    broadband_modem_class->initialization_stopped = initialization_stopped;
> +}
> diff --git a/plugins/altair/mm-broadband-modem-altair-lte.h b/plugins/altair/mm-broadband-modem-altair-lte.h
> new file mode 100644
> index 0000000..50c9f3e
> --- /dev/null
> +++ b/plugins/altair/mm-broadband-modem-altair-lte.h
> @@ -0,0 +1,51 @@
> +/* -*- 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_MODEM_ALTAIR_LTE_H
> +#define MM_BROADBAND_MODEM_ALTAIR_LTE_H
> +
> +#include "mm-broadband-modem.h"
> +
> +#define MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE            (mm_broadband_modem_altair_lte_get_type ())
> +#define MM_BROADBAND_MODEM_ALTAIR_LTE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE, MMBroadbandModemAltairLte))
> +#define MM_BROADBAND_MODEM_ALTAIR_LTE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE, MMBroadbandModemAltairLteClass))
> +#define MM_IS_BROADBAND_MODEM_ALTAIR_LTE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE))
> +#define MM_IS_BROADBAND_MODEM_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE))
> +#define MM_BROADBAND_MODEM_ALTAIR_LTE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE, MMBroadbandModemAltairLteClass))
> +
> +typedef struct _MMBroadbandModemAltairLte MMBroadbandModemAltairLte;
> +typedef struct _MMBroadbandModemAltairLteClass MMBroadbandModemAltairLteClass;
> +typedef struct _MMBroadbandModemAltairLtePrivate MMBroadbandModemAltairLtePrivate;
> +
> +struct _MMBroadbandModemAltairLte {
> +    MMBroadbandModem parent;
> +    MMBroadbandModemAltairLtePrivate *priv;
> +};
> +
> +struct _MMBroadbandModemAltairLteClass{
> +    MMBroadbandModemClass parent;
> +};
> +
> +GType mm_broadband_modem_altair_lte_get_type (void);
> +
> +MMBroadbandModemAltairLte *mm_broadband_modem_altair_lte_new (const gchar *device,
> +                                                              const gchar **drivers,
> +                                                              const gchar *plugin,
> +                                                              guint16 vendor_id,
> +                                                              guint16 product_id);
> +
> +#endif /* MM_BROADBAND_MODEM_ALTAIR_LTE_H */
> diff --git a/plugins/altair/mm-plugin-altair-lte.c b/plugins/altair/mm-plugin-altair-lte.c
> new file mode 100644
> index 0000000..1f6f869
> --- /dev/null
> +++ b/plugins/altair/mm-plugin-altair-lte.c
> @@ -0,0 +1,95 @@
> +/* -*- 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.
> + *
> + * 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., 59 Temple Place - Suite 330,
> + * Boston, MA 02111-1307, USA.
> + *
> + * Copyright (C) 2013 Altair Semiconductor
> + *
> + * Author: Ori Inbar <ori inbar altair-semi com>
> + */
> +
> +#include <string.h>
> +#include <gmodule.h>
> +
> +#include "mm-plugin-altair-lte.h"
> +#include "mm-private-boxed-types.h"
> +#include "mm-broadband-modem-altair-lte.h"
> +#include "mm-log.h"
> +
> +G_DEFINE_TYPE (MMPluginAltairLte, mm_plugin_altair_lte, MM_TYPE_PLUGIN)
> +
> +int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
> +int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
> +
> +static MMBaseModem *
> +create_modem (MMPlugin *self,
> +              const gchar *sysfs_path,
> +              const gchar **drivers,
> +              guint16 vendor,
> +              guint16 product,
> +              GList *probes,
> +              GError **error)
> +{
> +    return MM_BASE_MODEM (mm_broadband_modem_altair_lte_new (sysfs_path,
> +                                                              drivers,
> +                                                              mm_plugin_get_name (self),
> +                                                              vendor,
> +                                                              product));
> +}
> +/*****************************************************************************/
> +/* Custom commands for AT probing */
> +
> +/* just give a litte more time to answer
> + */
> +static const MMPortProbeAtCommand custom_at_probe[] = {
> +    { "AT", 3, mm_port_probe_response_processor_is_at },
> +    { "AT", 6, mm_port_probe_response_processor_is_at },
> +    { "AT", 9, mm_port_probe_response_processor_is_at },
> +    { NULL }

Is it really not enough with the current AT probing?

> +};
> +/*****************************************************************************/
> +G_MODULE_EXPORT MMPlugin *
> +mm_plugin_create (void)
> +{
> +    static const gchar *subsystems[] = { "tty", "net", NULL };
> +    static const mm_uint16_pair products[] = {
> +        { 0x216f, 0x0047 }, /* Altair NPe */
> +        { 0, 0 }
> +    };
> +
> +    return MM_PLUGIN (
> +        g_object_new (MM_TYPE_PLUGIN_ALTAIR_LTE,
> +                      MM_PLUGIN_NAME,                "Altair LTE",
> +                      MM_PLUGIN_ALLOWED_SUBSYSTEMS,  subsystems,
> +                      MM_PLUGIN_ALLOWED_PRODUCT_IDS, products,
> +                      MM_PLUGIN_ALLOWED_SINGLE_AT,   TRUE,
> +                      MM_PLUGIN_CUSTOM_AT_PROBE,     custom_at_probe,
> +                      MM_PLUGIN_SEND_LF,             TRUE,
> +                      NULL));
> +}
> +
> +static void
> +mm_plugin_altair_lte_init (MMPluginAltairLte *self)
> +{
> +}
> +
> +static void
> +mm_plugin_altair_lte_class_init (MMPluginAltairLteClass *klass)
> +{
> +    MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
> +
> +    plugin_class->create_modem = create_modem;
> +}
> diff --git a/plugins/altair/mm-plugin-altair-lte.h b/plugins/altair/mm-plugin-altair-lte.h
> new file mode 100644
> index 0000000..385a5cc
> --- /dev/null
> +++ b/plugins/altair/mm-plugin-altair-lte.h
> @@ -0,0 +1,48 @@
> +/* -*- 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.
> + *
> + * 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., 59 Temple Place - Suite 330,
> + * Boston, MA 02111-1307, USA.
> + *
> + * Copyright (C) 2013 Altair Semiconductor
> + *
> + * Author: Ori Inbar <ori inbar altair-semi com>
> + */
> +
> +#ifndef MM_PLUGIN_ALTAIR_LTE_H
> +#define MM_PLUGIN_ALTAIR_LTE_H
> +
> +#include "mm-plugin.h"
> +
> +#define MM_TYPE_PLUGIN_ALTAIR_LTE            (mm_plugin_altair_lte_get_type ())
> +#define MM_PLUGIN_ALTAIR_LTE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_ALTAIR_LTE, MMPluginAltairLte))
> +#define MM_PLUGIN_ALTAIR_LTE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  MM_TYPE_PLUGIN_ALTAIR_LTE, MMPluginAltairLteClass))
> +#define MM_IS_PLUGIN_ALTAIR_LTE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_ALTAIR_LTE))
> +#define MM_IS_PLUGIN_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  MM_TYPE_PLUGIN_ALTAIR_LTE))
> +#define MM_PLUGIN_ALTAIR_LTE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  MM_TYPE_PLUGIN_ALTAIR_LTE, MMPluginAltairLteClass))
> +
> +typedef struct {
> +    MMPlugin parent;
> +} MMPluginAltairLte;
> +
> +typedef struct {
> +    MMPluginClass parent;
> +} MMPluginAltairLteClass;
> +
> +GType mm_plugin_altair_lte_get_type (void);
> +
> +G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
> +
> +#endif /* MM_PLUGIN_ALTAIR_LTE_H */
> diff --git a/src/77-mm-usb-device-blacklist.rules b/src/77-mm-usb-device-blacklist.rules
> index 355bec3..544289f 100644
> --- a/src/77-mm-usb-device-blacklist.rules
> +++ b/src/77-mm-usb-device-blacklist.rules
> @@ -80,4 +80,7 @@ ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb00" ENV{ID_MM_DEVICE_IGNORE}="1"
>  # All devices from the Swiss Federal Institute of Technology
>  ATTRS{idVendor}=="0617", ENV{ID_MM_DEVICE_IGNORE}="1"
>
> +# Altair U-Boot device
> +ATTRS{idVendor}=="0216", ATTRS{idProduct}=="0051" ENV{ID_MM_DEVICE_IGNORE}="1"
> +
>  LABEL="mm_usb_device_blacklist_end"
>


--
Aleksander



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]