[PATCH] New Modem Manager Plugin for GCT Semiconductor's GDM724X usb devices
Aleksander Morgado
aleksander at lanedo.com
Mon Aug 12 02:37:01 PDT 2013
Hey!
On 08/08/13 13:34, Won Kang wrote:
> Signed-off-by: Won Kang <wonkang at gctsemi.com>
> ---
> plugins/Makefile.am | 16 +-
> plugins/gct/mm-broadband-bearer-gct.c | 1121 +++++++++++++++++++++++++++
> plugins/gct/mm-broadband-bearer-gct.h | 70 ++
> plugins/gct/mm-broadband-modem-gct.c | 1333 +++++++++++++++++++++++++++++++++
> plugins/gct/mm-broadband-modem-gct.h | 54 ++
> plugins/gct/mm-plugin-gct.c | 224 ++++++
> plugins/gct/mm-plugin-gct.h | 47 ++
> plugins/gct/mm-sim-gct.c | 131 ++++
> plugins/gct/mm-sim-gct.h | 52 ++
> 9 files changed, 3047 insertions(+), 1 deletion(-)
> create mode 100644 plugins/gct/mm-broadband-bearer-gct.c
> create mode 100644 plugins/gct/mm-broadband-bearer-gct.h
> create mode 100644 plugins/gct/mm-broadband-modem-gct.c
> create mode 100644 plugins/gct/mm-broadband-modem-gct.h
> create mode 100644 plugins/gct/mm-plugin-gct.c
> create mode 100644 plugins/gct/mm-plugin-gct.h
> create mode 100644 plugins/gct/mm-sim-gct.c
> create mode 100644 plugins/gct/mm-sim-gct.h
>
Please fix all the stuff reported in my inline comments below, and try
to reply to the questions I ask. I may have missed some coding style
changes; if you see more than those I already pointed you at, please
also fix them.
Regarding the overall logic, it looks kind of ok, except for some things
noted below.
As we don't have a modem to test with, also please attach a debug log of
ModemManager while running with this modem, including various things
like modem detection, connection, SMS retrieval and such.
Cheers!
> diff --git a/plugins/Makefile.am b/plugins/Makefile.am
> index 83f1fae..b3b3b6d 100644
> --- a/plugins/Makefile.am
> +++ b/plugins/Makefile.am
> @@ -77,7 +77,8 @@ pkglib_LTLIBRARIES = \
> libmm-plugin-sierra.la \
> libmm-plugin-mbm.la \
> libmm-plugin-via.la \
> - libmm-plugin-telit.la
> + libmm-plugin-telit.la \
> + libmm-plugin-gct.la
>
> # Generic
> libmm_plugin_generic_la_SOURCES = \
> @@ -297,6 +298,19 @@ libmm_plugin_samsung_la_CPPFLAGS = $(PLUGIN_COMMON_COMPILER_FLAGS) $(ICERA_COMMO
> libmm_plugin_samsung_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
> libmm_plugin_samsung_la_LIBADD = $(ICERA_COMMON_LIBADD_FLAGS)
>
> +# Gct modem
> +libmm_plugin_gct_la_SOURCES = \
> + gct/mm-plugin-gct.c \
> + gct/mm-plugin-gct.h \
> + gct/mm-broadband-modem-gct.c \
> + gct/mm-broadband-modem-gct.h \
> + gct/mm-broadband-bearer-gct.c \
> + gct/mm-broadband-bearer-gct.h \
> + gct/mm-sim-gct.c \
> + gct/mm-sim-gct.h
> +libmm_plugin_gct_la_CPPFLAGS = $(PLUGIN_COMMON_COMPILER_FLAGS)
> +libmm_plugin_gct_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
> +
> # Cinterion (previously Siemens) modem
> libmm_plugin_cinterion_la_SOURCES = \
> cinterion/mm-plugin-cinterion.c \
> diff --git a/plugins/gct/mm-broadband-bearer-gct.c b/plugins/gct/mm-broadband-bearer-gct.c
> new file mode 100644
> index 0000000..3f23f08
> --- /dev/null
> +++ b/plugins/gct/mm-broadband-bearer-gct.c
> @@ -0,0 +1,1121 @@
> +/* -*- 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 GCT Semiconductor, Inc.
> + * Author: Glen Lee <glenlee at gctsemi.com>
> + */
> +
> +#include <config.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <ctype.h>
> +#include <arpa/inet.h>
> +
> +#include <ModemManager.h>
> +#define _LIBMM_INSIDE_MM
> +#include <libmm-glib.h>
> +
> +#include "mm-base-modem-at.h"
> +#include "mm-broadband-bearer-gct.h"
> +#include "mm-log.h"
> +#include "mm-modem-helpers.h"
> +#include "mm-iface-modem.h"
> +#include "mm-iface-modem-3gpp.h"
> +
> +G_DEFINE_TYPE (MMBroadbandBearerGct, mm_broadband_bearer_gct, MM_TYPE_BROADBAND_BEARER);
You don't need the last semicolon.
> +
> +#define MAX_CID_SUPPORTED 4
> +
> +#define CGCONTRDP_TAG "+CGCONTRDP: "
> +#define GCTNETCFG_TAG "%GCTNETCFG: "
> +
> +typedef enum {
> + MM_BEARER_IP_TYPE_NONE = 0,
> + MM_BEARER_IP_TYPE_V4 = 1 << 0,
> + MM_BEARER_IP_TYPE_V6 = 1 << 1
> +} MMBearerIpType;
Can't you re-use the MMBearerIpFamily enum?
> +
> +struct _MMBroadbandBearerGctPrivate {
> + guint auth_idx;
> + gpointer connect_pending;
> + guint connect_pending_id;
> + gulong connect_cancellable_id;
> + gulong connect_port_closed_id;
> + MMBearerIpType ip_type;
For the looks of it, 'ip_type' here is used as part of the logic during
the IP config retrieval logic. Shouldn't you declare it inside
GetIpConfig3gppContext instead?
> +};
> +
> +/*****************************************************************************/
> +/* 3GPP IP config retrieval (sub-step of the 3GPP Connection sequence) */
> +
> +typedef enum {
> + GET_IP_STEP_FIRST,
> + GET_IP_STEP_SECOND,
> + GET_IP_STEP_LAST
> +} GetIp3gppConfigStep;
> +
> +typedef struct {
> + guint cid;
> + guint nic_type;
> + guint internal_type;
> +} GctNetCfg;
> +
> +typedef struct {
> + MMBroadbandBearerGct *self;
> + MMBearerIpConfig *ipv4_config;
> + MMBearerIpConfig *ipv6_config;
> +} MMBearerIpConfigSet;
> +
> +typedef struct {
> + MMBroadbandBearerGct *self;
> + MMBaseModem *modem;
> + MMAtSerialPort *primary;
> + guint cid;
> + GSimpleAsyncResult *result;
> + guint gct_net_conf_cnt;
> + GctNetCfg gct_net_conf[5];
> + GetIp3gppConfigStep step;
> +} GetIpConfig3gppContext;
> +
> +static guint
> +char_cnt(gchar *ptr, gchar ch)
Whitespace before '('.
> +{
> + guint i = 0;
> +
> + while(*ptr)
Whitespace before '('.
> + if(*ptr++ == ch)
Whitespace before '('.
> + i++;
> +
> + return i;
> +}
> +
> +static void
> +get_ip_config_context_complete_and_free (GetIpConfig3gppContext *ctx)
> +{
> + g_simple_async_result_complete_in_idle (ctx->result);
> + g_object_unref (ctx->result);
> + g_object_unref (ctx->primary);
> + g_object_unref (ctx->modem);
> + g_object_unref (ctx->self);
> + g_slice_free (GetIpConfig3gppContext, ctx);
> +}
> +
> +static gboolean
> +get_ip_config_3gpp_finish (MMBroadbandBearer *self,
> + GAsyncResult *res,
> + MMBearerIpConfig **ipv4_config,
> + MMBearerIpConfig **ipv6_config,
> + GError **error)
> +{
> + MMBearerIpConfigSet *ip_config_set;
> +
> + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
> + return FALSE;
> +
> + ip_config_set = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
> +
> + mm_dbg("Bearer IPv4 configuration %s", ip_config_set->ipv4_config ? "SET" : "NOT SET");
Whitespace before '('.
> + mm_dbg("Bearer IPv6 configuration %s", ip_config_set->ipv6_config ? "SET" : "NOT SET");
Whitespace before '('.
> +
> + *ipv4_config = ip_config_set->ipv4_config ? g_object_ref (ip_config_set->ipv4_config) : NULL;
> + *ipv6_config = ip_config_set->ipv6_config ? g_object_ref (ip_config_set->ipv6_config) : NULL;
> +
> + return TRUE;
> +}
> +
> +static void
> +_bearer_ipv4_config_set_gateway_and_prefix(MMBearerIpConfigSet *ip_config_set, gchar *ip)
Whitespace before '('.
Also, give each parameter its own line.
> +{
> + gint prefix = 0;
> + struct in_addr inp;
> + guint32 ipv4;
> + guint32 gateway;
> + gchar net;
> +
> + if (!inet_pton (AF_INET, ip, &ipv4)) {
> + /* Error converting IP */
> + return;
> + }
> +
> + net = ipv4 & 0xFF;
> +
> + /* prefix calculation based on default ip class */
> + if ((net & 0x80) == 0)
> + prefix = 8;
> + else if ((net & 0xC0) == 0x80)
> + prefix = 16;
> + else if ((net & 0xE0) == 0xC0)
> + prefix = 24;
> +
> + /* fake gateway based on the inverted value of the last octet of the ip address */
Is this really the way to go? Can't you just go on without an explicit
gateway?
> + gateway = ipv4;
> + gateway &= 0x00FFFFFF;
> + gateway |= (~ipv4) & 0xFF000000;
> + memcpy(&inp, &gateway, sizeof(struct in_addr));
Whitespace before '('.
> +
> + mm_dbg("ipv4 address: %d,%d,%d,%d/%d",
Whitespace before '('.
> + ipv4>>0 & 0xFF,
> + ipv4>>8 & 0xFF,
> + ipv4>>16 & 0xFF,
> + ipv4>>24 & 0xFF,
> + prefix
> + );
> + mm_dbg("ipv4 gateway: %d.%d.%d.%d",
Whitespace before '('.
> + gateway>>0 & 0xFF,
> + gateway>>8 & 0xFF,
> + gateway>>16 & 0xFF,
> + gateway>>24 & 0xFF
> + );
> +
> + /* configure the prefix and gateway */
> + mm_bearer_ip_config_set_prefix (ip_config_set->ipv4_config, prefix);
> + mm_bearer_ip_config_set_gateway (ip_config_set->ipv4_config, inet_ntoa(inp));
Whitespace after inet_ntoa and before '('.
> +}
> +
> +static void
> +run_get_ip_config_context_step (GetIpConfig3gppContext *ctx);
> +
> +static void
> +ip_config_ready (MMBaseModem *modem,
> + GAsyncResult *res,
> + GetIpConfig3gppContext *ctx)
> +{
> + MMBearerIpConfigSet *ip_config_set = NULL;
> + const gchar *response;
> + GError *error = NULL;
> + gchar **items;
> + gchar *dns_v4[3] = { 0, };
> + gchar *dns_v6[3] = { 0, };
> + guint i;
> + guint gct_loop;
> + guint dns_i;
> + gchar *items_sub;
> + gchar **lines;
> + gchar **iter;
> + guint32 tmp_ipv4;
> + struct in6_addr tmp_pv6;
> + gchar* ip;
> +
> + ip_config_set = (MMBearerIpConfigSet *)g_malloc0(sizeof(MMBearerIpConfigSet));
Whitespaces before the various '('.
> + ip_config_set->self = ctx->self;
You don't need ->self in ip_config_set for anything, just remove it from
the struct.
> +
> + response = mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error);
> + if (error) {
> + g_simple_async_result_take_error (ctx->result, error);
> + get_ip_config_context_complete_and_free (ctx);
> + return;
> + }
> +
> + /*
> + * TODO: use a regex to parse this
> + * The response for IPv6 would be something like the following
> +
> + +CGCONTRDP: 3,6,"vzwinternet.mnc480.mcc311.gprs","10.168.86.201","","198.224.174.135","198.224.173.135","",""
> +
> + +CGCONTRDP: 3,6,"vzwinternet.mnc480.mcc311.gprs","38.0.16.16.177.35.78.84.0.0.0.25.171.20.242.1","","32.1.72.136.0.97.255.0.6.4.0.13.0.0.0.0","32.1.72.136.0.104.255.0.6.8.0.13.0.0.0.0","32.1.72.136.0.3.255.240.0.192.1.4.0.0.0.83","32.1.72.136.0.2.255.240.0.160.1.4.0.0.0.83"
> +
> + OK
All comment lines should start with '*'
> + */
> +
> + lines = g_strsplit_set (response, "\r\n", 0);
> + if (!lines)
> + {
The '{' goes in the same line as the if().
> + get_ip_config_context_complete_and_free (ctx);
You probably need to g_simple_async_result_set_error() before
complete_and_free().
> + return;
> + }
> +
> + for (iter = lines; iter && *iter; iter++) {
> +
> + /* skip emtpy line */
'emtpy' seems a typo :)
> + if (!g_str_has_prefix (*iter, CGCONTRDP_TAG)) {
> + continue;
> + }
> +
> + items = g_strsplit ( mm_strip_tag (*iter, CGCONTRDP_TAG), ",", 0);
No whitespace needed after '('.
> +
> + for (i = 0, dns_i = 0; items[i]; i++) {
> + if (i == 0) { /* CID */
> + gint num;
> +
> + if (!mm_get_int_from_str (items[i], &num) ||
> + num != ctx->cid) {
> + error = g_error_new (MM_CORE_ERROR,
> + MM_CORE_ERROR_FAILED,
> + "Unknown CID in CGCONTRDP response ("
> + "got %d, expected %d)", (guint) num, ctx->cid);
> + break;
> + }
> +
> + } else if (i == 1) { /* bearer id */
> + /* Do nothing */
> + } else if (i == 2) { /* APN */
> + /* Do nothing */
> + } else if (i == 3) { /* IP address */
> +
> + for( gct_loop = 0; gct_loop < ctx->gct_net_conf_cnt; gct_loop++)
> + {
The '{' goes in the same line as the for().
> + if (ctx->gct_net_conf[gct_loop].cid == ctx->cid)
> + {
The '{' goes in the same line as the if().
> + guint internal_type;
Whiteline needed after variable declarations.
> + internal_type= ctx->gct_net_conf[gct_loop].internal_type;
Whitespace needed before '='.
> + mm_dbg("ip config: cid %d, internal pdn %d", ctx->cid, internal_type);
Whitespace needed before '('.
> +
> + if(internal_type)
Whitespace needed before '('.
> + goto skip_ip_configuration;
Not sure how, but this logic is already too complex; can you skip the
goto somehow?
> + }
> +
> + }
> +
> + /* Remove the starting and ending quatation mark */
> + items_sub = g_strndup (items[i] + 1, strlen(items[i]) - 2);
> +
> + if (char_cnt(items_sub, '.') == 3) /* IPv4 */
Whitespace needed before '('.
> + {
The '{' goes in the same line as the if().
> + if (!inet_pton (AF_INET, items_sub, &tmp_ipv4))
> + {
The '{' goes in the same line as the if().
> + g_clear_object (&ip_config_set);
> + g_free(items_sub);
> + break;
> + }
> +
> + ip_config_set->ipv4_config = mm_bearer_ip_config_new ();
> + mm_bearer_ip_config_set_method (ip_config_set->ipv4_config, MM_BEARER_IP_METHOD_STATIC);
> + mm_bearer_ip_config_set_address (ip_config_set->ipv4_config, items_sub);
> + _bearer_ipv4_config_set_gateway_and_prefix(ip_config_set, items_sub);
Whitespace needed before '('.
> +
> + ctx->self->priv->ip_type = MM_BEARER_IP_TYPE_V4;
> + }
> + else if (char_cnt(items_sub, '.') == 15) /* IPv6 */
The 'else if' goes in the same line as the previous '}'; also whitespace
before the '('.
> + {
The '{' goes in the same line as the if().
> + gchar **items_ipv6 = g_strsplit (items_sub, ".", 0);
Whiteline between variable declarations and the first method call. So
first declare the variable, then whiteline, and then the g_strsplit() call.
> +
> + ip = g_strdup_printf ("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
> + atoi(items_ipv6[0]),
> + atoi(items_ipv6[1]),
> + atoi(items_ipv6[2]),
> + atoi(items_ipv6[3]),
> + atoi(items_ipv6[4]),
> + atoi(items_ipv6[5]),
> + atoi(items_ipv6[6]),
> + atoi(items_ipv6[7]),
> + atoi(items_ipv6[8]),
> + atoi(items_ipv6[9]),
> + atoi(items_ipv6[10]),
> + atoi(items_ipv6[11]),
> + atoi(items_ipv6[12]),
> + atoi(items_ipv6[13]),
> + atoi(items_ipv6[14]),
> + atoi(items_ipv6[15]));
In all the previous lines, whitespace before the '('.
> + g_free(items_ipv6);
Whitespace needed before '('.
> +
> + if (!inet_pton (AF_INET6, ip, &tmp_pv6))
> + {
The '{' goes in the same line as the if().
> + g_clear_object (&ip_config_set);
> + g_free(ip);
> + g_free(items_sub);
> + break;
> + }
> +
> + ip_config_set->ipv6_config = mm_bearer_ip_config_new ();
> +
> + mm_bearer_ip_config_set_method (ip_config_set->ipv6_config, MM_BEARER_IP_METHOD_STATIC);
> + mm_bearer_ip_config_set_address (ip_config_set->ipv6_config, ip);
> +
> + ctx->self->priv->ip_type = MM_BEARER_IP_TYPE_V6;
> + g_free(ip);
Whitespace needed before '('.
> + }
> +
> + g_free(items_sub);
Whitespace needed before '('.
> + }
> + else if (i == 5 || i == 6) { /* DNS entries */
The 'else if' goes in the same line as the previous '}'.
> + items_sub = g_strndup (items[i] + 1, strlen(items[i]) - 2);
> +
> + if (ctx->self->priv->ip_type == MM_BEARER_IP_TYPE_V4)
> + {
The '{' goes in the same line as the if().
> + mm_dbg("ipv4 dns: %s", items_sub);
Whitespace needed before '('.
> + if (inet_pton (AF_INET, items_sub, &tmp_ipv4)) {
> + dns_v4[dns_i++] = g_strdup(items_sub);
> + }
> + }
> + else if (ctx->self->priv->ip_type == MM_BEARER_IP_TYPE_V6)
The 'else if' goes in the same line as the previous '}'.
> + {
The '{' goes in the same line as the if().
> + gchar **items_ipv6 = g_strsplit (items_sub, ".", 0);
Whiteline between variable declarations and the first method call. So
first declare the variable, then whiteline, and then the g_strsplit() call.
> + ip = g_strdup_printf ("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
> + atoi(items_ipv6[0]),
> + atoi(items_ipv6[1]),
> + atoi(items_ipv6[2]),
> + atoi(items_ipv6[3]),
> + atoi(items_ipv6[4]),
> + atoi(items_ipv6[5]),
> + atoi(items_ipv6[6]),
> + atoi(items_ipv6[7]),
> + atoi(items_ipv6[8]),
> + atoi(items_ipv6[9]),
> + atoi(items_ipv6[10]),
> + atoi(items_ipv6[11]),
> + atoi(items_ipv6[12]),
> + atoi(items_ipv6[13]),
> + atoi(items_ipv6[14]),
> + atoi(items_ipv6[15]));
In all the previous lines, whitespace before the '('.
> + g_free(items_ipv6);
Whitespace before the '('.
> + mm_dbg("ipv4 dns: %s", items_sub);
Whitespace before the '('.
> + if (inet_pton (AF_INET6, ip, &tmp_pv6)) {
> + dns_v6[dns_i++] = g_strdup(ip);
Whitespace before the '('.
> + }
> +
> + g_free(ip);
Whitespace before the '('.
> + }
> + g_free(items_sub);
Whitespace before the '('.
> + }
> + }
> +skip_ip_configuration:
> + g_strfreev (items);
> + }
> +
> + if (!ip_config_set) {
> + if (error)
> + g_simple_async_result_take_error (ctx->result, error);
> + else
> + g_simple_async_result_set_error (ctx->result,
> + MM_CORE_ERROR,
> + MM_CORE_ERROR_FAILED,
> + "Couldn't get IP config: couldn't parse response '%s'",
> + response);
> + } else {
> + guint k;
> +
> + /* If we got IPv4 DNS entries, set them in the IP config */
> + if (dns_v4[0])
> + {
The '{' goes in the same line as the if().
> + mm_bearer_ip_config_set_dns (ip_config_set->ipv4_config, (const gchar **)dns_v4);
> + for (k=0; dns_v4[k]; k++)
> + g_free(dns_v4[k]);
> + }
> +
> + /* If we got IPv6 DNS entries, set them in the IP config */
> + if (dns_v6[0])
> + {
The '{' goes in the same line as the if().
> + mm_bearer_ip_config_set_dns (ip_config_set->ipv6_config, (const gchar **)dns_v6);
> + for (k=0; dns_v6[k]; k++)
> + g_free(dns_v6[k]);
Whitespace before the '('.
> + }
> +
> + g_simple_async_result_set_op_res_gpointer (ctx->result,
> + ip_config_set,
> + (GDestroyNotify)g_object_unref);
ip_config_set is a struct, not a GObject. Therefore the GDestroyNotify
callback needs to be 'g_free' not 'g_object_unref'.
> + }
> +
> + ctx->step++;
> + run_get_ip_config_context_step(ctx);
Whitespace before the '('.
> +
> + g_strfreev (lines);
> +
> +}
> +
> +static void
> +gct_net_config_ready (MMBaseModem *modem,
> + GAsyncResult *res,
> + GetIpConfig3gppContext *ctx)
Parameters need alignment.
> +{
> + const gchar *response;
> + GError *error = NULL;
> + gchar **lines;
> + gchar **iter;
> + guint gct_net_conf_cnt = 0;
> +
> + gint cid;
> + gint nic_type;
> + gint internal_type;
> +
> + response = mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error);
> +
> + if (error) {
> + g_simple_async_result_take_error (ctx->result, error);
> + get_ip_config_context_complete_and_free (ctx);
> + return;
> + }
> +
> + lines = g_strsplit_set (response, "\r\n", 0);
> + if (!lines)
> + {
The '{' goes in the same line as the if().
> + get_ip_config_context_complete_and_free (ctx);
You probably need to g_simple_async_result_set_error() before
complete_and_free().
> + return;
> + }
> +
> + for (iter = lines; iter && *iter; iter++) {
> +
> + /* skip emtpy line */
> + if (!g_str_has_prefix (*iter, GCTNETCFG_TAG)) {
> + continue;
> + }
> +
> + sscanf (*iter + strlen(GCTNETCFG_TAG), "%d,%x,%d", &cid, &nic_type, &internal_type);
> +
> + mm_dbg("GCT net config: cid(%d), nic_type(0x%x), internal_type(%d)",
> + cid, nic_type, internal_type);
> +
> + ctx->gct_net_conf[gct_net_conf_cnt].cid = cid;
> + ctx->gct_net_conf[gct_net_conf_cnt].nic_type = nic_type;
> + ctx->gct_net_conf[gct_net_conf_cnt++].internal_type = internal_type;
> + }
> +
> + g_strfreev (lines);
> +
> + ctx->gct_net_conf_cnt = gct_net_conf_cnt;
> +
> + ctx->step++;
> + run_get_ip_config_context_step(ctx);
> +}
> +
> +static void
> +run_get_ip_config_context_step (GetIpConfig3gppContext *ctx)
> +{
> + gchar *command;
> +
> + switch (ctx->step) {
> + case GET_IP_STEP_FIRST:
> + mm_base_modem_at_command_full (
> + MM_BASE_MODEM (ctx->modem),
> + ctx->primary,
> + "%GCTNETCFG",
> + 3,
> + FALSE,
> + FALSE, /* raw */
> + NULL, /* cancellable */
> + (GAsyncReadyCallback)gct_net_config_ready,
> + ctx);
> + break;
> +
> + case GET_IP_STEP_SECOND:
Just declare 'command' here within the case, which is where it's used only.
> + command = g_strdup_printf ("+CGCONTRDP=%d", ctx->cid);
> + mm_base_modem_at_command_full (
> + MM_BASE_MODEM (ctx->modem),
> + ctx->primary,
> + command,
> + 3,
> + FALSE,
> + FALSE, /* raw */
> + NULL, /* cancellable */
> + (GAsyncReadyCallback)ip_config_ready,
> + ctx);
> + g_free (command);
> + break;
> +
> + case GET_IP_STEP_LAST:
> + get_ip_config_context_complete_and_free (ctx);
> + break;
> + }
> +}
> +
> +static void
> +get_ip_config_3gpp (MMBroadbandBearer *self,
> + MMBroadbandModem *modem,
> + MMAtSerialPort *primary,
> + MMAtSerialPort *secondary,
> + MMPort *data,
> + guint cid,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GetIpConfig3gppContext *ctx;
> +
> + ctx = g_slice_new0 (GetIpConfig3gppContext);
> + ctx->self = g_object_ref (self);
> + ctx->modem = g_object_ref (modem);
> + ctx->primary = g_object_ref (primary);
> + ctx->cid = cid;
> + ctx->result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + get_ip_config_3gpp);
> +
> + ctx->step = GET_IP_STEP_FIRST;
> +
> + run_get_ip_config_context_step (ctx);
> +}
> +
> +/*****************************************************************************/
> +/* 3GPP Dialing (sub-step of the 3GPP Connection sequence) */
> +
> +typedef enum {
> + DIAL_3GPP_STEP_FIRST,
> + DIAL_3GPP_STEP_PLMN_SELECTION,
> + DIAL_3GPP_STEP_PS_ATTACH,
> + DIAL_3GPP_STEP_GET_DATA_PORT,
> + DIAL_3GPP_STEP_LAST
> +} Dial3gppStep;
> +
> +typedef struct {
> + MMBroadbandBearerGct *self;
> + MMBaseModem *modem;
> + MMAtSerialPort *primary;
> + guint cid;
> + GCancellable *cancellable;
> + GSimpleAsyncResult *result;
> + MMPort *data;
> + Dial3gppStep step;
> +} Dial3gppContext;
> +
> +static void
> +dial_3gpp_context_complete_and_free (Dial3gppContext *ctx)
> +{
> + g_simple_async_result_complete_in_idle (ctx->result);
> + g_object_unref (ctx->cancellable);
> + g_object_unref (ctx->result);
> + g_object_unref (ctx->data);
> + g_object_unref (ctx->primary);
> + g_object_unref (ctx->modem);
> + g_object_unref (ctx->self);
> + g_slice_free (Dial3gppContext, ctx);
> +}
> +
> +static MMPort *
> +dial_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_PORT (g_object_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))));
> +}
> +
> +static void dial_3gpp_context_step (Dial3gppContext *ctx);
> +
> +static void
> +cops_ready (MMBaseModem *modem,
> + GAsyncResult *res,
> + Dial3gppContext *ctx)
> +{
> + const gchar *response;
> + GError *error = NULL;
> +
> + response = mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error);
> +
> + if(error) {
> + g_simple_async_result_take_error (ctx->result, error);
> + dial_3gpp_context_complete_and_free (ctx);
> + return;
> + }
> +
> + /* Go on */
> + ctx->step++;
> + dial_3gpp_context_step (ctx);
> +}
> +
> +static void
> +cgact_ready (MMBaseModem *modem,
> + GAsyncResult *res,
> + Dial3gppContext *ctx)
> +{
> + const gchar *response;
> + GError *error = NULL;
> +
> + response = mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error);
> +
> + if(error) {
> + g_simple_async_result_take_error (ctx->result, error);
> + dial_3gpp_context_complete_and_free (ctx);
> + return;
> + }
> +
> + /* Go on */
> + ctx->step++;
> + dial_3gpp_context_step (ctx);
> +}
> +
> +static void
> +data_port_ready (MMBaseModem *modem,
> + GAsyncResult *res,
> + Dial3gppContext *ctx)
Parameters need alignment.
> +{
> + const gchar *response;
> + GError *error = NULL;
> + gchar **lines;
> + gchar **iter;
> + GList *dataports;
> + GList *l;
> + gint cid, nic_type, internal_type;
> +
> + response = mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error);
> +
> + if (error) {
> + g_simple_async_result_take_error (ctx->result, error);
> + dial_3gpp_context_complete_and_free (ctx);
> + return;
> + }
Please include here a comment with the kind of response which is expected.
> +
> + lines = g_strsplit_set (response, "\r\n", 0);
> + if (!lines) {
> + dial_3gpp_context_complete_and_free (ctx);
> + return;
> + }
> +
> + for (iter = lines; iter && *iter; iter++) {
> + if (!g_str_has_prefix (*iter, GCTNETCFG_TAG)) {
> + continue;
> + }
> +
> + if (sscanf (*iter + strlen(GCTNETCFG_TAG), "%d, %x, %d", &cid, &nic_type, &internal_type) != 3) {
Whitespace after strlen and before '('-
> + continue;
> + }
> +
> + mm_dbg("GCT net config: cid(%d), nic_type(0x%x), internal_type(%d)",
> + cid, nic_type, internal_type);
Whitespace after mm_dbg and before '('.
> +
> + if (cid == ctx->cid)
> + {
The '{' should go in the same line as the if().
Also, you can declare 'dataports' and 'l' here inside this if(), as
they're only used here.
> + /* Mask out the nic_type to match the pdn number */
> + nic_type &= 0x0F;
> + g_assert (nic_type >= 0 && nic_type < MAX_CID_SUPPORTED);
nic_type is a value received and parsed from the modem; you shouldn't
g_assert() based on its value. If the value is not the expected one, you
should return a controlled error instead of asserting.
> +
> + /* From the list of data ports, find one that matches the nic_type value */
> + dataports = mm_base_modem_get_data_ports (modem);
> + for (l = dataports; l; l = g_list_next (l) ) {
> + MMPort *port = (MMPort *) l->data;
> + const gchar *port_name = mm_port_get_device (port);
Don't mix variable declarations with method calls. Declare 'port_name'
here and below, after the whiteline, call 'port_name =
mm_port_get_device (port)'.
> + int device_id, pdn_number;
Not a big deal, but better use 'gint' for consistency.
> +
> + if (sscanf (port_name, "lte%dpdn%d", &device_id, &pdn_number) == 2) {
> + if (ctx->cid == cid && pdn_number == nic_type) {
> + /* Found the port with this pdn number and cid */
> + ctx->data = port;
> + mm_dbg("GCT net interface %s chosen for cid (%d)",
Whitespace between mm_dbg and '('.
> + port_name,
> + ctx->cid);
> + break;
> + }
> + }
> + }
> +
> + break;
> + }
> + }
> +
> + g_strfreev (lines);
> +
> + if (!ctx->data) {
> + g_simple_async_result_set_error (
> + ctx->result,
> + MM_CORE_ERROR,
> + MM_CORE_ERROR_NOT_FOUND,
> + "No valid data port found to launch connection");
> + dial_3gpp_context_complete_and_free (ctx);
> + return;
> + }
> +
> + /* Go on */
> + ctx->step++;
> + dial_3gpp_context_step (ctx);
> +}
> +
> +static void
> +dial_3gpp_context_step (Dial3gppContext *ctx)
> +{
> + gchar *command;
> + command = NULL;
'command' is not used in all the steps; just declare it in the specific
cases of the switch when you need it. Actually; you're already
re-declaring it in some of the steps.
> + if (g_cancellable_is_cancelled (ctx->cancellable)) {
> + g_simple_async_result_set_error (ctx->result,
> + MM_CORE_ERROR,
> + MM_CORE_ERROR_CANCELLED,
> + "Dial operation has been cancelled");
> + dial_3gpp_context_complete_and_free (ctx);
> + return;
> + }
> +
> + switch (ctx->step) {
> + case DIAL_3GPP_STEP_FIRST:
> + /* Fall down */
> + ctx->step++;
> + case DIAL_3GPP_STEP_PLMN_SELECTION: {
> + MMBroadbandModemGct *modem = NULL;
> + gchar* command;
> +
> + g_object_get (ctx->self,
> + MM_BEARER_MODEM, &modem,
> + NULL);
> +
> + g_assert (modem != NULL);
You shouldn't get again the modem object, you already have it in
ctx->modem. And remember that whenever you g_object_get() the modem
object you're really getting a full new reference that needs to be
unref-ed. In this case, you can just avoid re-getting it.
> +
> + command = g_strdup_printf ("+COPS=0");
> +
Nope, no; automatic home network selection is handled already by the
3GPP interface, you shouldn't need it as part of the 3GPP connection
sequence; don't add it here. Just remove this step.
> + mm_base_modem_at_command_full (MM_BASE_MODEM (ctx->modem),
> + ctx->primary,
> + command,
> + 120,
> + FALSE,
> + FALSE, /* raw */
> + NULL, /* cancellable */
> + (GAsyncReadyCallback)cops_ready,
> + ctx);
> + return;
> + }
> + case DIAL_3GPP_STEP_PS_ATTACH: {
> +
No whiteline here.
> + MMBroadbandModemGct *modem = NULL;
> + gchar* command;
> +
> + g_object_get (ctx->self,
> + MM_BEARER_MODEM, &modem,
> + NULL);
> +
> + g_assert (modem != NULL);
> +
You shouldn't get again the modem object, you already have it in
ctx->modem. And remember that whenever you g_object_get() the modem
object you're really getting a full new reference that needs to be
unref-ed. In this case, you can just avoid re-getting it.
> + command = g_strdup_printf ("+CGACT=1,%d",ctx->cid);
> +
> + mm_base_modem_at_command_full (MM_BASE_MODEM (ctx->modem),
> + ctx->primary,
> + command,
> + 10,
> + FALSE,
> + FALSE, /* raw */
> + NULL, /* cancellable */
> + (GAsyncReadyCallback)cgact_ready,
> + ctx);
You need to g_free (command); here.
> + return;
> + }
> + case DIAL_3GPP_STEP_GET_DATA_PORT: {
> +
> + MMBroadbandModemGct *modem = NULL;
> +
> + g_object_get (ctx->self,
> + MM_BEARER_MODEM, &modem,
> + NULL);
> +
> + g_assert (modem != NULL);
You shouldn't get again the modem object, you already have it in
ctx->modem. And remember that whenever you g_object_get() the modem
object you're really getting a full new reference that needs to be
unref-ed. In this case, you can just avoid re-getting it.
> +
> + mm_base_modem_at_command_full (MM_BASE_MODEM (ctx->modem),
> + ctx->primary,
> + "%GCTNETCFG",
> + 10,
> + FALSE,
> + FALSE, /* raw */
> + NULL, /* cancellable */
> + (GAsyncReadyCallback)data_port_ready,
> + ctx);
> + return;
> + }
> + case DIAL_3GPP_STEP_LAST:
> + g_simple_async_result_set_op_res_gpointer (ctx->result,
> + g_object_ref (ctx->data),
> + (GDestroyNotify)g_object_unref);
> + dial_3gpp_context_complete_and_free (ctx);
> + return;
> + }
> +}
> +
> +static void
> +dial_3gpp (MMBroadbandBearer *self,
> + MMBaseModem *modem,
> + MMAtSerialPort *primary,
> + guint cid,
> + GCancellable *cancellable,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + Dial3gppContext *ctx;
> +
> + g_assert (primary != NULL);
> +
> + ctx = g_slice_new0 (Dial3gppContext);
> + ctx->self = g_object_ref (self);
> + ctx->modem = g_object_ref (modem);
> + ctx->primary = g_object_ref (primary);
> + ctx->cid = cid;
> + ctx->result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + dial_3gpp);
> + ctx->cancellable = g_object_ref (cancellable);
> +
> + /* We need a net data port */
> +
> + if (ctx->cid > MAX_CID_SUPPORTED) {
> + g_simple_async_result_set_error (
> + ctx->result,
> + MM_CORE_ERROR,
> + MM_CORE_ERROR_NOT_FOUND,
> + "Invalid CID %d, Gct modem supports up to only %d", ctx->cid, MAX_CID_SUPPORTED);
> + dial_3gpp_context_complete_and_free (ctx);
> + return;
> + }
> +
> + ctx->step = DIAL_3GPP_STEP_FIRST;
> +
> + dial_3gpp_context_step (ctx);
> +}
> +
> +/*****************************************************************************/
> +/* 3GPP disconnect */
> +
> +typedef enum {
> + DISCONNECT_3GPP_STEP_FIRST,
> + DISCONNECT_3GPP_STEP_PS_DETACH,
> + DISCONNECT_3GPP_STEP_PLMN_SELECTION,
> + DISCONNECT_3GPP_STEP_LAST
> +} Disconnect3gppStep;
> +
> +typedef struct {
> + MMBroadbandBearerGct *self;
> + MMBaseModem *modem;
> + MMAtSerialPort *primary;
> + GSimpleAsyncResult *result;
> + Disconnect3gppStep step;
> +} DisconnectContext;
> +
> +static void
> +disconnect_context_complete_and_free (DisconnectContext *ctx)
> +{
> + g_simple_async_result_complete (ctx->result);
> + g_object_unref (ctx->result);
> + g_object_unref (ctx->primary);
> + g_object_unref (ctx->self);
> + g_object_unref (ctx->modem);
> + g_free (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);
> +}
> +
Single whiteline here.
> +
> +static void disconnect_3gpp_context_step (DisconnectContext *ctx);
> +
> +static void
> +re_cops_ready (MMBaseModem *modem,
> + GAsyncResult *res,
> + DisconnectContext *ctx)
Alignment needed in the parameters.
> +{
> + const gchar *response;
> + GError *error = NULL;
> +
> + response = mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error);
> +
> + if(error) {
Need a whitespace after the 'if' and before the '('.
> + g_simple_async_result_take_error (ctx->result, error);
> + disconnect_context_complete_and_free (ctx);
> + return;
> + }
> +
> + /* Go on */
> + ctx->step++;
> + disconnect_3gpp_context_step (ctx);
> +}
> +
> +
> +static void
> +detach_ready (MMBaseModem *modem,
> + GAsyncResult *res,
> + DisconnectContext *ctx)
Alignment needed in the parameters.
> +{
> + const gchar *response;
> + GError *error = NULL;
> +
> + response = mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error);
> +
> + if(error) {
Need a whitespace after the 'if' and before the '('.
> + g_simple_async_result_take_error (ctx->result, error);
> + disconnect_context_complete_and_free (ctx);
> + return;
> + }
> +
> + sleep(1);
Errr no. No sleep() calls. If you need to wait some time before assuming
the modem is disconnected; setup a 1s timeout with g_timeout_add_seconds().
> +
> + /* Go on */
> + ctx->step++;
> + disconnect_3gpp_context_step (ctx);
> +}
> +
> +static void
> +disconnect_3gpp_context_step (DisconnectContext *ctx)
> +{
> + gchar *command;
> + command = NULL;
> +
> + switch (ctx->step) {
> + case DISCONNECT_3GPP_STEP_FIRST:
> + /* Fall down */
> + ctx->step++;
> + case DISCONNECT_3GPP_STEP_PS_DETACH: {
> + MMBroadbandModemGct *modem = NULL;
> + gchar* command;
> +
> + g_object_get (ctx->self,
> + MM_BEARER_MODEM, &modem,
> + NULL);
> +
> + g_assert (modem != NULL);
> +
> + command = g_strdup_printf ("+CGATT=0");
> +
> + mm_base_modem_at_command_full (MM_BASE_MODEM (ctx->modem),
> + ctx->primary,
> + command,
> + 10,
> + FALSE,
> + FALSE, /* raw */
> + NULL, /* cancellable */
> + (GAsyncReadyCallback)detach_ready,
> + ctx);
> + return;
> + }
> + case DISCONNECT_3GPP_STEP_PLMN_SELECTION: {
> +
> + MMBroadbandModemGct *modem = NULL;
> + gchar* command;
> +
> + g_object_get (ctx->self,
> + MM_BEARER_MODEM, &modem,
> + NULL);
> +
> + g_assert (modem != NULL);
You shouldn't get again the modem object, you already have it in
ctx->modem. And remember that whenever you g_object_get() the modem
object you're really getting a full new reference that needs to be
unref-ed. In this case, you can just avoid re-getting it.
> +
> + command = g_strdup_printf ("+COPS=0");
> +
> + mm_base_modem_at_command_full (MM_BASE_MODEM (ctx->modem),
> + ctx->primary,
> + command,
> + 120,
> + FALSE,
> + FALSE, /* raw */
> + NULL, /* cancellable */
> + (GAsyncReadyCallback)re_cops_ready,
> + ctx);
> + return;
What's the point of re-running home registration here? Isn't the modem
still registered in the network after disconnection?
> + }
> +
> + case DISCONNECT_3GPP_STEP_LAST:
> + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> + 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)
> +{
> + DisconnectContext *ctx;
> + MMBroadbandModemGct *gct_modem = NULL;
> +
> + g_object_get (self,
> + MM_BEARER_MODEM, &gct_modem,
> + NULL);
This gct_modem is unused, and worse, it actually leaks a reference. You
should probably remove it.
> +
> + g_assert (modem != NULL);
> +
> + g_assert (primary != NULL);
> +
> + ctx = g_new0 (DisconnectContext, 1);
> + ctx->self = g_object_ref (self);
> + ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
> + ctx->primary = g_object_ref (primary);
> + ctx->result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + disconnect_3gpp);
> + ctx->step = DISCONNECT_3GPP_STEP_FIRST;
> +
> + disconnect_3gpp_context_step (ctx);
> +}
> +
> +/*****************************************************************************/
> +
> +MMBearer *
> +mm_broadband_bearer_gct_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_gct_new (MMBroadbandModemGct *modem,
> + MMBearerProperties *config,
> + GCancellable *cancellable,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + const gchar *apn;
> + MMBearerIpFamily ip_type;
> +
> + g_async_initable_new_async (
> + MM_TYPE_BROADBAND_BEARER_GCT,
> + G_PRIORITY_DEFAULT,
> + cancellable,
> + callback,
> + user_data,
> + MM_BEARER_MODEM, modem,
> + MM_BEARER_CONFIG, config,
> + NULL);
> +
> + apn = mm_bearer_properties_get_apn (config);
> + ip_type = mm_bearer_properties_get_ip_type (config);
> +
> + mm_dbg ("Bearer creation : apn=%s, ip_type=%s", apn, mm_3gpp_get_pdp_type_from_ip_family (ip_type));
I believe we already log this info during Simple.Connect(), I would just
remove the log.
> +
> + /* Configure the default ip type */
> + if (ip_type != MM_BEARER_IP_FAMILY_IPV4V6 && strncasecmp(apn, "vzw", 3) == 0) {
> + mm_bearer_properties_set_ip_type (config, MM_BEARER_IP_FAMILY_IPV4V6);
> + mm_dbg ("Bearer IP type changed to %s for VZW",
> + mm_3gpp_get_pdp_type_from_ip_family ( mm_bearer_properties_get_ip_type (config)));
> + }
Nope, no. You shouldn't overwrite the user's desired IP type based on
the operator to use. This is a problem of the interface user, not a
problem to handle in ModemManager.
> +}
> +
> +static void
> +mm_broadband_bearer_gct_init (MMBroadbandBearerGct *self)
> +{
> + /* Initialize private data */
> + self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
> + MM_TYPE_BROADBAND_BEARER_GCT,
> + MMBroadbandBearerGctPrivate);
> +}
> +
> +static void
> +mm_broadband_bearer_gct_class_init (MMBroadbandBearerGctClass *klass)
> +{
> + GObjectClass *object_class = G_OBJECT_CLASS (klass);
> + MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass);
> +
> + g_type_class_add_private (object_class, sizeof (MMBroadbandBearerGctPrivate));
> +
> + broadband_bearer_class->dial_3gpp = dial_3gpp;
> + broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish;
> + broadband_bearer_class->get_ip_config_3gpp = get_ip_config_3gpp;
> + broadband_bearer_class->get_ip_config_3gpp_finish = get_ip_config_3gpp_finish;
> + broadband_bearer_class->disconnect_3gpp = disconnect_3gpp;
> + broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish;
> +}
> diff --git a/plugins/gct/mm-broadband-bearer-gct.h b/plugins/gct/mm-broadband-bearer-gct.h
> new file mode 100644
> index 0000000..09dec80
> --- /dev/null
> +++ b/plugins/gct/mm-broadband-bearer-gct.h
> @@ -0,0 +1,70 @@
> +/* -*- 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 GCT Semiconductor, Inc.
> + * Author: Glen Lee <glenlee at gctsemi.com>
> + */
> +
> +#ifndef MM_BROADBAND_BEARER_GCT_H
> +#define MM_BROADBAND_BEARER_GCT_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-gct.h"
> +
> +#define MM_TYPE_BROADBAND_BEARER_GCT (mm_broadband_bearer_gct_get_type ())
> +#define MM_BROADBAND_BEARER_GCT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_BEARER_GCT, MMBroadbandBearerGct))
> +#define MM_BROADBAND_BEARER_GCT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_BEARER_GCT, MMBroadbandBearerGctClass))
> +#define MM_IS_BROADBAND_BEARER_GCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_BEARER_GCT))
> +#define MM_IS_BROADBAND_BEARER_GCT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_BEARER_GCT))
> +#define MM_BROADBAND_BEARER_GCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_BEARER_GCT, MMBroadbandBearerGctClass))
> +
> +typedef enum {
> + MM_BROADBAND_BEARER_GCT_CONNECTION_STATUS_UNKNOWN,
> + MM_BROADBAND_BEARER_GCT_CONNECTION_STATUS_CONNECTED,
> + MM_BROADBAND_BEARER_GCT_CONNECTION_STATUS_CONNECTION_FAILED,
> + MM_BROADBAND_BEARER_GCT_CONNECTION_STATUS_DISCONNECTED
> +} MMBroadbandBearerGctConnectionStatus;
Unused enum type; remove it.
> +
> +typedef struct _MMBroadbandBearerGct MMBroadbandBearerGct;
> +typedef struct _MMBroadbandBearerGctClass MMBroadbandBearerGctClass;
> +typedef struct _MMBroadbandBearerGctPrivate MMBroadbandBearerGctPrivate;
> +
> +struct _MMBroadbandBearerGct {
> + MMBroadbandBearer parent;
> + MMBroadbandBearerGctPrivate *priv;
> +};
> +
> +struct _MMBroadbandBearerGctClass {
> + MMBroadbandBearerClass parent;
> +};
> +
> +GType mm_broadband_bearer_gct_get_type (void);
> +
> +/* Default 3GPP bearer creation implementation */
> +void mm_broadband_bearer_gct_new (MMBroadbandModemGct *modem,
> + MMBearerProperties *config,
> + GCancellable *cancellable,
> + GAsyncReadyCallback callback,
> + gpointer user_data);
> +MMBearer *mm_broadband_bearer_gct_new_finish (GAsyncResult *res,
> + GError **error);
> +
> +void mm_broadband_bearer_gct_report_connection_status (MMBroadbandBearerGct *self,
> + MMBroadbandBearerGctConnectionStatus status);
Remove this method from the header, it's nowhere used.
> +
> +#endif /* MM_BROADBAND_BEARER_GCT_H */
> diff --git a/plugins/gct/mm-broadband-modem-gct.c b/plugins/gct/mm-broadband-modem-gct.c
> new file mode 100644
> index 0000000..537824b
> --- /dev/null
> +++ b/plugins/gct/mm-broadband-modem-gct.c
> @@ -0,0 +1,1333 @@
> +/* -*- 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 GCT Semiconductor, Inc.
> + * Author: Glen Lee <glenlee at gctsemi.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-modem-gct.h"
> +#include "mm-iface-modem-3gpp.h"
> +#include "mm-iface-modem-3gpp-ussd.h"
> +#include "mm-iface-modem-location.h"
> +#include "mm-iface-modem-time.h"
> +#include "mm-iface-modem-messaging.h"
> +#include "mm-broadband-bearer-gct.h"
> +#include "mm-modem-helpers.h"
> +#include "mm-log.h"
> +#include "mm-iface-modem.h"
> +#include "mm-sim-gct.h"
> +#include "mm-bearer-list.h"
> +#include "mm-sms-part.h"
> +#include "mm-sms-list.h"
> +
> +
> +static MMIfaceModem *iface_modem_parent;
> +
> +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_location_init(MMIfaceModemLocation *iface);
> +static void iface_modem_time_init(MMIfaceModemTime *iface);
> +static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
> +
> +
One line is probably enough here, not three.
> +
> +G_DEFINE_TYPE_EXTENDED (MMBroadbandModemGct, mm_broadband_modem_gct, 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_LOCATION, iface_modem_location_init)
> + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)
> + G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)
> + );
Just place the last parenthesis with the last G_IMPLEMENT_INTERFACE
line, not in its own line. And remove the last semicolon as it really
isn't needed.
> +
> +/*****************************************************************************/
> +/* Setup ports (Broadband modem class) */
> +
> +static void
> +setup_ports (MMBroadbandModem *self)
> +{
> + /* Call parent's setup ports first always */
> + MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_gct_parent_class)->setup_ports (self);
> +}
You don't need to subclass setup_ports() just to call the parent
implementation. Just leave the parent setup_ports() in place and remove
this method.
> +
> +/*****************************************************************************/
> +/* Create SIM (Modem interface) */
> +
> +static MMSim *
> +modem_create_sim_finish (MMIfaceModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return mm_sim_gct_new_finish (res, error);
> +}
> +
> +static void
> +modem_create_sim (MMIfaceModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + /* New GCT SIM */
> + mm_sim_gct_new (MM_BASE_MODEM (self),
> + NULL, /* cancellable */
> + callback,
> + user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Bearer Information */
> +
> +typedef struct {
> + gboolean connected;
> +} BearerListReportStatusForeachContext;
> +
> +static void
> +bearer_list_info_foreach (MMBearer *bearer,
> + BearerListReportStatusForeachContext *ctx)
> +{
> + guint status;
> + guint cid;
> +
> + if (!MM_IS_BROADBAND_BEARER_GCT (bearer))
> + return;
> +
> + status = mm_bearer_get_status(MM_BEARER(bearer));
> + cid = mm_broadband_bearer_get_3gpp_cid(MM_BROADBAND_BEARER(bearer));
> +
> + mm_dbg("bearer with cid(%d) status(%d)", cid, status);
> +
> + if (status != MM_BEARER_STATUS_DISCONNECTED)
> + ctx->connected ++;
> +}
> +
> +void
> +modem_bearer_get_info(MMBroadbandModemGct *self,
> + guint8 *connected)
> +{
Methods which are exported by the plugin should be prefixed with "mm_".
But actually, when do you need to use this command out of the plugin
implementation? I don't see any use of it, not even internally; so
please just remove it (and bearer_list_info_foreach()) as it's nowhere used.
> + MMBearerList *list = NULL;
> + BearerListReportStatusForeachContext ctx;
> +
> + ctx.connected = 0;
> +
> + g_object_get (self,
> + MM_IFACE_MODEM_BEARER_LIST, &list,
> + NULL);
> +
> + mm_bearer_list_foreach (list,
> + (MMBearerListForeachFunc)bearer_list_info_foreach,
> + &ctx);
> +
> + mm_dbg("number of bearers active = %d", ctx.connected);
> +
> + *connected = ctx.connected;
> +
> + g_object_unref (list);
> +}
> +
> +/*****************************************************************************/
> +/* Create Bearer (Modem interface) */
> +
> +static MMBearer *
> +modem_create_bearer_finish (MMIfaceModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + MMBearer *bearer;
> +
> + bearer = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
> + mm_dbg ("New GCT bearer created at DBus path '%s'", mm_bearer_get_path (bearer));
> +
> + return g_object_ref (bearer);
> +}
> +
> +static void
> +broadband_bearer_gct_new_ready (GObject *source,
> + GAsyncResult *res,
> + GSimpleAsyncResult *simple)
> +{
> + MMBearer *bearer = NULL;
> + GError *error = NULL;
> +
> + bearer = mm_broadband_bearer_gct_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;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + modem_create_bearer);
> +
> + mm_broadband_bearer_gct_new (MM_BROADBAND_MODEM_GCT (self),
> + properties,
> + NULL, /* cancellable */
> + (GAsyncReadyCallback)broadband_bearer_gct_new_ready,
> + result);
> +}
> +
> +/*****************************************************************************/
> +/* Setup_format */
> +
> +static gboolean
> +messaging_setup_sms_format_finish (MMIfaceModemMessaging *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
> +}
> +
> +static void
> +cmgf_format_check_ready (MMBroadbandModem *self,
> + GAsyncResult *res,
> + GSimpleAsyncResult *simple)
> +{
> + GError *error = NULL;
> + const gchar *response;
> +
> + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
> + if (error) {
> + mm_dbg ("Failed to query supported SMS modes: '%s'",
> + error->message);
> + g_error_free (error);
> + }
> +
> + mm_dbg ("Use Text mode");
> +
> + g_simple_async_result_set_op_res_gboolean (simple, TRUE);
> + g_simple_async_result_complete (simple);
> + g_object_unref (simple);
> +}
> +
> +static void
> +messaging_setup_sms_format (MMIfaceModemMessaging *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + messaging_setup_sms_format);
> +
> + /* Setup Format SMS formats */
> + mm_base_modem_at_command (MM_BASE_MODEM (self),
> + "+CMGF=1",
> + 3,
> + TRUE,
> + (GAsyncReadyCallback)cmgf_format_check_ready,
> + result);
If you want to restrict SMS to the Text format, you better just set the
"MM_IFACE_MODEM_MESSAGING_SMS_PDU_MODE" property in the modem object to
FALSE whithin the mm_broadband_modem_gct_new() call, and remove the
messaging_setup_sms_format() method all together.
But anyway, do you really want to use text mode? Doesn't the modem
support PDU mode?
> +}
> +
> +/*****************************************************************************/
> +/* Setup/cleanup messaging related unsolicited events (Messaging interface) */
> +
> +static gboolean
> +modem_messaging_setup_cleanup_unsolicited_events_finish (MMIfaceModemMessaging *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
> +}
> +
> +typedef struct {
> + MMBroadbandModem *self;
> + GSimpleAsyncResult *result;
> + guint idx;
> +} SmsPartContext;
> +
> +static void
> +sms_part_context_complete_and_free (SmsPartContext *ctx)
> +{
> + g_simple_async_result_complete (ctx->result);
> + g_object_unref (ctx->result);
> + g_object_unref (ctx->self);
> + g_free (ctx);
> +}
> +
> +static void
> +sms_part_ready (MMBroadbandModem *self,
> + GAsyncResult *res,
> + SmsPartContext *ctx)
> +{
> + MMSmsPart *part;
> + gint rv, status, tpdu_len;
> + gchar pdu[SMS_MAX_PDU_LEN + 1];
> + const gchar *response;
> + GError *error = NULL;
> +
> + /* Always always always unlock mem1 storage. Warned you've been. */
> + mm_broadband_modem_unlock_sms_storages (self, TRUE, FALSE);
> +
> + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
> + if (error) {
> + /* We're really ignoring this error afterwards, as we don't have a callback
> + * passed to the async operation, so just log the error here. */
> + mm_warn ("Couldn't retrieve SMS part: '%s'",
> + error->message);
> + g_simple_async_result_take_error (ctx->result, error);
> + sms_part_context_complete_and_free (ctx);
> + return;
> + }
> +
> + rv = sscanf (response, "+CMGR: %d,,%d %" G_STRINGIFY (SMS_MAX_PDU_LEN) "s",
> + &status, &tpdu_len, pdu);
> + if (rv != 3) {
> + error = g_error_new (MM_CORE_ERROR,
> + MM_CORE_ERROR_FAILED,
> + "Failed to parse CMGR response (parsed %d items)", rv);
> + mm_warn ("Couldn't retrieve SMS part: '%s'", error->message);
> + g_simple_async_result_take_error (ctx->result, error);
> + sms_part_context_complete_and_free (ctx);
> + return;
> + }
> +
> + part = mm_sms_part_new_from_pdu (ctx->idx, pdu, &error);
> + if (part) {
> + mm_dbg ("Correctly parsed PDU (%d)", ctx->idx);
> + mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
> + part,
> + MM_SMS_STATE_RECEIVED,
> + MM_SMS_STORAGE_ME);
> + } else {
> + /* Don't treat the error as critical */
> + mm_dbg ("Error parsing PDU (%d): %s", ctx->idx, error->message);
> + g_error_free (error);
> + }
> +
> + /* All done */
> + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> + sms_part_context_complete_and_free (ctx);
> +}
> +
> +static void
> +indication_lock_storages_ready (MMBroadbandModem *self,
> + GAsyncResult *res,
> + SmsPartContext *ctx)
> +{
> + gchar *command;
> + /* Storage now set and locked */
> +
> + /* Retrieve the message */
> + command = g_strdup_printf ("+CMGR=%d", ctx->idx);
> + mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
> + command,
> + 10,
> + FALSE,
> + (GAsyncReadyCallback)sms_part_ready,
> + ctx);
> + g_free (command);
> +}
> +
> +static void
> +cmt_received (MMAtSerialPort *port,
> + GMatchInfo *info,
> + MMBroadbandModem *self)
> +{
> + SmsPartContext *ctx;
> + MMSmsStorage storage;
> +
> + storage = MM_SMS_STORAGE_ME;
> +
> + ctx = g_new0 (SmsPartContext, 1);
> + ctx->self = g_object_ref (self);
> + ctx->result = g_simple_async_result_new (G_OBJECT (self), NULL, NULL, cmt_received);
> + ctx->idx = 1;
> +
I don't get this. +CMT is supposed to return the whole received PDU in
the +CMT line itself, as opposed to +CMTI indications where we get the
index of the message to be read from the storage:
+CMT: <length><CR><LF><pdu>
+CMTI: <mem3>, <index>
But here you're just assuming that the index is always 1 for the last
received SMS message, which doesn't seem to be ok.
So, what's the thing here? Doesn't the modem support +CMTI SMS
indications (using <mt>=1 in the +CNMI call in
messaging_enable_unsolicited_events(), instead of <mt>=3, if I'm not
mistaken)? If it doesn't then you probably need to properly parse the
+CMT response, not assume it goes to index 1.
> + /* First, request to set the proper storage to read from */
> + mm_broadband_modem_lock_sms_storages (ctx->self,
> + storage,
> + MM_SMS_STORAGE_UNKNOWN,
> + (GAsyncReadyCallback)indication_lock_storages_ready,
> + ctx);
> +}
> +
> +static GRegex *
> +mm_3gpp_cmt_regex_get (void)
For static methods, remove the "mm_" prefix.
> +{
> + return g_regex_new ("\\r\\n\\+CMT.*",
> + G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW | G_REGEX_OPTIMIZE,
> + 0,
> + NULL);
Align the previous parameters in the method call.
> +}
> +
> +static void
> +set_messaging_unsolicited_events_handlers (MMIfaceModemMessaging *self,
> + gboolean enable,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> + MMAtSerialPort *ports[1];
Don't create an array of 1 element; just a "MMAtSerialPort *port;" is
enough here.
> + GRegex *cmt_regex;
> +
> + mm_dbg("set_messaging_unsolicited_events_handlers enable(%d)", enable);
Remove the previous log; doesn't seem to be needed.
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + set_messaging_unsolicited_events_handlers);
> +
> + cmt_regex = mm_3gpp_cmt_regex_get ();
> + ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
> +
> + /* Set/unset unsolicited CMT event handler */
> + mm_dbg ("(%s) %s messaging unsolicited events handlers",
> + mm_port_get_device (MM_PORT (ports[0])),
> + enable ? "Setting" : "Removing");
> + mm_at_serial_port_add_unsolicited_msg_handler (
> + ports[0],
> + cmt_regex,
> + enable ? (MMAtSerialUnsolicitedMsgFn) cmt_received : NULL,
> + enable ? self : NULL,
> + NULL);
> +
> + g_regex_unref (cmt_regex);
> + g_simple_async_result_set_op_res_gboolean (result, TRUE);
> + g_simple_async_result_complete_in_idle (result);
> + g_object_unref (result);
> +}
> +
> +static void
> +modem_messaging_setup_unsolicited_events (MMIfaceModemMessaging *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + set_messaging_unsolicited_events_handlers (self, TRUE, callback, user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Enable unsolicited events (SMS indications) (Messaging interface) */
> +
> +static gboolean
> +messaging_enable_unsolicited_events_finish (MMIfaceModemMessaging *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
> +}
> +
> +static void
> +messaging_enable_unsolicited_events (MMIfaceModemMessaging *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + /* AT+CNMI=<mode>,[<mt>[,<bm>[,<ds>[,<bfr>]]]]
> + * but <bfr> should be either not set, or equal to 1;
> + * and <ds> can be only either 0 or 2 (EGS5)
> + */
> + mm_base_modem_at_command (MM_BASE_MODEM (self),
> + "+CNMI=1,3,3,2,1",
> + 3,
> + FALSE,
> + callback,
> + user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Reset (Modem interface) */
> +
> +static gboolean
> +modem_reset_finish (MMIfaceModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
> +}
> +
> +static void
> +modem_reset (MMIfaceModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + mm_base_modem_at_command (MM_BASE_MODEM (self),
> + "+SYSRESET",
> + 3,
> + FALSE,
> + callback,
> + user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Modem power down (Modem interface) */
> +
> +static gboolean
> +modem_power_down_finish (MMIfaceModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
> +}
> +
> +static void
> +modem_power_down_ready (MMBaseModem *self,
> + GAsyncResult *res,
> + GSimpleAsyncResult *simple)
> +{
> + mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);
> +
> + g_simple_async_result_set_op_res_gboolean (simple, TRUE);
> + g_simple_async_result_complete (simple);
> + g_object_unref (simple);
> +}
> +
> +static void
> +modem_power_down (MMIfaceModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + modem_power_down);
> +
> + /* run AT+CFUN=4 (power save) */
> + mm_base_modem_at_command (MM_BASE_MODEM (self),
> + "+CFUN=1",
This looks like a typo to me. Shouldn't it be CFUN=4 ?
> + 3,
> + FALSE,
> + (GAsyncReadyCallback)modem_power_down_ready,
> + result);
If you're not going to do anything special with the response string, you
can avoid creating a new GSimpleAsyncResult; just do it as before with
the modem_reset(), i.e. call mm_base_modem_at_command() passing the
original callback and user_data.
> +}
> +
> +/*****************************************************************************/
> +/* Register in network (3GPP interface) */
Add whiteline here.
> +typedef enum {
> + REGISTRATION_STEP_FIRST,
> + REGISTRATION_STEP_SECOND
> +} RegistrationStep;
> +
> +typedef struct {
> + MMBroadbandModem *self;
> + GSimpleAsyncResult *result;
> + RegistrationStep step;
> +} RunRegistrationChecksContext;
> +
> +static void
> +run_registration_checks_context_complete_and_free (RunRegistrationChecksContext *ctx)
> +{
> + g_simple_async_result_complete_in_idle (ctx->result);
> + g_object_unref (ctx->result);
> + g_object_unref (ctx->self);
> + g_free (ctx);
> +}
> +
> +static gboolean
> +modem_3gpp_run_registration_checks_finish (MMIfaceModem3gpp *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
> +}
> +
> +static void run_registration_checks_context_step (RunRegistrationChecksContext *ctx);
> +
> +#define GCTREG "\\+(COPS):\\s*0*([0-9])\\s*,\\s*0*([0-9])\\s*,([^,\\)]*),\\s*0*([0-9])"
> +
> +static void
> +registration_status_check_ready (MMBroadbandModem *self,
> + GAsyncResult *res,
> + RunRegistrationChecksContext *ctx)
> +{
> + GRegex *r;
> + GMatchInfo *match_info;
> + const gchar *response;
> + GError *error;
> + gchar * reply;
> + gchar * cops_mode;
> + gchar * cops_format;
> + gchar * cops_operator = NULL;
> + gchar * cops_access_technology;
> +
> + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
> +
> + if(!response) {
> + g_simple_async_result_take_error (ctx->result, error);
> + run_registration_checks_context_complete_and_free (ctx);
> + }
> +
> + reply = strstr (response, "+COPS: ");
> +
> + r = g_regex_new (GCTREG, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
> +
> + g_assert (r != NULL);
> +
> + if (g_regex_match (r, reply, 0, &match_info)) {
> + cops_mode = g_match_info_fetch (match_info, 2);
> + cops_format = g_match_info_fetch (match_info, 3);
If you're not going to use them, don't fetch cops_mode and cops_format.
> + cops_operator = g_match_info_fetch (match_info, 4);
> + cops_access_technology = g_match_info_fetch (match_info, 5);
> +
> + if (strncmp (cops_operator+1, "FFFFF", 5) != 0)
> + {
The '{' goes in the same line as the if().
> + mm_iface_modem_3gpp_update_access_technologies (MM_IFACE_MODEM_3GPP (self), atoi(cops_access_technology));
Add whitespace after atoi and before the '('.
> + mm_iface_modem_3gpp_update_eps_registration_state( MM_IFACE_MODEM_3GPP(self), MM_MODEM_3GPP_REGISTRATION_STATE_HOME );
Remove whitespace before after '(' and before ')'; and also add
whitespace before '('.
> +
> + mm_dbg("modem is registered to network %s", cops_operator);
Add whitespace before the parenthesis.
> + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> + } else {
> + mm_dbg("modem is not registered to network");
Add whitespace before the parenthesis.
Also, you'll need to set the EPS registration state to
MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN and the access tech to
MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN in this case.
> + }
> + }
> +
> + g_match_info_free (match_info);
> + g_regex_unref (r);
> +
> + ctx->step++;
> +
> + run_registration_checks_context_step(ctx);
Add whitespace before the parenthesis.
> +}
> +
> +
> +static void
> +run_registration_checks_context_step (RunRegistrationChecksContext *ctx)
> +{
> + switch (ctx->step) {
> + case REGISTRATION_STEP_FIRST:
> + mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
> + "+COPS=3,2;+COPS?",
> + 10,
> + FALSE,
> + (GAsyncReadyCallback)registration_status_check_ready,
> + ctx);
> + break;
> + case REGISTRATION_STEP_SECOND:
> + g_simple_async_result_set_op_res_gpointer (ctx->result,
> + NULL,
> + NULL);
> + run_registration_checks_context_complete_and_free (ctx);
> + break;
> + }
> +}
> +
> +static void
> +modem_3gpp_run_registration_checks (MMIfaceModem3gpp *self,
> + gboolean cs_supported,
> + gboolean ps_supported,
> + gboolean eps_supported,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + RunRegistrationChecksContext *ctx;
If the whole purpose of this method is to run a single AT command and
parse its results, please remove the use of a
RunRegistrationChecksContext. Just mm_base_modem_at_command() here and
parse the results afterwards.
Also, is this (checking current operator) really the only way to check
if the modem is registered? Doesn't the modem support AT+CEREG?
> +
> + ctx = g_new0 (RunRegistrationChecksContext, 1);
> + ctx->self = g_object_ref (self);
> + ctx->result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + modem_3gpp_run_registration_checks);
> +
> + ctx->step = REGISTRATION_STEP_FIRST;
> +
> + run_registration_checks_context_step (ctx);
> +}
> +
> +/*****************************************************************************/
> +/* Capabilities loading (Modem interface) */
> +
> +static MMModemCapability
> +modem_load_current_capabilities_finish (MMIfaceModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return (MMModemCapability)GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
> + G_SIMPLE_ASYNC_RESULT (res)));
Align the parameters in the previous line.
> +}
> +
> +static void
> +modem_load_current_capabilities (MMIfaceModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> + MMModemCapability cap;
> +
> + /* With nm-applet, only GSM or CDMA devices are treated as compatible devices
> + * Add the GSM_UMTS flag for nm-applet */
> + cap = MM_MODEM_CAPABILITY_LTE | MM_MODEM_CAPABILITY_GSM_UMTS;
> +
Nope, no. If the nm-applet doesn't know how to handle LTE-only devices,
please report a bug for nm-applet and it will get updated. This modem
only does LTE it seems, so the proper way to handle this is to:
* Return *only* LTE in 'current capabilties'.
* Provide a NULL method to load 'supported capabilities' (will default
to 'current capabilities' in this case).
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + modem_load_current_capabilities);
> +
> + g_simple_async_result_set_op_res_gpointer (result,
> + GUINT_TO_POINTER (cap),
> + NULL);
> + g_simple_async_result_complete_in_idle (result);
> + g_object_unref (result);
> +}
> +
> +/*****************************************************************************/
> +/* Check if unlock required (Modem interface) */
> +
> +typedef struct {
> + const gchar *result;
> + MMModemLock code;
> +} CPinResult;
> +
> +static CPinResult unlock_results[] = {
> + /* Longer entries first so we catch the correct one with strcmp() */
> + { "READY", MM_MODEM_LOCK_NONE },
> + { "SIM PIN2", MM_MODEM_LOCK_SIM_PIN2 },
> + { "SIM PUK2", MM_MODEM_LOCK_SIM_PUK2 },
> + { "SIM PIN", MM_MODEM_LOCK_SIM_PIN },
> + { "SIM PUK", MM_MODEM_LOCK_SIM_PUK },
> + { "PH-NETSUB PIN", MM_MODEM_LOCK_PH_NETSUB_PIN },
> + { "PH-NETSUB PUK", MM_MODEM_LOCK_PH_NETSUB_PUK },
> + { "PH-FSIM PIN", MM_MODEM_LOCK_PH_FSIM_PIN },
> + { "PH-FSIM PUK", MM_MODEM_LOCK_PH_FSIM_PUK },
> + { "PH-CORP PIN", MM_MODEM_LOCK_PH_CORP_PIN },
> + { "PH-CORP PUK", MM_MODEM_LOCK_PH_CORP_PUK },
> + { "PH-SIM PIN", MM_MODEM_LOCK_PH_SIM_PIN },
> + { "PH-NET PIN", MM_MODEM_LOCK_PH_NET_PIN },
> + { "PH-NET PUK", MM_MODEM_LOCK_PH_NET_PUK },
> + { "PH-SP PIN", MM_MODEM_LOCK_PH_SP_PIN },
> + { "PH-SP PUK", MM_MODEM_LOCK_PH_SP_PUK },
> + { NULL }
> +};
> +
> +static MMModemLock
> +modem_load_unlock_required_finish (MMIfaceModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
> + return MM_MODEM_LOCK_UNKNOWN;
> +
> + return (MMModemLock) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
> + G_SIMPLE_ASYNC_RESULT (res)));
> +}
> +
> +static void
> +cpin_query_ready (MMIfaceModem *self,
> + GAsyncResult *res,
> + GSimpleAsyncResult *simple)
> +{
> +
> + MMModemLock lock = MM_MODEM_LOCK_UNKNOWN;
> + const gchar *result;
> + GError *error = NULL;
> +
> + result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
> + if (error) {
> + g_simple_async_result_take_error (simple, error);
> + g_simple_async_result_complete (simple);
> + g_object_unref (simple);
> + return;
> + }
> +
> + if (result &&
> + strstr (result, "+CPIN:")) {
> + CPinResult *iter = &unlock_results[0];
> + const gchar *str;
> +
> + str = strstr (result, "+CPIN:") + 6;
> + /* Skip possible whitespaces after '+CPIN:' and before the response */
> + while (*str == ' ')
> + str++;
> +
> + if (str[0] == '"')
> + str++;
> +
> + /* Translate the reply */
> + while (iter->result) {
> + if (g_str_has_prefix (str, iter->result)) {
> + lock = iter->code;
> + break;
> + }
> + iter++;
> + }
> + }
> +
> + g_simple_async_result_set_op_res_gpointer (simple,
> + GUINT_TO_POINTER (lock),
> + NULL);
> + g_simple_async_result_complete (simple);
> + g_object_unref (simple);
> +}
> +
> +static void
> +modem_load_unlock_required (MMIfaceModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + modem_load_unlock_required);
> +
> + mm_base_modem_at_command (MM_BASE_MODEM (self),
> + "+CPIN?",
> + 9, /* When initialzed for the first time, the SIM related operations can take a while */
If the only purpose of the whole subclassed method is to provide a
longer timeout here, which I believe is the case, we can probably update
the generic implementation to a longer value, like 10s; and fully remove
this method. Can you suggest an independent patch for that?
> + FALSE,
> + (GAsyncReadyCallback)cpin_query_ready,
> + result);
> +}
> +
> +/*****************************************************************************/
> +/* Location capabilities loading (Location interface) */
> +
> +static MMModemLocationSource
> +location_load_capabilities_finish (MMIfaceModemLocation *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return (MMModemLocationSource) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
> + G_SIMPLE_ASYNC_RESULT (res)));
> +}
> +
> +static void
> +location_load_capabilities (MMIfaceModemLocation *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> + MMModemLocationSource sources;
> +
> + /* By GCT modem alone, no location source available */
> + sources = MM_MODEM_LOCATION_SOURCE_NONE;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + location_load_capabilities);
> +
> + g_simple_async_result_set_op_res_gpointer (result,
> + GUINT_TO_POINTER (sources),
> + NULL);
> + g_simple_async_result_complete_in_idle (result);
> + g_object_unref (result);
> +}
> +
> +
> +/*****************************************************************************/
> +/* Load network timezone (Time interface) */
> +
> +static gboolean
> +parse_cclk_query_reply (const gchar *response,
> + gchar **iso8601,
> + MMNetworkTimezone **tz,
> + GError **error)
> +{
> + gint year;
> + gint month;
> + gint day;
> + gint hour;
> + gint minute;
> + gint second;
> + gchar sign;
> + gint offset;
> +
> + /* Example response would be something like +CCLK: 13/04/12,07:41:59+36 */
> + response = mm_strip_tag (response, "+CCLK: ");
> + if (sscanf (response,
> + "%02d/%02d/%02d,%02d:%02d:%02d%c%02d\"",
> + &year,
> + &month,
> + &day,
> + &hour,
> + &minute,
> + &second,
> + &sign,
> + &offset) == 8) {
> + /* Offset comes in 15-min intervals */
> + offset *= 15;
> + /* Apply sign to offset */
> + if (sign == '-')
> + offset *= -1;
> +
> + /* If asked for it, build timezone information */
> + if (tz) {
> + *tz = mm_network_timezone_new ();
> + mm_network_timezone_set_offset (*tz, offset);
> + }
> +
> + if (iso8601) {
> + /* GCT modems only report a 2-digit year, while ISO-8601 requires
> + * a 4-digit year. Assume 2000.
> + */
> + if (year < 100)
> + year += 2000;
> +
> + /* don't give tz info in the date/time string, we have another
> + * property for that */
> + *iso8601 = g_strdup_printf ("%04d/%02d/%02d %02d:%02d:%02d",
> + year, month, day,
> + hour, minute, second);
> + }
> +
> + return TRUE;
> + }
> +
> + g_set_error (error,
> + MM_CORE_ERROR,
> + MM_CORE_ERROR_FAILED,
> + "Unknown CCLK response: %s",
> + response);
> + return FALSE;
> +}
> +
> +static MMNetworkTimezone *
> +modem_time_load_network_timezone_finish (MMIfaceModemTime *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + const gchar *response;
> + MMNetworkTimezone *tz;
> +
> + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL);
> + if (!response) {
> + /* We'll assume we can retry a bit later */
> + g_set_error (error,
> + MM_CORE_ERROR,
> + MM_CORE_ERROR_RETRY,
> + "Retry");
> + return NULL;
> + }
> +
> + return (parse_cclk_query_reply (response, NULL, &tz, error) ? tz : NULL);
> +}
> +
> +static void
> +modem_time_load_network_timezone (MMIfaceModemTime *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + mm_base_modem_at_command (MM_BASE_MODEM (self),
> + "AT+CCLK?",
> + 3,
> + FALSE,
> + callback,
> + user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Load network time (Time interface) */
> +
> +static gchar *
> +modem_time_load_network_time_finish (MMIfaceModemTime *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + const gchar *response;
> + gchar *iso8601;
> +
> + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
> + if (!response)
> + return NULL;
> +
> + return (parse_cclk_query_reply (response, &iso8601, NULL, error) ? iso8601 : NULL);
> +}
> +
> +static void
> +modem_time_load_network_time (MMIfaceModemTime *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + mm_base_modem_at_command (MM_BASE_MODEM (self),
> + "AT+CCLK?",
> + 3,
> + FALSE,
> + callback,
> + user_data);
> +}
> +
> +/*****************************************************************************/
> +/* Check support (Time interface) */
> +
> +static gboolean
> +modem_time_check_support_finish (MMIfaceModemTime *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return TRUE;
> +}
> +
> +static void
> +modem_time_check_support (MMIfaceModemTime *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + modem_time_check_support);
> +
> + g_simple_async_result_complete_in_idle (result);
> + g_object_unref (result);
> +}
> +
> +
> +/*****************************************************************************/
> +/* Load supported modes (Modem interface) */
> +
> +static GArray *
> +modem_load_supported_modes_finish (MMIfaceModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)));
> +}
> +
> +static void
> +modem_load_supported_modes (MMIfaceModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> + GArray *combinations;
> + MMModemModeCombination mode;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + modem_load_supported_modes);
> +
> + combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
> +
> + mode.allowed = MM_MODEM_MODE_4G;
> + mode.preferred = MM_MODEM_MODE_NONE;
> + g_array_append_val (combinations, mode);
> +
Remove one whiteline, only one needed.
> +
> + g_simple_async_result_set_op_res_gpointer (result, combinations, (GDestroyNotify) g_array_unref);
> + g_simple_async_result_complete_in_idle (result);
> + g_object_unref (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_ANY;
> + return TRUE;
> +}
> +static void
> +load_access_technologies (MMIfaceModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + load_access_technologies);
> +
> + g_simple_async_result_set_op_res_gpointer (
> + result,
> + GUINT_TO_POINTER (MM_MODEM_ACCESS_TECHNOLOGY_LTE),
> + NULL);
> + g_simple_async_result_complete_in_idle (result);
> + g_object_unref (result);
> +}
> +
> +/*****************************************************************************/
> +/* Load unlock retries (Modem interface) */
> +
> +static MMUnlockRetries *
> +load_unlock_retries_finish (MMIfaceModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
> + return NULL;
> + return (MMUnlockRetries *) g_object_ref (g_simple_async_result_get_op_res_gpointer (
> + G_SIMPLE_ASYNC_RESULT (res)));
> +}
> +
> +static void
> +load_unlock_retries_ready (MMBaseModem *self,
> + GAsyncResult *res,
> + GSimpleAsyncResult *operation_result)
> +{
> + const gchar *response;
> + GError *error = NULL;
> + int pin1, pin2, puk1, puk2;
> +
> + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
> + if (!response) {
> + mm_dbg ("Couldn't query unlock retries: '%s'", error->message);
> + g_simple_async_result_take_error (operation_result, error);
> + g_simple_async_result_complete (operation_result);
> + g_object_unref (operation_result);
> + return;
> + }
> +
> + response = mm_strip_tag (response, "+CPINC:");
> + if (sscanf (response, " %d, %d, %d, %d", &pin1, &pin2, &puk1, &puk2) == 4) {
> + MMUnlockRetries *retries;
Whiteline needed between variable declarations and the first method call.
> + retries = mm_unlock_retries_new ();
> + mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN, pin1);
> + mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN2, pin2);
> + mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK, puk1);
> + mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK2, puk2);
> + g_simple_async_result_set_op_res_gpointer (operation_result,
> + retries,
> + (GDestroyNotify)g_object_unref);
> + } else {
> + g_simple_async_result_set_error (operation_result,
> + MM_CORE_ERROR,
> + MM_CORE_ERROR_FAILED,
> + "Invalid unlock retries response: '%s'",
> + response);
> + }
> + g_simple_async_result_complete (operation_result);
> + g_object_unref (operation_result);
> +}
> +
> +static void
> +load_unlock_retries (MMIfaceModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + mm_base_modem_at_command (
> + MM_BASE_MODEM (self),
> + "+CPINC?",
> + 3,
> + FALSE,
> + (GAsyncReadyCallback)load_unlock_retries_ready,
> + g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + load_unlock_retries));
> +}
> +
> +/*****************************************************************************/
> +/* First enabling step */
> +
AT+COPS=0 to automatically register in the home network is already
handled in the 3GPP interface's register_in_network() method, and I
don't believe you need it also in enabling_started(). It also isn't the
best place for it, as enabling_started() is actually run before powering
up the radio (if needed). You should probably remove the whole
enabling_started() subclassed method all together.
> +static void
> +auto_register_in_network (MMBroadbandModem *self,
> + GAsyncResult *res,
> + void* ctx)
> +{
> + GError *error;
> + const gchar *response;
> +
> + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
> + if (!response)
> + mm_dbg("Failed to get Auto Register result during enabling state");
> +}
> +
> +static gboolean
> +enabling_started_finish (MMBroadbandModem *self,
> + GAsyncResult *res,
> + GError **error)
> +{
> + mm_dbg("Auto Register during the enabling state");
> + mm_base_modem_at_command (MM_BASE_MODEM (self),
> + "AT+COPS=0",
> + 120,
> + FALSE,
> + (GAsyncReadyCallback)auto_register_in_network,
> + NULL);
> +
> + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
> +}
> +
> +static void
> +parent_enabling_started_ready (MMBroadbandModem *self,
> + GAsyncResult *res,
> + GSimpleAsyncResult *simple)
> +{
> + GError *error = NULL;
> +
> + if (!MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_gct_parent_class)->enabling_started_finish (
> + self,
> + res,
> + &error)) {
> + mm_dbg ("Couldn't start parent enabling: %s", error->message);
> + g_error_free (error);
> + }
> +
> + g_simple_async_result_set_op_res_gboolean (simple, TRUE);
> + g_simple_async_result_complete (simple);
> + g_object_unref (simple);
> +}
> +
> +static void
> +enabling_started (MMBroadbandModem *self,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GSimpleAsyncResult *result;
> +
> + result = g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + enabling_started);
> + MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_gct_parent_class)->enabling_started (
> + self,
> + (GAsyncReadyCallback)parent_enabling_started_ready,
> + result);
> +}
> +
> +/*****************************************************************************/
> +
> +MMBroadbandModemGct *
> +mm_broadband_modem_gct_new (const gchar *device,
> + const gchar **drivers,
> + const gchar *plugin,
> + guint16 vendor_id,
> + guint16 product_id)
> +{
> + return g_object_new (MM_TYPE_BROADBAND_MODEM_GCT,
> + 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,
> + 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_gct_init (MMBroadbandModemGct *self)
> +{
> + mm_dbg("GCT modem manager plugin built on %s, at %s", __DATE__, __TIME__);
No need for this log message.
> +}
> +
> +static void
> +iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
> +{
> + /* Other actions */
> + iface->run_registration_checks = modem_3gpp_run_registration_checks;
> + iface->run_registration_checks_finish = modem_3gpp_run_registration_checks_finish;
> + iface->setup_unsolicited_events = NULL;
> + iface->setup_unsolicited_events_finish = NULL;
> +}
> +
> +static void
> +iface_modem_3gpp_ussd_init (MMIfaceModem3gppUssd *iface)
> +{
> + /* Assume we don't have USSD support */
> + iface->check_support = NULL;
> + iface->check_support_finish = NULL;
> +}
> +
> +static void
> +iface_modem_location_init (MMIfaceModemLocation *iface)
> +{
> + iface->load_capabilities = location_load_capabilities;
> + iface->load_capabilities_finish = location_load_capabilities_finish;
> +}
> +
> +static void
> +iface_modem_time_init (MMIfaceModemTime *iface)
> +{
> + iface->check_support = modem_time_check_support;
> + iface->check_support_finish = modem_time_check_support_finish;
> + iface->load_network_time = modem_time_load_network_time;
> + iface->load_network_time_finish = modem_time_load_network_time_finish;
> + iface->load_network_timezone = modem_time_load_network_timezone;
> + iface->load_network_timezone_finish = modem_time_load_network_timezone_finish;
> +}
> +
> +static void
> +iface_modem_messaging_init (MMIfaceModemMessaging *iface)
> +{
> + iface->check_support = NULL;
> + iface->check_support_finish = NULL;
This is not right. If there is no implementation to check support; it is
assumed that messaging is NOT supported. If you want to support it,
please provide a custom check_support() method for the messaging
interface. If it is always supported, the method can just return TRUE
without doing further checkes.
> + iface->setup_sms_format = messaging_setup_sms_format;
> + iface->setup_sms_format_finish = messaging_setup_sms_format_finish;
> + iface->enable_unsolicited_events = messaging_enable_unsolicited_events;
> + iface->enable_unsolicited_events_finish = messaging_enable_unsolicited_events_finish;
> + iface->setup_unsolicited_events = modem_messaging_setup_unsolicited_events;
> + iface->setup_unsolicited_events_finish = modem_messaging_setup_cleanup_unsolicited_events_finish;
> +}
> +
> +static void
> +iface_modem_init (MMIfaceModem *iface)
> +{
> + iface_modem_parent = g_type_interface_peek_parent (iface);
> +
> + iface->create_bearer = modem_create_bearer;
> + iface->create_bearer_finish = modem_create_bearer_finish;
> + iface->load_current_capabilities = modem_load_current_capabilities;
> + iface->load_current_capabilities_finish = modem_load_current_capabilities_finish;
> + iface->load_unlock_required = modem_load_unlock_required;
> + iface->load_unlock_required_finish = modem_load_unlock_required_finish;
> +
> + iface->create_sim = modem_create_sim;
> + iface->create_sim_finish = modem_create_sim_finish;
> + iface->load_supported_modes = modem_load_supported_modes;
> + iface->load_supported_modes_finish = modem_load_supported_modes_finish;
> + iface->load_access_technologies = load_access_technologies;
> + iface->load_access_technologies_finish = load_access_technologies_finish;
> + iface->load_unlock_retries = load_unlock_retries;
> + iface->load_unlock_retries_finish = load_unlock_retries_finish;
> + iface->setup_flow_control = NULL;
> + iface->setup_flow_control_finish = NULL;
> +
> + iface->modem_power_down = modem_power_down;
> + iface->modem_power_down_finish = modem_power_down_finish;
> + iface->reset = modem_reset;
> + iface->reset_finish = modem_reset_finish;
> +}
> +
> +static void
> +mm_broadband_modem_gct_class_init (MMBroadbandModemGctClass *klass)
> +{
> + MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
> +
> + broadband_modem_class->setup_ports = setup_ports;
> + broadband_modem_class->enabling_started = enabling_started;
> + broadband_modem_class->enabling_started_finish = enabling_started_finish;
> + broadband_modem_class->enabling_modem_init = NULL;
> + broadband_modem_class->enabling_modem_init_finish = NULL;
> +}
> diff --git a/plugins/gct/mm-broadband-modem-gct.h b/plugins/gct/mm-broadband-modem-gct.h
> new file mode 100644
> index 0000000..6fe698c
> --- /dev/null
> +++ b/plugins/gct/mm-broadband-modem-gct.h
> @@ -0,0 +1,54 @@
> +/* -*- 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 GCT Semiconductor, Inc.
> + * Author: Glen Lee <glenlee at gctsemi.com>
> + */
> +
> +#ifndef MM_BROADBAND_MODEM_GCT_H
> +#define MM_BROADBAND_MODEM_GCT_H
> +
> +#include "mm-broadband-modem.h"
> +
> +#define MM_TYPE_BROADBAND_MODEM_GCT (mm_broadband_modem_gct_get_type ())
> +#define MM_BROADBAND_MODEM_GCT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_GCT, MMBroadbandModemGct))
> +#define MM_BROADBAND_MODEM_GCT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_GCT, MMBroadbandModemGctClass))
> +#define MM_IS_BROADBAND_MODEM_GCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_GCT))
> +#define MM_IS_BROADBAND_MODEM_GCT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_GCT))
> +#define MM_BROADBAND_MODEM_GCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_GCT, MMBroadbandModemGctClass))
> +
> +typedef struct _MMBroadbandModemGct MMBroadbandModemGct;
> +typedef struct _MMBroadbandModemGctClass MMBroadbandModemGctClass;
> +typedef struct _MMBroadbandModemGctPrivate MMBroadbandModemGctPrivate;
> +
> +struct _MMBroadbandModemGct {
> + MMBroadbandModem parent;
> + MMBroadbandModemGctPrivate *priv;
> +};
> +
> +struct _MMBroadbandModemGctClass{
> + MMBroadbandModemClass parent;
> +};
> +
> +GType mm_broadband_modem_gct_get_type (void);
> +
> +MMBroadbandModemGct *mm_broadband_modem_gct_new (const gchar *device,
> + const gchar **drivers,
> + const gchar *plugin,
> + guint16 vendor_id,
> + guint16 product_id);
> +
> +void modem_bearer_get_info(MMBroadbandModemGct *self,
> + guint8 *connected);
As said previously, no need of this method in the header.
> +
> +
> +#endif /* MM_BROADBAND_MODEM_GCT_H */
> diff --git a/plugins/gct/mm-plugin-gct.c b/plugins/gct/mm-plugin-gct.c
> new file mode 100644
> index 0000000..99e1d84
> --- /dev/null
> +++ b/plugins/gct/mm-plugin-gct.c
> @@ -0,0 +1,224 @@
> +/* -*- 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 GCT Semiconductor, Inc.
> + * Author: Glen Lee <glenlee at gctsemi.com>
> + */
> +
> +#include <string.h>
> +#include <gmodule.h>
> +
> +#define _LIBMM_INSIDE_MM
> +#include <libmm-glib.h>
> +
> +#include "mm-plugin-gct.h"
> +#include "mm-private-boxed-types.h"
> +#include "mm-broadband-modem-gct.h"
> +#include "mm-log.h"
> +
> +G_DEFINE_TYPE (MMPluginGct, mm_plugin_gct, MM_TYPE_PLUGIN)
> +
> +int mm_plugin_major_version = MM_PLUGIN_MAJOR_VERSION;
> +int mm_plugin_minor_version = MM_PLUGIN_MINOR_VERSION;
> +
> +/*****************************************************************************/
> +/* Custom init */
> +
> +typedef struct {
> + MMPortProbe *probe;
> + MMAtSerialPort *port;
> + GCancellable *cancellable;
> + GSimpleAsyncResult *result;
> + guint retries;
> +} GctCustomInitContext;
> +
> +static void
> +gct_custom_init_context_complete_and_free (GctCustomInitContext *ctx)
> +{
> + g_simple_async_result_complete_in_idle (ctx->result);
> +
> + if (ctx->cancellable)
> + g_object_unref (ctx->cancellable);
> + g_object_unref (ctx->port);
> + g_object_unref (ctx->probe);
> + g_object_unref (ctx->result);
> + g_slice_free (GctCustomInitContext, ctx);
> +}
> +
> +static gboolean
> +gct_custom_init_finish (MMPortProbe *probe,
> + GAsyncResult *result,
> + GError **error)
> +{
> + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
> +}
> +
> +static void gct_custom_init_step (GctCustomInitContext *ctx);
> +
> +static void
> +lteinit_ready (MMAtSerialPort *port,
> + GString *response,
> + GError *error,
> + GctCustomInitContext *ctx)
Alignment needed in the parameters in the previous method.
> +{
> + if (error) {
> + /* If consumed all tries and the last error was a timeout, assume the
> + * port is not AT */
> + if (ctx->retries == 0 &&
> + g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) {
> + mm_port_probe_set_result_at (ctx->probe, FALSE);
> + }
> +
> + /* Just retry... */
> + gct_custom_init_step (ctx);
> + return;
> + }
> +
> + mm_port_probe_set_result_at (ctx->probe, TRUE);
> +
> + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> + gct_custom_init_context_complete_and_free (ctx);
> +}
> +
> +static void
> +gct_custom_init_step (GctCustomInitContext *ctx)
> +{
> + if (g_cancellable_is_cancelled (ctx->cancellable)) {
> + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> + gct_custom_init_context_complete_and_free (ctx);
> + return;
> + }
> +
> + if (ctx->retries == 0) {
> + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
> + gct_custom_init_context_complete_and_free (ctx);
> + return;
> + }
> +
> + ctx->retries--;
> + mm_at_serial_port_queue_command (
> + ctx->port,
> + "AT%LTEINIT",
> + 2,
> + FALSE, /* raw */
> + ctx->cancellable,
> + (MMAtSerialResponseFn)lteinit_ready,
> + ctx);
Out of curiosity; which is the purpose of the previous AT%LTEINIT
command? I'm wondering if it really needs to go as a custom_init()
command. The custom init is usually needed to prepare the modem to get
properly grabbed by the plugin, or to gather information about the port
types and such. In other words, will the modem be detected without the
AT%LTEINIT command? We can always add the command to some other step in
the logic, depending its purpose. So, could you explain a bit what it does?
> +}
> +
> +static void
> +gct_custom_init (MMPortProbe *probe,
> + MMAtSerialPort *port,
> + GCancellable *cancellable,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
> +{
> + GctCustomInitContext *ctx;
> +
> + ctx = g_slice_new (GctCustomInitContext);
> + ctx->result = g_simple_async_result_new (G_OBJECT (probe),
> + callback,
> + user_data,
> + gct_custom_init);
> + ctx->probe = g_object_ref (probe);
> + ctx->port = g_object_ref (port);
> + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
> + ctx->retries = 2;
> +
> + gct_custom_init_step (ctx);
> +}
> +
> +/*****************************************************************************/
> +
> +
> +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_gct_new (sysfs_path,
> + drivers,
> + mm_plugin_get_name (self),
> + vendor,
> + product));
Alignment needed in the parameters in the previous method.
> +}
> +
> +static gboolean
> +grab_port (MMPlugin *self,
> + MMBaseModem *modem,
> + MMPortProbe *probe,
> + GError **error)
> +{
> + MMPortType ptype;
> + MMAtPortFlag pflags = MM_AT_PORT_FLAG_NONE;
> +
> + ptype = mm_port_probe_get_port_type (probe);
> +
> + /* Always prefer the ttyACM port as PRIMARY AT port */
> + if (ptype == MM_PORT_TYPE_AT &&
> + g_str_has_prefix (mm_port_probe_get_port_name (probe), "GCT-ATC")) {
> + pflags = MM_AT_PORT_FLAG_PRIMARY;
> + }
> +
> + return mm_base_modem_grab_port (modem,
> + mm_port_probe_get_port_subsys (probe),
> + mm_port_probe_get_port_name (probe),
> + ptype,
> + pflags,
> + error);
> +}
> +
> +G_MODULE_EXPORT MMPlugin *
> +mm_plugin_create (void)
> +{
> + static const gchar *subsystems[] = { "tty", "net", NULL };
> + static const mm_uint16_pair product_ids[] = {
> + { 0x1076, 0x8000 },
> + { 0, 0 }
> + };
> + static const MMAsyncMethod custom_init = {
> + .async = G_CALLBACK (gct_custom_init),
> + .finish = G_CALLBACK (gct_custom_init_finish),
> + };
> + return MM_PLUGIN (
> + g_object_new (MM_TYPE_PLUGIN_GCT,
> + MM_PLUGIN_NAME, "Gct",
> + MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
> + MM_PLUGIN_ALLOWED_PRODUCT_IDS, product_ids,
> + MM_PLUGIN_CUSTOM_INIT, &custom_init,
> + MM_PLUGIN_ALLOWED_AT, TRUE,
> + NULL));
> +}
> +
> +static void
> +mm_plugin_gct_init (MMPluginGct *self)
> +{
> +}
> +
> +static void
> +mm_plugin_gct_class_init (MMPluginGctClass *klass)
> +{
> + MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
> +
> + plugin_class->create_modem = create_modem;
> + plugin_class->grab_port = grab_port;
> +}
> diff --git a/plugins/gct/mm-plugin-gct.h b/plugins/gct/mm-plugin-gct.h
> new file mode 100644
> index 0000000..f404c3b
> --- /dev/null
> +++ b/plugins/gct/mm-plugin-gct.h
> @@ -0,0 +1,47 @@
> +/* -*- 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 GCT Semiconductor, Inc.
> + * Author: Glen Lee <glenlee at gctsemi.com>
> + */
> +
> +#ifndef MM_PLUGIN_GCT_H
> +#define MM_PLUGIN_GCT_H
> +
> +#include "mm-plugin.h"
> +
> +#define MM_TYPE_PLUGIN_GCT (mm_plugin_gct_get_type ())
> +#define MM_PLUGIN_GCT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_GCT, MMPluginGct))
> +#define MM_PLUGIN_GCT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_GCT, MMPluginGctClass))
> +#define MM_IS_PLUGIN_GCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_GCT))
> +#define MM_IS_PLUGIN_GCT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_GCT))
> +#define MM_PLUGIN_GCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_GCT, MMPluginGctClass))
> +
> +typedef struct {
> + MMPlugin parent;
> +} MMPluginGct;
> +
> +typedef struct {
> + MMPluginClass parent;
> +} MMPluginGctClass;
> +
> +GType mm_plugin_gct_get_type (void);
> +
> +G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
> +
> +#endif /* MM_PLUGIN_GCT_H */
> diff --git a/plugins/gct/mm-sim-gct.c b/plugins/gct/mm-sim-gct.c
> new file mode 100644
> index 0000000..81b5ffc
> --- /dev/null
> +++ b/plugins/gct/mm-sim-gct.c
> @@ -0,0 +1,131 @@
> +/* -*- 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 GCT Semiconductor, Inc.
> + * Author: Glen Lee <glenlee at gctsemi.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-log.h"
> +#include "mm-modem-helpers.h"
> +#include "mm-base-modem-at.h"
> +
> +#include "mm-sim-gct.h"
> +
> +G_DEFINE_TYPE (MMSimGct, mm_sim_gct, MM_TYPE_SIM);
> +
> +
> +static void
> +change_pin_ready (MMBaseModem *modem,
> + GAsyncResult *res,
> + GSimpleAsyncResult *simple)
> +{
> + GError *error = NULL;
> +
> + mm_base_modem_at_command_finish (modem, res, &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
> +change_pin (MMSim *self,
> + const gchar *old_pin,
> + const gchar *new_pin,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
Alignment needed in the parameters in the previous method declaration.
> +{
> + MMBaseModem *modem = NULL;
> + gchar *command;
> +
> + g_object_get (self,
> + MM_SIM_MODEM, &modem,
> + NULL);
> +
> + command = g_strdup_printf ("+CPWD=\"P2\",\"%s\",\"%s\"",
> + old_pin,
> + new_pin);
Alignment needed in the parameters in the previous method.
> + mm_base_modem_at_command (
> + MM_BASE_MODEM (modem),
> + command,
> + 3,
> + FALSE,
> + (GAsyncReadyCallback)change_pin_ready,
> + g_simple_async_result_new (G_OBJECT (self),
> + callback,
> + user_data,
> + change_pin));
> + g_object_unref (modem);
> +}
> +
> +
> +/*****************************************************************************/
> +
> +MMSim *
> +mm_sim_gct_new_finish (GAsyncResult *res,
> + GError **error)
Alignment needed in the parameters in the previous method declaration.
> +{
> + GObject *source;
> + GObject *sim;
> +
> + source = g_async_result_get_source_object (res);
> + sim = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, error);
> + g_object_unref (source);
> +
> + if (!sim)
> + return NULL;
> +
> + /* Only export valid SIMs */
> + mm_sim_export (MM_SIM (sim));
> +
> + return MM_SIM (sim);
> +}
> +
> +void
> +mm_sim_gct_new (MMBaseModem *modem,
> + GCancellable *cancellable,
> + GAsyncReadyCallback callback,
> + gpointer user_data)
Alignment needed in the parameters in the previous method declaration.
> +{
> + g_async_initable_new_async (MM_TYPE_SIM_GCT,
> + G_PRIORITY_DEFAULT,
> + cancellable,
> + callback,
> + user_data,
> + MM_SIM_MODEM, modem,
> + NULL);
> +}
> +
> +static void
> +mm_sim_gct_init (MMSimGct *self)
> +{
> +}
> +
> +static void
> +mm_sim_gct_class_init (MMSimGctClass *klass)
> +{
> + MMSimClass *sim_class = MM_SIM_CLASS (klass);
> +
> + sim_class->change_pin = change_pin;
Is the PIN change really the only method that needs to be subclassed?
> +}
> diff --git a/plugins/gct/mm-sim-gct.h b/plugins/gct/mm-sim-gct.h
> new file mode 100644
> index 0000000..6bbb428
> --- /dev/null
> +++ b/plugins/gct/mm-sim-gct.h
> @@ -0,0 +1,52 @@
> +/* -*- 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 GCT Semiconductor, Inc.
> + * Author: Glen Lee <glenlee at gctsemi.com>
> + */
> +
> +#ifndef MM_SIM_GCT_H
> +#define MM_SIM_GCT_H
> +
> +#include <glib.h>
> +#include <glib-object.h>
> +
> +#include "mm-sim.h"
> +
> +#define MM_TYPE_SIM_GCT (mm_sim_gct_get_type ())
> +#define MM_SIM_GCT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SIM_GCT, MMSimGct))
> +#define MM_SIM_GCT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SIM_GCT, MMSimGctClass))
> +#define MM_IS_SIM_GCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SIM_GCT))
> +#define MM_IS_SIM_GCT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SIM_GCT))
> +#define MM_SIM_GCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SIM_GCT, MMSimGctClass))
> +
> +typedef struct _MMSimGct MMSimGct;
> +typedef struct _MMSimGctClass MMSimGctClass;
> +
> +struct _MMSimGct {
> + MMSim parent;
> +};
> +
> +struct _MMSimGctClass {
> + MMSimClass parent;
> +};
> +
> +GType mm_sim_gct_get_type (void);
> +
> +void mm_sim_gct_new (MMBaseModem *modem,
> + GCancellable *cancellable,
> + GAsyncReadyCallback callback,
> + gpointer user_data);
> +MMSim *mm_sim_gct_new_finish (GAsyncResult *res,
> + GError **error);
Parameters need to be aligned here in the previous two methods.
> +
> +#endif /* MM_SIM_GCT_H */
>
--
Aleksander
More information about the ModemManager-devel
mailing list