build: move plugins directory to src/plugins
We are going to allow including the plugin sources built within the ModemManager daemon binary; moving the sources within the daemon sources directory makes it easier.
This commit is contained in:
committed by
Aleksander Morgado
parent
072d7ac906
commit
e14b904cbd
@@ -0,0 +1,160 @@
|
||||
|
||||
The following list shows the relationship among the different plugins provided
|
||||
by default by ModemManager. For each of the plugin types, the list of modem
|
||||
objects created by the plugin is given.
|
||||
|
||||
* Altair:
|
||||
** MMBroadbandModemAltairLte
|
||||
|
||||
* Anydata:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemAnydata
|
||||
|
||||
* Cinterion:
|
||||
** MMBroadbandModemQmiCinterion
|
||||
** MMBroadbandModemCinterion
|
||||
|
||||
* Dell:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemFoxconnT77w968 (from the Foxconn utils)
|
||||
** MMBroadbandModemMbimXmm (from the XMM utils)
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModemNovatel (from the Novatel utils)
|
||||
** MMBroadbandModemSierra (from the Sierra Legacy utils)
|
||||
** MMBroadbandModemTelit (from the Telit utils)
|
||||
** MMBroadbandModemXmm (from the XMM utils)
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* D-Link:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* Fibocom:
|
||||
** MMBroadbandModemMbimXmm (from the XMM utils)
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModemXmm (from the XMM utils)
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* Foxconn:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemFoxconnT77w968
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* Generic:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* Gosuncn:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* Haier:
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* Huawei:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModemHuawei
|
||||
|
||||
* Icera (no explicit plugin):
|
||||
** MMBroadbandModemIcera
|
||||
|
||||
* Iridium:
|
||||
** MMBroadbandModemIridium
|
||||
|
||||
* Linktop:
|
||||
** MMBroadbandModemLinktop
|
||||
|
||||
* Longcheer:
|
||||
** MMBroadbandModemLongcheer
|
||||
|
||||
* MBM:
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModemMbm
|
||||
|
||||
* Motorola:
|
||||
** MMBroadbandModemMotorola
|
||||
|
||||
* Mtk:
|
||||
** MMBroadbandModemMtk
|
||||
|
||||
* Nokia:
|
||||
** MMBroadbandModemNokia
|
||||
|
||||
* Nokia Icera:
|
||||
** MMBroadbandModemIcera (from the Icera utils)
|
||||
|
||||
* Novatel:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemNovatel
|
||||
|
||||
* Novatel LTE:
|
||||
** MMBroadbandModemNovatelLte
|
||||
|
||||
* Option:
|
||||
** MMBroadbandModemOption
|
||||
|
||||
* Option HSO:
|
||||
** MMBroadbandModemHso
|
||||
|
||||
* Pantech:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemPantech
|
||||
|
||||
* Quectel:
|
||||
** MMBroadbandModemQmiQuectel
|
||||
** MMBroadbandModemQuectel
|
||||
|
||||
* Samsung:
|
||||
** MMBroadbandModemSamsung (subclassed from the Icera utils)
|
||||
|
||||
* Sierra Legacy:
|
||||
** MMBroadbandModemSierraIcera (subclassed from the Icera utils)
|
||||
** MMBroadbandModemSierra
|
||||
|
||||
* Sierra:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* Simtech:
|
||||
** MMBroadbandModemQmiSimtech
|
||||
** MMBroadbandModemSimtech
|
||||
|
||||
* Telit:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemMbimTelit
|
||||
** MMBroadbandModemTelit
|
||||
|
||||
* Thuraya
|
||||
** MMBroadbandModemThuraya
|
||||
|
||||
* TP-Link:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModem (generic)
|
||||
|
||||
* u-blox:
|
||||
** MMBroadbandModemUblox
|
||||
|
||||
* via:
|
||||
** MMBroadbandModemVia
|
||||
|
||||
* wavecom:
|
||||
** MMBroadbandModemWavecom
|
||||
|
||||
* x22x:
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemX22x
|
||||
|
||||
* XMM (no explicit plugin):
|
||||
** MMBroadbandModemMbimXmm
|
||||
** MMBroadbandModemXmm
|
||||
|
||||
* ZTE
|
||||
** MMBroadbandModemQmi (generic)
|
||||
** MMBroadbandModemMbim (generic)
|
||||
** MMBroadbandModemZteIcera (subclassed from the Icera utils)
|
||||
** MMBroadbandModemZte
|
||||
@@ -0,0 +1,370 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2013 Altair Semiconductor
|
||||
*
|
||||
* Author: Ori Inbar <ori.inbar@altair-semi.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-broadband-bearer-altair-lte.h"
|
||||
#include "mm-iface-modem-3gpp.h"
|
||||
#include "mm-log.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
|
||||
#define CONNECTION_CHECK_TIMEOUT_SEC 5
|
||||
#define STATCM_TAG "%STATCM:"
|
||||
|
||||
G_DEFINE_TYPE (MMBroadbandBearerAltairLte, mm_broadband_bearer_altair_lte, MM_TYPE_BROADBAND_BEARER);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP Connect sequence */
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
MMPort *data;
|
||||
} DetailedConnectContext;
|
||||
|
||||
static void
|
||||
detailed_connect_context_free (DetailedConnectContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->data);
|
||||
g_object_unref (ctx->primary);
|
||||
g_object_unref (ctx->modem);
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static MMBearerConnectResult *
|
||||
connect_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_3gpp_connect_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
DetailedConnectContext *ctx;
|
||||
const gchar *result;
|
||||
GError *error = NULL;
|
||||
MMBearerIpConfig *config;
|
||||
|
||||
result = mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (!result) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
config = mm_bearer_ip_config_new ();
|
||||
|
||||
mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP);
|
||||
|
||||
/* Set operation result */
|
||||
g_task_return_pointer (
|
||||
task,
|
||||
mm_bearer_connect_result_new (ctx->data, config, config),
|
||||
(GDestroyNotify)mm_bearer_connect_result_unref);
|
||||
g_object_unref (task);
|
||||
|
||||
g_object_unref (config);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_3gpp_apnsettings_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
DetailedConnectContext *ctx;
|
||||
const gchar *result;
|
||||
GError *error = NULL;
|
||||
|
||||
result = mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (!result) {
|
||||
g_prefix_error (&error, "setting APN failed: ");
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
"%DPDNACT=1",
|
||||
MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT, /* timeout */
|
||||
FALSE, /* allow_cached */
|
||||
FALSE, /* is_raw */
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback)connect_3gpp_connect_ready,
|
||||
task); /* user_data */
|
||||
}
|
||||
|
||||
static void
|
||||
connect_3gpp (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
DetailedConnectContext *ctx;
|
||||
gchar *command, *apn;
|
||||
MMBearerProperties *config;
|
||||
MMModem3gppRegistrationState registration_state;
|
||||
MMPort *data;
|
||||
GTask *task;
|
||||
|
||||
/* There is a known firmware bug that can leave the modem unusable if a
|
||||
* connect attempt is made when out of coverage. So, fail without trying.
|
||||
*/
|
||||
g_object_get (modem,
|
||||
MM_IFACE_MODEM_3GPP_REGISTRATION_STATE, ®istration_state,
|
||||
NULL);
|
||||
if (registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN) {
|
||||
g_task_report_new_error (self,
|
||||
callback,
|
||||
user_data,
|
||||
connect_3gpp,
|
||||
MM_MOBILE_EQUIPMENT_ERROR,
|
||||
MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK,
|
||||
"Out of coverage, can't connect.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't allow a connect while we detach from the network to process SIM
|
||||
* refresh.
|
||||
* */
|
||||
if (mm_broadband_modem_altair_lte_is_sim_refresh_detach_in_progress (modem)) {
|
||||
mm_obj_dbg (self, "detached from network to process SIM refresh, failing connect request");
|
||||
g_task_report_new_error (self,
|
||||
callback,
|
||||
user_data,
|
||||
connect_3gpp,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_RETRY,
|
||||
"Detached from network to process SIM refresh, can't connect.");
|
||||
return;
|
||||
}
|
||||
|
||||
data = mm_base_modem_peek_best_data_port (MM_BASE_MODEM (modem), MM_PORT_TYPE_NET);
|
||||
if (!data) {
|
||||
g_task_report_new_error (self,
|
||||
callback,
|
||||
user_data,
|
||||
connect_3gpp,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_CONNECTED,
|
||||
"Couldn't connect: no available net port available");
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_new0 (DetailedConnectContext, 1);
|
||||
ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->data = g_object_ref (data);
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)detailed_connect_context_free);
|
||||
|
||||
config = mm_base_bearer_peek_config (MM_BASE_BEARER (self));
|
||||
apn = mm_port_serial_at_quote_string (mm_bearer_properties_get_apn (config));
|
||||
command = g_strdup_printf ("%%APNN=%s", apn);
|
||||
g_free (apn);
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
command,
|
||||
10, /* timeout */
|
||||
FALSE, /* allow_cached */
|
||||
FALSE, /* is_raw */
|
||||
cancellable,
|
||||
(GAsyncReadyCallback)connect_3gpp_apnsettings_ready,
|
||||
task); /* user_data */
|
||||
g_free (command);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP Disconnect sequence */
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
MMPort *data;
|
||||
} DetailedDisconnectContext;
|
||||
|
||||
static gboolean
|
||||
disconnect_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
detailed_disconnect_context_free (DetailedDisconnectContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->data);
|
||||
g_object_unref (ctx->primary);
|
||||
g_object_unref (ctx->modem);
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp_check_status (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
|
||||
const gchar *result;
|
||||
GError *error = NULL;
|
||||
|
||||
result = mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (!result)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
MMPort *data,
|
||||
guint cid,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
DetailedDisconnectContext *ctx;
|
||||
MMModem3gppRegistrationState registration_state;
|
||||
GTask *task;
|
||||
|
||||
/* There is a known firmware bug that can leave the modem unusable if a
|
||||
* disconnect attempt is made when out of coverage. So, fail without trying.
|
||||
*/
|
||||
g_object_get (modem,
|
||||
MM_IFACE_MODEM_3GPP_REGISTRATION_STATE, ®istration_state,
|
||||
NULL);
|
||||
if (registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN) {
|
||||
g_task_report_new_error (self,
|
||||
callback,
|
||||
user_data,
|
||||
disconnect_3gpp,
|
||||
MM_MOBILE_EQUIPMENT_ERROR,
|
||||
MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK,
|
||||
"Out of coverage, can't disconnect.");
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_new0 (DetailedDisconnectContext, 1);
|
||||
ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->data = g_object_ref (data);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)detailed_disconnect_context_free);
|
||||
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
"%DPDNACT=0",
|
||||
MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT, /* timeout */
|
||||
FALSE, /* allow_cached */
|
||||
FALSE, /* is_raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback)disconnect_3gpp_check_status,
|
||||
task); /* user_data */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseBearer *
|
||||
mm_broadband_bearer_altair_lte_new_finish (GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
GObject *bearer;
|
||||
GObject *source;
|
||||
|
||||
source = g_async_result_get_source_object (res);
|
||||
bearer = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, error);
|
||||
g_object_unref (source);
|
||||
|
||||
if (!bearer)
|
||||
return NULL;
|
||||
|
||||
/* Only export valid bearers */
|
||||
mm_base_bearer_export (MM_BASE_BEARER (bearer));
|
||||
|
||||
return MM_BASE_BEARER (bearer);
|
||||
}
|
||||
|
||||
void
|
||||
mm_broadband_bearer_altair_lte_new (MMBroadbandModemAltairLte *modem,
|
||||
MMBearerProperties *config,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE,
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data,
|
||||
MM_BASE_BEARER_MODEM, modem,
|
||||
MM_BASE_BEARER_CONFIG, config,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_altair_lte_init (MMBroadbandBearerAltairLte *self)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_altair_lte_class_init (MMBroadbandBearerAltairLteClass *klass)
|
||||
{
|
||||
MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass);
|
||||
MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass);
|
||||
|
||||
base_bearer_class->load_connection_status = NULL;
|
||||
base_bearer_class->load_connection_status_finish = NULL;
|
||||
#if defined WITH_SUSPEND_RESUME
|
||||
base_bearer_class->reload_connection_status = NULL;
|
||||
base_bearer_class->reload_connection_status_finish = NULL;
|
||||
#endif
|
||||
|
||||
broadband_bearer_class->connect_3gpp = connect_3gpp;
|
||||
broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish;
|
||||
broadband_bearer_class->disconnect_3gpp = disconnect_3gpp;
|
||||
broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2013 Altair Semiconductor
|
||||
*
|
||||
* Author: Ori Inbar <ori.inbar@altair-semi.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_BEARER_ALTAIR_LTE_H
|
||||
#define MM_BROADBAND_BEARER_ALTAIR_LTE_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-broadband-bearer.h"
|
||||
#include "mm-broadband-modem-altair-lte.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE (mm_broadband_bearer_altair_lte_get_type ())
|
||||
#define MM_BROADBAND_BEARER_ALTAIR_LTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE, MMBroadbandBearerAltairLte))
|
||||
#define MM_BROADBAND_BEARER_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE, MMBroadbandBearerAltairLteClass))
|
||||
#define MM_IS_BROADBAND_BEARER_ALTAIR_LTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE))
|
||||
#define MM_IS_BROADBAND_BEARER_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE))
|
||||
#define MM_BROADBAND_BEARER_ALTAIR_LTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_BEARER_ALTAIR_LTE, MMBroadbandBearerAltairLteClass))
|
||||
|
||||
typedef struct _MMBroadbandBearerAltairLte MMBroadbandBearerAltairLte;
|
||||
typedef struct _MMBroadbandBearerAltairLteClass MMBroadbandBearerAltairLteClass;
|
||||
|
||||
struct _MMBroadbandBearerAltairLte {
|
||||
MMBroadbandBearer parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandBearerAltairLteClass {
|
||||
MMBroadbandBearerClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_bearer_altair_lte_get_type (void);
|
||||
|
||||
/* Default 3GPP bearer creation implementation */
|
||||
void mm_broadband_bearer_altair_lte_new (MMBroadbandModemAltairLte *modem,
|
||||
MMBearerProperties *properties,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
MMBaseBearer *mm_broadband_bearer_altair_lte_new_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_BROADBAND_BEARER_ALTAIR_LTE_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2013 Altair Semiconductor
|
||||
*
|
||||
* Author: Ori Inbar <ori.inbar@altair-semi.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_ALTAIR_LTE_H
|
||||
#define MM_BROADBAND_MODEM_ALTAIR_LTE_H
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE (mm_broadband_modem_altair_lte_get_type ())
|
||||
#define MM_BROADBAND_MODEM_ALTAIR_LTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE, MMBroadbandModemAltairLte))
|
||||
#define MM_BROADBAND_MODEM_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE, MMBroadbandModemAltairLteClass))
|
||||
#define MM_IS_BROADBAND_MODEM_ALTAIR_LTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE))
|
||||
#define MM_IS_BROADBAND_MODEM_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE))
|
||||
#define MM_BROADBAND_MODEM_ALTAIR_LTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_ALTAIR_LTE, MMBroadbandModemAltairLteClass))
|
||||
|
||||
typedef struct _MMBroadbandModemAltairLte MMBroadbandModemAltairLte;
|
||||
typedef struct _MMBroadbandModemAltairLteClass MMBroadbandModemAltairLteClass;
|
||||
typedef struct _MMBroadbandModemAltairLtePrivate MMBroadbandModemAltairLtePrivate;
|
||||
|
||||
struct _MMBroadbandModemAltairLte {
|
||||
MMBroadbandModem parent;
|
||||
MMBroadbandModemAltairLtePrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemAltairLteClass{
|
||||
MMBroadbandModemClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_altair_lte_get_type (void);
|
||||
|
||||
MMBroadbandModemAltairLte *mm_broadband_modem_altair_lte_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
gboolean mm_broadband_modem_altair_lte_is_sim_refresh_detach_in_progress (MMBroadbandModem *self);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_ALTAIR_LTE_H */
|
||||
@@ -0,0 +1,259 @@
|
||||
/* -*- 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 Google Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-modem-helpers-altair-lte.h"
|
||||
|
||||
#define MM_ALTAIR_IMS_PDN_CID 1
|
||||
#define MM_ALTAIR_INTERNET_PDN_CID 3
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Bands response parser */
|
||||
|
||||
GArray *
|
||||
mm_altair_parse_bands_response (const gchar *response)
|
||||
{
|
||||
gchar **split;
|
||||
GArray *bands;
|
||||
guint i;
|
||||
|
||||
/*
|
||||
* Response is "<band>[,<band>...]"
|
||||
*/
|
||||
split = g_strsplit_set (response, ",", -1);
|
||||
if (!split)
|
||||
return NULL;
|
||||
|
||||
bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), g_strv_length (split));
|
||||
|
||||
for (i = 0; split[i]; i++) {
|
||||
guint32 band_value;
|
||||
MMModemBand band;
|
||||
|
||||
band_value = (guint32)strtoul (split[i], NULL, 10);
|
||||
band = MM_MODEM_BAND_EUTRAN_1 - 1 + band_value;
|
||||
|
||||
/* Due to a firmware issue, the modem may incorrectly includes 0 in the
|
||||
* bands response. We thus ignore any band value outside the range of
|
||||
* E-UTRAN operating bands. */
|
||||
if (band >= MM_MODEM_BAND_EUTRAN_1 && band <= MM_MODEM_BAND_EUTRAN_44)
|
||||
g_array_append_val (bands, band);
|
||||
}
|
||||
|
||||
g_strfreev (split);
|
||||
|
||||
return bands;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* +CEER response parser */
|
||||
|
||||
gchar *
|
||||
mm_altair_parse_ceer_response (const gchar *response,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GRegex) r = NULL;
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
gchar *ceer_response = NULL;
|
||||
|
||||
|
||||
/* First accept an empty response as the no error case. Sometimes, the only
|
||||
* response to the AT+CEER query is an OK.
|
||||
*/
|
||||
if (g_strcmp0 ("", response) == 0) {
|
||||
return g_strdup ("");
|
||||
}
|
||||
|
||||
/* The response we are interested in looks so:
|
||||
* +CEER: EPS_AND_NON_EPS_SERVICES_NOT_ALLOWED
|
||||
*/
|
||||
r = g_regex_new ("\\+CEER:\\s*(\\w*)?",
|
||||
G_REGEX_RAW,
|
||||
0, NULL);
|
||||
g_assert (r != NULL);
|
||||
|
||||
if (!g_regex_match (r, response, 0, &match_info)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Could not parse +CEER response");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (g_match_info_matches (match_info)) {
|
||||
ceer_response = mm_get_string_unquoted_from_match_info (match_info, 1);
|
||||
if (!ceer_response)
|
||||
ceer_response = g_strdup ("");
|
||||
}
|
||||
|
||||
return ceer_response;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* %CGINFO="cid",1 response parser */
|
||||
|
||||
gint
|
||||
mm_altair_parse_cid (const gchar *response, GError **error)
|
||||
{
|
||||
g_autoptr(GRegex) regex = NULL;
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
guint cid = -1;
|
||||
|
||||
regex = g_regex_new ("\\%CGINFO:\\s*(\\d+)", G_REGEX_RAW, 0, NULL);
|
||||
g_assert (regex);
|
||||
if (!g_regex_match_full (regex, response, strlen (response), 0, 0, &match_info, error))
|
||||
return -1;
|
||||
|
||||
if (!mm_get_uint_from_match_info (match_info, 1, &cid))
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Failed to parse %%CGINFO=\"cid\",1 response");
|
||||
|
||||
return cid;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* %PCOINFO response parser */
|
||||
|
||||
MMPco *
|
||||
mm_altair_parse_vendor_pco_info (const gchar *pco_info, GError **error)
|
||||
{
|
||||
g_autoptr(GRegex) regex = NULL;
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
MMPco *pco = NULL;
|
||||
gint num_matches;
|
||||
|
||||
if (!pco_info || !pco_info[0]) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
|
||||
"No PCO info given");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Expected %PCOINFO response:
|
||||
*
|
||||
* Solicited response: %PCOINFO:<mode>,<cid>[,<pcoid>[,<payload>]]
|
||||
* Unsolicited response: %PCOINFO:<cid>,<pcoid>[,<payload>]
|
||||
*/
|
||||
regex = g_regex_new ("\\%PCOINFO:(?:\\s*\\d+\\s*,)?(\\d+)\\s*(,([^,\\)]*),([0-9A-Fa-f]*))?",
|
||||
G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
|
||||
0, NULL);
|
||||
g_assert (regex);
|
||||
|
||||
if (!g_regex_match_full (regex, pco_info, strlen (pco_info), 0, 0, &match_info, error))
|
||||
return NULL;
|
||||
|
||||
num_matches = g_match_info_get_match_count (match_info);
|
||||
if (num_matches != 5) {
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Failed to parse substrings, number of matches: %d",
|
||||
num_matches);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (g_match_info_matches (match_info)) {
|
||||
guint pco_cid;
|
||||
g_autofree gchar *pco_id = NULL;
|
||||
g_autofree gchar *pco_payload = NULL;
|
||||
g_autofree guint8 *pco_payload_bytes = NULL;
|
||||
gsize pco_payload_bytes_len;
|
||||
guint8 pco_prefix[6];
|
||||
GByteArray *pco_raw;
|
||||
gsize pco_raw_len;
|
||||
|
||||
if (!mm_get_uint_from_match_info (match_info, 1, &pco_cid)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse CID from PCO info: '%s'", pco_info);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We are only interested in IMS and Internet PDN PCO. */
|
||||
if (pco_cid != MM_ALTAIR_IMS_PDN_CID && pco_cid != MM_ALTAIR_INTERNET_PDN_CID) {
|
||||
g_match_info_next (match_info, error);
|
||||
continue;
|
||||
}
|
||||
|
||||
pco_id = mm_get_string_unquoted_from_match_info (match_info, 3);
|
||||
if (!pco_id) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse PCO ID from PCO info: '%s'", pco_info);
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_strcmp0 (pco_id, "FF00")) {
|
||||
g_match_info_next (match_info, error);
|
||||
continue;
|
||||
}
|
||||
|
||||
pco_payload = mm_get_string_unquoted_from_match_info (match_info, 4);
|
||||
if (!pco_payload) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse PCO payload from PCO info: '%s'", pco_info);
|
||||
break;
|
||||
}
|
||||
|
||||
pco_payload_bytes = mm_utils_hexstr2bin (pco_payload, -1, &pco_payload_bytes_len, error);
|
||||
if (!pco_payload_bytes) {
|
||||
g_prefix_error (error, "Invalid PCO payload from PCO info '%s': ", pco_info);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Protocol Configuration Options (PCO) is an information element with an
|
||||
* identifier (IEI) 0x27 and contains between 3 and 253 octets. See 3GPP TS
|
||||
* 24.008 for more details on PCO.
|
||||
*
|
||||
* NOTE: The standard uses one-based indexing, but to better correlate to the
|
||||
* code, zero-based indexing is used in the description hereinafter.
|
||||
*
|
||||
* Octet | Value
|
||||
* --------+--------------------------------------------
|
||||
* 0 | PCO IEI (= 0x27)
|
||||
* 1 | Length of PCO contents (= total length - 2)
|
||||
* 2 | bit 7 : ext
|
||||
* | bit 6 to 3 : spare (= 0b0000)
|
||||
* | bit 2 to 0 : Configuration protocol
|
||||
* 3 to 4 | Element 1 ID
|
||||
* 5 | Length of element 1 contents
|
||||
* 6 to m | Element 1 contents
|
||||
* ... |
|
||||
*/
|
||||
pco_raw_len = sizeof (pco_prefix) + pco_payload_bytes_len;
|
||||
pco_prefix[0] = 0x27;
|
||||
pco_prefix[1] = pco_raw_len - 2;
|
||||
pco_prefix[2] = 0x80;
|
||||
/* Verizon uses element ID 0xFF00 for carrier-specific PCO content. */
|
||||
pco_prefix[3] = 0xFF;
|
||||
pco_prefix[4] = 0x00;
|
||||
pco_prefix[5] = pco_payload_bytes_len;
|
||||
|
||||
pco_raw = g_byte_array_sized_new (pco_raw_len);
|
||||
g_byte_array_append (pco_raw, pco_prefix, sizeof (pco_prefix));
|
||||
g_byte_array_append (pco_raw, pco_payload_bytes, pco_payload_bytes_len);
|
||||
|
||||
pco = mm_pco_new ();
|
||||
mm_pco_set_session_id (pco, pco_cid);
|
||||
mm_pco_set_complete (pco, TRUE);
|
||||
mm_pco_set_data (pco, pco_raw->data, pco_raw->len);
|
||||
break;
|
||||
}
|
||||
|
||||
return pco;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* -*- 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 Google Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MM_MODEM_HELPERS_ALTAIR_H
|
||||
#define MM_MODEM_HELPERS_ALTAIR_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
/* Bands response parser */
|
||||
GArray *mm_altair_parse_bands_response (const gchar *response);
|
||||
|
||||
/* +CEER response parser */
|
||||
gchar *mm_altair_parse_ceer_response (const gchar *response,
|
||||
GError **error);
|
||||
|
||||
/* %CGINFO="cid",1 response parser */
|
||||
gint mm_altair_parse_cid (const gchar *response, GError **error);
|
||||
|
||||
/* %PCOINFO response parser */
|
||||
MMPco *mm_altair_parse_vendor_pco_info (const gchar *pco_info, GError **error);
|
||||
|
||||
#endif /* MM_MODEM_HELPERS_ALTAIR_H */
|
||||
@@ -0,0 +1,101 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2013 Altair Semiconductor
|
||||
*
|
||||
* Author: Ori Inbar <ori.inbar@altair-semi.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#include "mm-plugin-altair-lte.h"
|
||||
#include "mm-private-boxed-types.h"
|
||||
#include "mm-broadband-modem-altair-lte.h"
|
||||
#include "mm-log.h"
|
||||
|
||||
G_DEFINE_TYPE (MMPluginAltairLte, mm_plugin_altair_lte, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Custom commands for AT probing */
|
||||
|
||||
/* Increase the response timeout for probe commands since some altair modems
|
||||
take longer to respond after a reset.
|
||||
*/
|
||||
static const MMPortProbeAtCommand custom_at_probe[] = {
|
||||
{ "AT", 7, mm_port_probe_response_processor_is_at },
|
||||
{ "AT", 7, mm_port_probe_response_processor_is_at },
|
||||
{ "AT", 7, mm_port_probe_response_processor_is_at },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
return MM_BASE_MODEM (mm_broadband_modem_altair_lte_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", NULL };
|
||||
static const mm_uint16_pair products[] = {
|
||||
{ 0x216f, 0x0047 }, /* Altair NPe */
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_ALTAIR_LTE,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_PRODUCT_IDS, products,
|
||||
MM_PLUGIN_CUSTOM_AT_PROBE, custom_at_probe,
|
||||
MM_PLUGIN_ALLOWED_SINGLE_AT, TRUE,
|
||||
MM_PLUGIN_SEND_LF, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_altair_lte_init (MMPluginAltairLte *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_altair_lte_class_init (MMPluginAltairLteClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) 2013 Altair Semiconductor
|
||||
*
|
||||
* Author: Ori Inbar <ori.inbar@altair-semi.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_ALTAIR_LTE_H
|
||||
#define MM_PLUGIN_ALTAIR_LTE_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_ALTAIR_LTE (mm_plugin_altair_lte_get_type ())
|
||||
#define MM_PLUGIN_ALTAIR_LTE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_ALTAIR_LTE, MMPluginAltairLte))
|
||||
#define MM_PLUGIN_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_ALTAIR_LTE, MMPluginAltairLteClass))
|
||||
#define MM_IS_PLUGIN_ALTAIR_LTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_ALTAIR_LTE))
|
||||
#define MM_IS_PLUGIN_ALTAIR_LTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_ALTAIR_LTE))
|
||||
#define MM_PLUGIN_ALTAIR_LTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_ALTAIR_LTE, MMPluginAltairLteClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginAltairLte;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginAltairLteClass;
|
||||
|
||||
GType mm_plugin_altair_lte_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_ALTAIR_LTE_H */
|
||||
@@ -0,0 +1,189 @@
|
||||
/* -*- 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 Google Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-modem-helpers-altair-lte.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test bands response parsing */
|
||||
|
||||
static void
|
||||
test_parse_bands (void)
|
||||
{
|
||||
GArray *bands;
|
||||
|
||||
bands = mm_altair_parse_bands_response ("");
|
||||
g_assert (bands != NULL);
|
||||
g_assert_cmpuint (bands->len, ==, 0);
|
||||
g_array_free (bands, TRUE);
|
||||
|
||||
/* 0 and 45 are outside the range of E-UTRAN operating bands and should be ignored. */
|
||||
bands = mm_altair_parse_bands_response ("0, 0, 1, 4,13,44,45");
|
||||
g_assert (bands != NULL);
|
||||
g_assert_cmpuint (bands->len, ==, 4);
|
||||
g_assert_cmpuint (g_array_index (bands, MMModemBand, 0), ==, MM_MODEM_BAND_EUTRAN_1);
|
||||
g_assert_cmpuint (g_array_index (bands, MMModemBand, 1), ==, MM_MODEM_BAND_EUTRAN_4);
|
||||
g_assert_cmpuint (g_array_index (bands, MMModemBand, 2), ==, MM_MODEM_BAND_EUTRAN_13);
|
||||
g_assert_cmpuint (g_array_index (bands, MMModemBand, 3), ==, MM_MODEM_BAND_EUTRAN_44);
|
||||
g_array_free (bands, TRUE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test +CEER responses */
|
||||
|
||||
typedef struct {
|
||||
const gchar *str;
|
||||
const gchar *result;
|
||||
} CeerTest;
|
||||
|
||||
static const CeerTest ceer_tests[] = {
|
||||
{ "", "" }, /* Special case, sometimes the response is empty, treat it as a good response. */
|
||||
{ "+CEER:", "" },
|
||||
{ "+CEER: EPS_AND_NON_EPS_SERVICES_NOT_ALLOWED", "EPS_AND_NON_EPS_SERVICES_NOT_ALLOWED" },
|
||||
{ "+CEER: NO_SUITABLE_CELLS_IN_TRACKING_AREA", "NO_SUITABLE_CELLS_IN_TRACKING_AREA" },
|
||||
{ "WRONG RESPONSE", NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
test_ceer (void)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; ceer_tests[i].str; ++i) {
|
||||
GError *error = NULL;
|
||||
gchar *result;
|
||||
|
||||
result = mm_altair_parse_ceer_response (ceer_tests[i].str, &error);
|
||||
if (ceer_tests[i].result) {
|
||||
g_assert_cmpstr (ceer_tests[i].result, ==, result);
|
||||
g_assert_no_error (error);
|
||||
g_free (result);
|
||||
}
|
||||
else {
|
||||
g_assert (result == NULL);
|
||||
g_assert (error != NULL);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_cid (void)
|
||||
{
|
||||
g_assert (mm_altair_parse_cid ("%CGINFO: 2", NULL) == 2);
|
||||
g_assert (mm_altair_parse_cid ("%CGINFO:blah", NULL) == -1);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test %PCOINFO responses */
|
||||
|
||||
typedef struct {
|
||||
const gchar *pco_info;
|
||||
guint32 session_id;
|
||||
gsize pco_data_size;
|
||||
guint8 pco_data[50];
|
||||
} TestValidPcoInfo;
|
||||
|
||||
static const TestValidPcoInfo good_pco_infos[] = {
|
||||
/* Valid PCO values */
|
||||
{ "%PCOINFO: 1,1,FF00,13018400", 1, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x00 } },
|
||||
{ "%PCOINFO: 1,1,FF00,13018403", 1, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x03 } },
|
||||
{ "%PCOINFO: 1,1,FF00,13018405", 1, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x05 } },
|
||||
{ "%PCOINFO: 1,3,FF00,13018400", 3, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x00 } },
|
||||
{ "%PCOINFO: 1,3,FF00,13018403", 3, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x03 } },
|
||||
{ "%PCOINFO: 1,3,FF00,13018405", 3, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x05 } },
|
||||
{ "%PCOINFO:1,FF00,13018400", 1, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x00 } },
|
||||
{ "%PCOINFO:1,FF00,13018403", 1, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x03 } },
|
||||
{ "%PCOINFO:1,FF00,13018405", 1, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x05 } },
|
||||
/* Different payload */
|
||||
{ "%PCOINFO: 1,3,FF00,130185", 3, 9,
|
||||
{ 0x27, 0x07, 0x80, 0xFF, 0x00, 0x03, 0x13, 0x01, 0x85 } },
|
||||
/* Multiline PCO info */
|
||||
{ "%PCOINFO: 1,2,FF00,13018400\r\n%PCOINFO: 1,3,FF00,13018403", 3, 10,
|
||||
{ 0x27, 0x08, 0x80, 0xFF, 0x00, 0x04, 0x13, 0x01, 0x84, 0x03 } },
|
||||
};
|
||||
|
||||
static const gchar *bad_pco_infos[] = {
|
||||
/* Different container */
|
||||
"%PCOINFO: 1,3,F000,13018401",
|
||||
/* Ingood CID */
|
||||
"%PCOINFO: 1,2,FF00,13018401",
|
||||
/* Bad PCO info */
|
||||
"%PCOINFO: blah,blah,FF00,13018401",
|
||||
/* Bad PCO payload */
|
||||
"%PCOINFO: 1,1,FF00,130184011",
|
||||
};
|
||||
|
||||
static void
|
||||
test_parse_vendor_pco_info (void)
|
||||
{
|
||||
MMPco *pco;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (good_pco_infos); ++i) {
|
||||
const guint8 *pco_data;
|
||||
gsize pco_data_size;
|
||||
|
||||
pco = mm_altair_parse_vendor_pco_info (good_pco_infos[i].pco_info, NULL);
|
||||
g_assert (pco != NULL);
|
||||
g_assert_cmpuint (mm_pco_get_session_id (pco), ==, good_pco_infos[i].session_id);
|
||||
g_assert (mm_pco_is_complete (pco));
|
||||
pco_data = mm_pco_get_data (pco, &pco_data_size);
|
||||
g_assert (pco_data != NULL);
|
||||
g_assert_cmpuint (pco_data_size, ==, good_pco_infos[i].pco_data_size);
|
||||
g_assert_cmpint (memcmp (pco_data, good_pco_infos[i].pco_data, pco_data_size), ==, 0);
|
||||
g_object_unref (pco);
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (bad_pco_infos); ++i) {
|
||||
pco = mm_altair_parse_vendor_pco_info (bad_pco_infos[i], NULL);
|
||||
g_assert (pco == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/MM/altair/parse_bands", test_parse_bands);
|
||||
g_test_add_func ("/MM/altair/ceer", test_ceer);
|
||||
g_test_add_func ("/MM/altair/parse_cid", test_parse_cid);
|
||||
g_test_add_func ("/MM/altair/parse_vendor_pco_info", test_parse_vendor_pco_info);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ModemManager.h"
|
||||
#include "mm-serial-parsers.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-errors-types.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-broadband-modem-anydata.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-cdma.h"
|
||||
|
||||
static void iface_modem_init (MMIfaceModem *iface);
|
||||
static void iface_modem_cdma_init (MMIfaceModemCdma *iface);
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemAnydata, mm_broadband_modem_anydata, MM_TYPE_BROADBAND_MODEM, 0,
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init))
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Detailed registration state (CDMA interface) */
|
||||
typedef struct {
|
||||
MMModemCdmaRegistrationState detailed_cdma1x_state;
|
||||
MMModemCdmaRegistrationState detailed_evdo_state;
|
||||
} DetailedRegistrationStateResults;
|
||||
|
||||
static gboolean
|
||||
get_detailed_registration_state_finish (MMIfaceModemCdma *self,
|
||||
GAsyncResult *res,
|
||||
MMModemCdmaRegistrationState *detailed_cdma1x_state,
|
||||
MMModemCdmaRegistrationState *detailed_evdo_state,
|
||||
GError **error)
|
||||
{
|
||||
DetailedRegistrationStateResults *results;
|
||||
|
||||
results = g_task_propagate_pointer (G_TASK (res), error);
|
||||
if (!results)
|
||||
return FALSE;
|
||||
|
||||
*detailed_cdma1x_state = results->detailed_cdma1x_state;
|
||||
*detailed_evdo_state = results->detailed_evdo_state;
|
||||
g_free (results);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
hstate_ready (MMIfaceModemCdma *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
DetailedRegistrationStateResults *results;
|
||||
GError *error = NULL;
|
||||
const gchar *response;
|
||||
g_autoptr(GRegex) r = NULL;
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
|
||||
results = g_task_get_task_data (task);
|
||||
|
||||
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||
if (error) {
|
||||
/* Leave superclass' reg state alone if AT*HSTATE isn't supported */
|
||||
g_error_free (error);
|
||||
|
||||
g_task_return_pointer (task, g_memdup (results, sizeof (*results)), g_free);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
response = mm_strip_tag (response, "*HSTATE:");
|
||||
|
||||
/* Format is "<at state>,<session state>,<channel>,<pn>,<EcIo>,<rssi>,..." */
|
||||
r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([^,\\)]*)\\s*,\\s*([^,\\)]*)\\s*,.*",
|
||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
g_assert (r != NULL);
|
||||
|
||||
g_regex_match (r, response, 0, &match_info);
|
||||
if (g_match_info_get_match_count (match_info) >= 6) {
|
||||
guint val = 0;
|
||||
gint dbm = 0;
|
||||
|
||||
/* dBm is between -106 (worst) and -20.7 (best) */
|
||||
mm_get_int_from_match_info (match_info, 6, &dbm);
|
||||
|
||||
/* Parse the EVDO radio state */
|
||||
if (mm_get_uint_from_match_info (match_info, 1, &val)) {
|
||||
switch (val) {
|
||||
case 3: /* IDLE */
|
||||
/* If IDLE and the EVDO dBm is -105 or lower, assume no service.
|
||||
* It may be that IDLE actually means NO SERVICE too; not sure.
|
||||
*/
|
||||
if (dbm > -105)
|
||||
results->detailed_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
|
||||
break;
|
||||
case 4: /* ACCESS */
|
||||
case 5: /* CONNECT */
|
||||
results->detailed_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
|
||||
break;
|
||||
default:
|
||||
mm_obj_warn (self, "unknown *HSTATE (%d); assuming no service", val);
|
||||
/* fall through */
|
||||
case 0: /* NO SERVICE */
|
||||
case 1: /* ACQUISITION */
|
||||
case 2: /* SYNC */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_task_return_pointer (task, g_memdup (results, sizeof (*results)), g_free);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
state_ready (MMIfaceModemCdma *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
DetailedRegistrationStateResults *results;
|
||||
GError *error = NULL;
|
||||
const gchar *response;
|
||||
g_autoptr(GRegex) r = NULL;
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
|
||||
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||
if (error) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
results = g_task_get_task_data (task);
|
||||
response = mm_strip_tag (response, "*STATE:");
|
||||
|
||||
/* Format is "<channel>,<pn>,<sid>,<nid>,<state>,<rssi>,..." */
|
||||
r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([^,\\)]*)\\s*,.*",
|
||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
g_assert (r != NULL);
|
||||
|
||||
g_regex_match (r, response, 0, &match_info);
|
||||
if (g_match_info_get_match_count (match_info) >= 6) {
|
||||
guint val = 0;
|
||||
gint dbm = 0;
|
||||
|
||||
/* dBm is between -106 (worst) and -20.7 (best) */
|
||||
mm_get_int_from_match_info (match_info, 6, &dbm);
|
||||
|
||||
/* Parse the 1x radio state */
|
||||
if (mm_get_uint_from_match_info (match_info, 5, &val)) {
|
||||
switch (val) {
|
||||
case 1: /* IDLE */
|
||||
/* If IDLE and the 1X dBm is -105 or lower, assume no service.
|
||||
* It may be that IDLE actually means NO SERVICE too; not sure.
|
||||
*/
|
||||
if (dbm > -105)
|
||||
results->detailed_cdma1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
|
||||
break;
|
||||
case 2: /* ACCESS */
|
||||
case 3: /* PAGING */
|
||||
case 4: /* TRAFFIC */
|
||||
results->detailed_cdma1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED;
|
||||
break;
|
||||
default:
|
||||
mm_obj_warn (self, "unknown *HSTATE (%d); assuming no service", val);
|
||||
/* fall through */
|
||||
case 0: /* NO SERVICE */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Try for EVDO state too */
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"*HSTATE?",
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)hstate_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
get_detailed_registration_state (MMIfaceModemCdma *self,
|
||||
MMModemCdmaRegistrationState cdma1x_state,
|
||||
MMModemCdmaRegistrationState evdo_state,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
DetailedRegistrationStateResults *results;
|
||||
GTask *task;
|
||||
|
||||
results = g_new (DetailedRegistrationStateResults, 1);
|
||||
results->detailed_cdma1x_state = cdma1x_state;
|
||||
results->detailed_evdo_state = evdo_state;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, results, g_free);
|
||||
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"*STATE?",
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)state_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Reset (Modem interface) */
|
||||
|
||||
static gboolean
|
||||
reset_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
|
||||
}
|
||||
|
||||
static void
|
||||
reset (MMIfaceModem *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"*RESET",
|
||||
3,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Setup ports (Broadband modem class) */
|
||||
|
||||
static void
|
||||
setup_ports (MMBroadbandModem *self)
|
||||
{
|
||||
MMPortSerialAt *ports[2];
|
||||
g_autoptr(GRegex) active_regex = NULL;
|
||||
g_autoptr(GRegex) inactive_regex = NULL;
|
||||
g_autoptr(GRegex) dormant_regex = NULL;
|
||||
g_autoptr(GRegex) offline_regex = NULL;
|
||||
g_autoptr(GRegex) regreq_regex = NULL;
|
||||
g_autoptr(GRegex) authreq_regex = NULL;
|
||||
guint i;
|
||||
|
||||
/* Call parent's setup ports first always */
|
||||
MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_anydata_parent_class)->setup_ports (self);
|
||||
|
||||
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
||||
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
|
||||
|
||||
/* Data call has connected */
|
||||
active_regex = g_regex_new ("\\r\\n\\*ACTIVE:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
/* Data call disconnected */
|
||||
inactive_regex = g_regex_new ("\\r\\n\\*INACTIVE:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
/* Modem is now dormant */
|
||||
dormant_regex = g_regex_new ("\\r\\n\\*DORMANT:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
/* Network acquisition fail */
|
||||
offline_regex = g_regex_new ("\\r\\n\\*OFFLINE:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
/* Registration fail */
|
||||
regreq_regex = g_regex_new ("\\r\\n\\*REGREQ:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
/* Authentication fail */
|
||||
authreq_regex = g_regex_new ("\\r\\n\\*AUTHREQ:(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
|
||||
/* Now reset the unsolicited messages */
|
||||
for (i = 0; i < G_N_ELEMENTS (ports); i++) {
|
||||
if (!ports[i])
|
||||
continue;
|
||||
|
||||
/* Data state notifications */
|
||||
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), active_regex, NULL, NULL, NULL);
|
||||
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), inactive_regex, NULL, NULL, NULL);
|
||||
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), dormant_regex, NULL, NULL, NULL);
|
||||
|
||||
/* Abnormal state notifications
|
||||
*
|
||||
* FIXME: set 1X/EVDO registration state to UNKNOWN when these
|
||||
* notifications are received?
|
||||
*/
|
||||
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), offline_regex, NULL, NULL, NULL);
|
||||
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), regreq_regex, NULL, NULL, NULL);
|
||||
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), authreq_regex, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBroadbandModemAnydata *
|
||||
mm_broadband_modem_anydata_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_ANYDATA,
|
||||
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,
|
||||
/* Generic bearer supports TTY only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, FALSE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_anydata_init (MMBroadbandModemAnydata *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_init (MMIfaceModem *iface)
|
||||
{
|
||||
iface->reset = reset;
|
||||
iface->reset_finish = reset_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_cdma_init (MMIfaceModemCdma *iface)
|
||||
{
|
||||
iface->get_cdma1x_serving_system = NULL;
|
||||
iface->get_cdma1x_serving_system_finish = NULL;
|
||||
iface->get_detailed_registration_state = get_detailed_registration_state;
|
||||
iface->get_detailed_registration_state_finish = get_detailed_registration_state_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_anydata_class_init (MMBroadbandModemAnydataClass *klass)
|
||||
{
|
||||
MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
|
||||
|
||||
broadband_modem_class->setup_ports = setup_ports;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 - Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_ANYDATA_H
|
||||
#define MM_BROADBAND_MODEM_ANYDATA_H
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_ANYDATA (mm_broadband_modem_anydata_get_type ())
|
||||
#define MM_BROADBAND_MODEM_ANYDATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_ANYDATA, MMBroadbandModemAnydata))
|
||||
#define MM_BROADBAND_MODEM_ANYDATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_ANYDATA, MMBroadbandModemAnydataClass))
|
||||
#define MM_IS_BROADBAND_MODEM_ANYDATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_ANYDATA))
|
||||
#define MM_IS_BROADBAND_MODEM_ANYDATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_ANYDATA))
|
||||
#define MM_BROADBAND_MODEM_ANYDATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_ANYDATA, MMBroadbandModemAnydataClass))
|
||||
|
||||
typedef struct _MMBroadbandModemAnydata MMBroadbandModemAnydata;
|
||||
typedef struct _MMBroadbandModemAnydataClass MMBroadbandModemAnydataClass;
|
||||
|
||||
struct _MMBroadbandModemAnydata {
|
||||
MMBroadbandModem parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemAnydataClass{
|
||||
MMBroadbandModemClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_anydata_get_type (void);
|
||||
|
||||
MMBroadbandModemAnydata *mm_broadband_modem_anydata_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_ANYDATA_H */
|
||||
@@ -0,0 +1,97 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-plugin-anydata.h"
|
||||
#include "mm-broadband-modem-anydata.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
#include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginAnydata, mm_plugin_anydata, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered AnyDATA modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
return MM_BASE_MODEM (mm_broadband_modem_anydata_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x16d5, 0 };
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_ANYDATA,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_REQUIRED_QCDM, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_anydata_init (MMPluginAnydata *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_anydata_class_init (MMPluginAnydataClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_ANYDATA_H
|
||||
#define MM_PLUGIN_ANYDATA_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_ANYDATA (mm_plugin_anydata_get_type ())
|
||||
#define MM_PLUGIN_ANYDATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_ANYDATA, MMPluginAnydata))
|
||||
#define MM_PLUGIN_ANYDATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_ANYDATA, MMPluginAnydataClass))
|
||||
#define MM_IS_PLUGIN_ANYDATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_ANYDATA))
|
||||
#define MM_IS_PLUGIN_ANYDATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_ANYDATA))
|
||||
#define MM_PLUGIN_ANYDATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_ANYDATA, MMPluginAnydataClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginAnydata;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginAnydataClass;
|
||||
|
||||
GType mm_plugin_anydata_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_ANYDATA_H */
|
||||
@@ -0,0 +1,16 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION!="add|change|move|bind", GOTO="mm_broadmobi_port_types_end"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2020", GOTO="mm_broadmobi_port_types"
|
||||
GOTO="mm_broadmobi_port_types_end"
|
||||
|
||||
LABEL="mm_broadmobi_port_types"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
|
||||
|
||||
# BroadMobi BM818
|
||||
ATTRS{idVendor}=="2020", ATTRS{idProduct}=="2060", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
ATTRS{idVendor}=="2020", ATTRS{idProduct}=="2060", ENV{.MM_USBIFNUM}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="2020", ATTRS{idProduct}=="2060", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="2020", ATTRS{idProduct}=="2060", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
|
||||
LABEL="mm_broadmobi_port_types_end"
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2020 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-plugin-broadmobi.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
# include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginBroadmobi, mm_plugin_broadmobi, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered BroadMobi modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x2020, 0 };
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_BROADMOBI,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_REQUIRED_QCDM, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_broadmobi_init (MMPluginBroadmobi *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_broadmobi_class_init (MMPluginBroadmobiClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -*- 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) 2020 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_BROADMOBI_H
|
||||
#define MM_PLUGIN_BROADMOBI_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_BROADMOBI (mm_plugin_broadmobi_get_type ())
|
||||
#define MM_PLUGIN_BROADMOBI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_BROADMOBI, MMPluginBroadmobi))
|
||||
#define MM_PLUGIN_BROADMOBI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_BROADMOBI, MMPluginBroadmobiClass))
|
||||
#define MM_IS_PLUGIN_BROADMOBI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_BROADMOBI))
|
||||
#define MM_IS_PLUGIN_BROADMOBI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_BROADMOBI))
|
||||
#define MM_PLUGIN_BROADMOBI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_BROADMOBI, MMPluginBroadmobiClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginBroadmobi;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginBroadmobiClass;
|
||||
|
||||
GType mm_plugin_broadmobi_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_BROADMOBI_H */
|
||||
@@ -0,0 +1,71 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION!="add|change|move|bind", GOTO="mm_cinterion_port_types_end"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1e2d", GOTO="mm_cinterion_port_types"
|
||||
GOTO="mm_cinterion_port_types_end"
|
||||
|
||||
LABEL="mm_cinterion_port_types"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
|
||||
|
||||
# PHS8
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0053", ENV{.MM_USBIFNUM}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
|
||||
# PLS8 port types
|
||||
# ttyACM0 (if #0): AT port
|
||||
# ttyACM1 (if #2): AT port
|
||||
# ttyACM2 (if #4): GPS data port
|
||||
# ttyACM3 (if #6): unknown
|
||||
# ttyACM4 (if #8): unknown
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="08", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
# PLS62 family non-mbim enumeration uses alternate settings for 2G band management
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{ID_MM_CINTERION_MODEM_FAMILY}="imt"
|
||||
# PLS62 family non-mbim enumeration
|
||||
# ttyACM0 (if #0): AT port
|
||||
# ttyACM1 (if #2): AT port
|
||||
# ttyACM2 (if #4): can be AT or GNSS in some models
|
||||
# ttyACM3 (if #6): AT port (but just ignore)
|
||||
# ttyACM4 (if #8): DIAG/QCDM
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="08", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
|
||||
# PLS62 family mbim enumeration
|
||||
# ttyACM0 (if #0): AT port
|
||||
# ttyACM1 (if #2): AT port
|
||||
# ttyACM2 (if #4): can be AT or GNSS in some models
|
||||
# ttyACM3 (if #6): AT port (but just ignore)
|
||||
# ttyACM4 (if #8): DIAG/QCDM
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="08", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
|
||||
# PLS63
|
||||
# ttyACM0 (if #0): AT port
|
||||
# ttyACM1 (if #2): AT port
|
||||
# ttyACM2 (if #4): GPS data port
|
||||
# ttyACM3 (if #6): DIAG/QCDM
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0069", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0069", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0069", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0069", ENV{.MM_USBIFNUM}=="06", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
|
||||
# PLS83
|
||||
# ttyACM0 (if #0): AT port
|
||||
# ttyACM1 (if #2): AT port
|
||||
# ttyACM2 (if #4): GPS data port
|
||||
# ttyACM3 (if #6): DIAG/QCDM
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="06", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
|
||||
LABEL="mm_cinterion_port_types_end"
|
||||
@@ -0,0 +1,796 @@
|
||||
/* -*- 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) 2016 Trimble Navigation Limited
|
||||
* Author: Matthew Stanger <matthew_stanger@trimble.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>
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-broadband-bearer-cinterion.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-modem-helpers-cinterion.h"
|
||||
#include "mm-daemon-enums-types.h"
|
||||
|
||||
G_DEFINE_TYPE (MMBroadbandBearerCinterion, mm_broadband_bearer_cinterion, MM_TYPE_BROADBAND_BEARER)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* WWAN interface mapping */
|
||||
|
||||
typedef struct {
|
||||
guint swwan_index;
|
||||
guint usb_iface_num;
|
||||
} UsbInterfaceConfig;
|
||||
|
||||
/* Map SWWAN index, USB interface number and preferred PDP context.
|
||||
*
|
||||
* The expected USB interface mapping is:
|
||||
* INTERFACE=usb0 -> ID_USB_INTERFACE_NUM=0a
|
||||
* INTERFACE=usb1 -> ID_USB_INTERFACE_NUM=0c
|
||||
* INTERFACE=usb0 -> ID_USB_INTERFACE_NUM=08 (PLSx3w)
|
||||
*/
|
||||
static const UsbInterfaceConfig usb_interface_configs[] = {
|
||||
{
|
||||
.swwan_index = 1,
|
||||
.usb_iface_num = 0x0a,
|
||||
},
|
||||
{
|
||||
.swwan_index = 2,
|
||||
.usb_iface_num = 0x0c,
|
||||
},
|
||||
{
|
||||
.swwan_index = 1,
|
||||
.usb_iface_num = 0x08,
|
||||
},
|
||||
};
|
||||
|
||||
static gint
|
||||
get_usb_interface_config_index (MMPort *data,
|
||||
GError **error)
|
||||
{
|
||||
guint usb_iface_num;
|
||||
guint i;
|
||||
|
||||
usb_iface_num = (guint) mm_kernel_device_get_interface_number (mm_port_peek_kernel_device (data));
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (usb_interface_configs); i++) {
|
||||
if (usb_interface_configs[i].usb_iface_num == usb_iface_num)
|
||||
return (gint) i;
|
||||
}
|
||||
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Unsupported WWAN interface: unexpected interface number: 0x%02x", usb_iface_num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Connection status loading
|
||||
* NOTE: only CONNECTED or DISCONNECTED should be reported here.
|
||||
*/
|
||||
|
||||
static MMBearerConnectionStatus
|
||||
load_connection_status_finish (MMBaseBearer *bearer,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
GError *inner_error = NULL;
|
||||
gssize aux;
|
||||
|
||||
aux = g_task_propagate_int (G_TASK (res), &inner_error);
|
||||
if (inner_error) {
|
||||
g_propagate_error (error, inner_error);
|
||||
return MM_BEARER_CONNECTION_STATUS_UNKNOWN;
|
||||
}
|
||||
return (MMBearerConnectionStatus) aux;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
guint cid;
|
||||
guint retries;
|
||||
gboolean delay;
|
||||
gboolean retry;
|
||||
} LoadConnectionContext;
|
||||
|
||||
static void
|
||||
load_connection_context_free (LoadConnectionContext *ctx)
|
||||
{
|
||||
g_slice_free (LoadConnectionContext, ctx);
|
||||
}
|
||||
|
||||
static gboolean swwan_check_status (GTask *task);
|
||||
|
||||
static void
|
||||
swwan_check_status_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBroadbandBearerCinterion *self;
|
||||
const gchar *response;
|
||||
GError *error = NULL;
|
||||
MMBearerConnectionStatus status;
|
||||
LoadConnectionContext *ctx;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (!response) {
|
||||
g_task_return_error (task, error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = mm_cinterion_parse_swwan_response (response, ctx->cid, self, &error);
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) {
|
||||
g_task_return_error (task, error);
|
||||
goto out;
|
||||
} else if (ctx->retry && status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED) {
|
||||
mm_obj_dbg (self, "check status retry");
|
||||
if (ctx->retries == 0) {
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"CID %u status check retry exceeded", ctx->cid);
|
||||
goto out;
|
||||
} else {
|
||||
if (ctx->delay) {
|
||||
g_timeout_add_seconds (1, (GSourceFunc)swwan_check_status, task);
|
||||
} else {
|
||||
g_idle_add ((GSourceFunc)swwan_check_status, task);
|
||||
}
|
||||
ctx->retries--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED ||
|
||||
status == MM_BEARER_CONNECTION_STATUS_CONNECTED);
|
||||
g_task_return_int (task, (gssize) status);
|
||||
|
||||
out:
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
swwan_check_status (GTask *task)
|
||||
{
|
||||
MMBroadbandBearerCinterion *bearer;
|
||||
g_autoptr(MMBaseModem) modem = NULL;
|
||||
|
||||
bearer = g_task_get_source_object (task);
|
||||
g_object_get (bearer,
|
||||
MM_BASE_BEARER_MODEM, &modem,
|
||||
NULL);
|
||||
mm_base_modem_at_command (modem,
|
||||
"^SWWAN?",
|
||||
5,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback) swwan_check_status_ready,
|
||||
task);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
load_connection_status_by_cid (MMBroadbandBearerCinterion *bearer,
|
||||
gint cid,
|
||||
gboolean delay,
|
||||
gboolean retry,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
LoadConnectionContext *ctx;
|
||||
|
||||
task = g_task_new (bearer, NULL, callback, user_data);
|
||||
if (cid == MM_3GPP_PROFILE_ID_UNKNOWN) {
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Unknown profile id to check connection status");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_slice_new0 (LoadConnectionContext);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) load_connection_context_free);
|
||||
|
||||
/* Setup context */
|
||||
ctx->cid = cid;
|
||||
ctx->retries = 5;
|
||||
ctx->delay = delay;
|
||||
ctx->retry = retry;
|
||||
|
||||
/* Some modems require a delay before querying the SWWAN status
|
||||
* This is only needed for step DIAL_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION
|
||||
* and DISCONNECT_3GPP_CONTEXT_STEP_CONNECTION_STATUS. */
|
||||
if (delay) {
|
||||
g_timeout_add_seconds (1, (GSourceFunc)swwan_check_status, task);
|
||||
} else {
|
||||
g_idle_add ((GSourceFunc)swwan_check_status, task);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
load_connection_status (MMBaseBearer *bearer,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
load_connection_status_by_cid (MM_BROADBAND_BEARER_CINTERION (bearer),
|
||||
mm_base_bearer_get_profile_id (bearer),
|
||||
FALSE,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Dial 3GPP */
|
||||
|
||||
typedef enum {
|
||||
DIAL_3GPP_CONTEXT_STEP_FIRST = 0,
|
||||
DIAL_3GPP_CONTEXT_STEP_AUTH,
|
||||
DIAL_3GPP_CONTEXT_STEP_START_SWWAN,
|
||||
DIAL_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION,
|
||||
DIAL_3GPP_CONTEXT_STEP_LAST,
|
||||
} Dial3gppContextStep;
|
||||
|
||||
typedef struct {
|
||||
MMBroadbandBearerCinterion *self;
|
||||
MMBaseModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
guint cid;
|
||||
MMPort *data;
|
||||
gint usb_interface_config_index;
|
||||
Dial3gppContextStep step;
|
||||
} Dial3gppContext;
|
||||
|
||||
static void
|
||||
dial_3gpp_context_free (Dial3gppContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->modem);
|
||||
g_object_unref (ctx->self);
|
||||
g_object_unref (ctx->primary);
|
||||
g_clear_object (&ctx->data);
|
||||
g_slice_free (Dial3gppContext, ctx);
|
||||
}
|
||||
|
||||
static MMPort *
|
||||
dial_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return MM_PORT (g_task_propagate_pointer (G_TASK (res), error));
|
||||
}
|
||||
|
||||
static void dial_3gpp_context_step (GTask *task);
|
||||
|
||||
static void
|
||||
dial_connection_status_ready (MMBroadbandBearerCinterion *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBearerConnectionStatus status;
|
||||
Dial3gppContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = (Dial3gppContext *) g_task_get_task_data (task);
|
||||
|
||||
status = load_connection_status_finish (MM_BASE_BEARER (self), res, &error);
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED) {
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"CID %u is reported disconnected", ctx->cid);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (status == MM_BEARER_CONNECTION_STATUS_CONNECTED);
|
||||
|
||||
/* Go to next step */
|
||||
ctx->step++;
|
||||
dial_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
common_dial_operation_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
Dial3gppContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = (Dial3gppContext *) g_task_get_task_data (task);
|
||||
|
||||
if (!mm_base_modem_at_command_full_finish (modem, res, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Go to next step */
|
||||
ctx->step++;
|
||||
dial_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
swwan_dial_operation_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
MMBroadbandBearerCinterion *self) /* full ref! */
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_base_modem_at_command_full_finish (modem, res, &error)) {
|
||||
mm_obj_warn (self, "data connection attempt failed: %s", error->message);
|
||||
mm_base_bearer_report_connection_status (MM_BASE_BEARER (self),
|
||||
MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (self);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_cancel_dial (GTask *task)
|
||||
{
|
||||
Dial3gppContext *ctx;
|
||||
gchar *command;
|
||||
|
||||
ctx = (Dial3gppContext *) g_task_get_task_data (task);
|
||||
|
||||
/* Disconnect, may not succeed. Will not check response on cancel */
|
||||
command = g_strdup_printf ("^SWWAN=0,%u,%u",
|
||||
ctx->cid, usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
command,
|
||||
3,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
g_free (command);
|
||||
}
|
||||
|
||||
static void
|
||||
dial_3gpp_context_step (GTask *task)
|
||||
{
|
||||
MMBroadbandBearerCinterion *self;
|
||||
Dial3gppContext *ctx;
|
||||
MMCinterionModemFamily modem_family;
|
||||
gboolean default_swwan_behavior;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Check for cancellation */
|
||||
if (g_task_return_error_if_cancelled (task)) {
|
||||
handle_cancel_dial (task);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
modem_family = mm_broadband_modem_cinterion_get_family (MM_BROADBAND_MODEM_CINTERION (ctx->modem));
|
||||
default_swwan_behavior = modem_family == MM_CINTERION_MODEM_FAMILY_DEFAULT;
|
||||
|
||||
switch (ctx->step) {
|
||||
case DIAL_3GPP_CONTEXT_STEP_FIRST:
|
||||
ctx->step++;
|
||||
/* fall through */
|
||||
|
||||
case DIAL_3GPP_CONTEXT_STEP_AUTH: {
|
||||
g_autofree gchar *command = NULL;
|
||||
|
||||
command = mm_cinterion_build_auth_string (self,
|
||||
modem_family,
|
||||
mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)),
|
||||
ctx->cid);
|
||||
|
||||
if (command) {
|
||||
mm_obj_dbg (self, "dial step %u/%u: authenticating...", ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST);
|
||||
/* Send SGAUTH write, if User & Pass are provided.
|
||||
* advance to next state by callback */
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
command,
|
||||
10,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) common_dial_operation_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "dial step %u/%u: authentication not required", ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST);
|
||||
ctx->step++;
|
||||
} /* fall through */
|
||||
|
||||
case DIAL_3GPP_CONTEXT_STEP_START_SWWAN: {
|
||||
g_autofree gchar *command = NULL;
|
||||
|
||||
mm_obj_dbg (self, "dial step %u/%u: starting SWWAN interface %u connection...",
|
||||
ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST, usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||
command = g_strdup_printf ("^SWWAN=1,%u,%u",
|
||||
ctx->cid,
|
||||
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||
|
||||
if (default_swwan_behavior) {
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
command,
|
||||
MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) common_dial_operation_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We "jump" to the last step here here since the modem expects the
|
||||
* DHCP discover packet while ^SWWAN runs. If the command fails,
|
||||
* we'll mark the bearer disconnected later in the callback.
|
||||
*/
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
command,
|
||||
MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) swwan_dial_operation_ready,
|
||||
g_object_ref (self));
|
||||
ctx->step = DIAL_3GPP_CONTEXT_STEP_LAST;
|
||||
dial_3gpp_context_step (task);
|
||||
return;
|
||||
}
|
||||
|
||||
case DIAL_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION:
|
||||
g_assert (default_swwan_behavior);
|
||||
mm_obj_dbg (self, "dial step %u/%u: checking SWWAN interface %u status...",
|
||||
ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST, usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||
load_connection_status_by_cid (ctx->self,
|
||||
(gint) ctx->cid,
|
||||
TRUE,
|
||||
TRUE,
|
||||
(GAsyncReadyCallback) dial_connection_status_ready,
|
||||
task);
|
||||
return;
|
||||
|
||||
case DIAL_3GPP_CONTEXT_STEP_LAST:
|
||||
mm_obj_dbg (self, "dial step %u/%u: finished", ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST);
|
||||
g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dial_3gpp (MMBroadbandBearer *self,
|
||||
MMBaseModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
guint cid,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
Dial3gppContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
g_assert (primary != NULL);
|
||||
|
||||
/* Setup task and create connection context */
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
ctx = g_slice_new0 (Dial3gppContext);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) dial_3gpp_context_free);
|
||||
|
||||
/* Setup context */
|
||||
ctx->self = MM_BROADBAND_BEARER_CINTERION (g_object_ref (self));
|
||||
ctx->modem = g_object_ref (modem);
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->cid = cid;
|
||||
ctx->step = DIAL_3GPP_CONTEXT_STEP_FIRST;
|
||||
|
||||
/* Get a net port to setup the connection on */
|
||||
ctx->data = mm_base_modem_peek_best_data_port (MM_BASE_MODEM (modem), MM_PORT_TYPE_NET);
|
||||
if (!ctx->data) {
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
|
||||
"No valid data port found to launch connection");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
g_object_ref (ctx->data);
|
||||
|
||||
/* Validate configuration */
|
||||
ctx->usb_interface_config_index = get_usb_interface_config_index (ctx->data, &error);
|
||||
if (ctx->usb_interface_config_index < 0) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Run! */
|
||||
dial_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Disconnect 3GPP */
|
||||
|
||||
typedef enum {
|
||||
DISCONNECT_3GPP_CONTEXT_STEP_FIRST,
|
||||
DISCONNECT_3GPP_CONTEXT_STEP_STOP_SWWAN,
|
||||
DISCONNECT_3GPP_CONTEXT_STEP_CONNECTION_STATUS,
|
||||
DISCONNECT_3GPP_CONTEXT_STEP_LAST,
|
||||
} Disconnect3gppContextStep;
|
||||
|
||||
typedef struct {
|
||||
MMBroadbandBearerCinterion *self;
|
||||
MMBaseModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
MMPort *data;
|
||||
guint cid;
|
||||
gint usb_interface_config_index;
|
||||
Disconnect3gppContextStep step;
|
||||
} Disconnect3gppContext;
|
||||
|
||||
static void
|
||||
disconnect_3gpp_context_free (Disconnect3gppContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->data);
|
||||
g_object_unref (ctx->primary);
|
||||
g_object_unref (ctx->self);
|
||||
g_object_unref (ctx->modem);
|
||||
g_slice_free (Disconnect3gppContext, ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
disconnect_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void disconnect_3gpp_context_step (GTask *task);
|
||||
|
||||
static void
|
||||
disconnect_connection_status_ready (MMBroadbandBearerCinterion *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBearerConnectionStatus status;
|
||||
Disconnect3gppContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = (Disconnect3gppContext *) g_task_get_task_data (task);
|
||||
|
||||
status = load_connection_status_finish (MM_BASE_BEARER (self), res, &error);
|
||||
switch (status) {
|
||||
case MM_BEARER_CONNECTION_STATUS_UNKNOWN:
|
||||
/* Assume disconnected */
|
||||
mm_obj_dbg (self, "couldn't get CID %u status, assume disconnected: %s", ctx->cid, error->message);
|
||||
g_clear_error (&error);
|
||||
break;
|
||||
case MM_BEARER_CONNECTION_STATUS_DISCONNECTED:
|
||||
break;
|
||||
case MM_BEARER_CONNECTION_STATUS_CONNECTED:
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"CID %u is reported connected", ctx->cid);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
case MM_BEARER_CONNECTION_STATUS_DISCONNECTING:
|
||||
case MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/* Go on to next step */
|
||||
ctx->step++;
|
||||
disconnect_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
swwan_disconnect_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
Disconnect3gppContext *ctx;
|
||||
|
||||
ctx = (Disconnect3gppContext *) g_task_get_task_data (task);
|
||||
|
||||
/* We don't bother to check error or response here since, ctx flow's
|
||||
* next step checks it */
|
||||
mm_base_modem_at_command_full_finish (modem, res, NULL);
|
||||
|
||||
/* Go on to next step */
|
||||
ctx->step++;
|
||||
disconnect_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp_context_step (GTask *task)
|
||||
{
|
||||
MMBroadbandBearerCinterion *self;
|
||||
Disconnect3gppContext *ctx;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
switch (ctx->step) {
|
||||
case DISCONNECT_3GPP_CONTEXT_STEP_FIRST:
|
||||
ctx->step++;
|
||||
/* fall through */
|
||||
|
||||
case DISCONNECT_3GPP_CONTEXT_STEP_STOP_SWWAN: {
|
||||
gchar *command;
|
||||
|
||||
command = g_strdup_printf ("^SWWAN=0,%u,%u",
|
||||
ctx->cid, usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||
mm_obj_dbg (self, "disconnect step %u/%u: disconnecting PDP CID %u...",
|
||||
ctx->step, DISCONNECT_3GPP_CONTEXT_STEP_LAST, ctx->cid);
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
command,
|
||||
MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback) swwan_disconnect_ready,
|
||||
task);
|
||||
g_free (command);
|
||||
return;
|
||||
}
|
||||
|
||||
case DISCONNECT_3GPP_CONTEXT_STEP_CONNECTION_STATUS:
|
||||
mm_obj_dbg (self, "disconnect step %u/%u: checking SWWAN interface %u status...",
|
||||
ctx->step, DISCONNECT_3GPP_CONTEXT_STEP_LAST,
|
||||
usb_interface_configs[ctx->usb_interface_config_index].swwan_index);
|
||||
load_connection_status_by_cid (MM_BROADBAND_BEARER_CINTERION (ctx->self),
|
||||
(gint) ctx->cid,
|
||||
TRUE,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback) disconnect_connection_status_ready,
|
||||
task);
|
||||
return;
|
||||
|
||||
case DISCONNECT_3GPP_CONTEXT_STEP_LAST:
|
||||
mm_obj_dbg (self, "disconnect step %u/%u: finished",
|
||||
ctx->step, DISCONNECT_3GPP_CONTEXT_STEP_LAST);
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
MMPort *data,
|
||||
guint cid,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
Disconnect3gppContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
g_assert (primary != NULL);
|
||||
g_assert (data != NULL);
|
||||
|
||||
/* Setup task and create connection context */
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
ctx = g_slice_new0 (Disconnect3gppContext);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) disconnect_3gpp_context_free);
|
||||
|
||||
/* Setup context */
|
||||
ctx->self = MM_BROADBAND_BEARER_CINTERION (g_object_ref (self));
|
||||
ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->data = g_object_ref (data);
|
||||
ctx->cid = cid;
|
||||
ctx->step = DISCONNECT_3GPP_CONTEXT_STEP_FIRST;
|
||||
|
||||
/* Validate configuration */
|
||||
ctx->usb_interface_config_index = get_usb_interface_config_index (data, &error);
|
||||
if (ctx->usb_interface_config_index < 0) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start */
|
||||
disconnect_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Setup and Init Bearers */
|
||||
|
||||
MMBaseBearer *
|
||||
mm_broadband_bearer_cinterion_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_base_bearer_export (MM_BASE_BEARER (bearer));
|
||||
|
||||
return MM_BASE_BEARER (bearer);
|
||||
}
|
||||
|
||||
void
|
||||
mm_broadband_bearer_cinterion_new (MMBroadbandModemCinterion *modem,
|
||||
MMBearerProperties *config,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
MM_TYPE_BROADBAND_BEARER_CINTERION,
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data,
|
||||
MM_BASE_BEARER_MODEM, modem,
|
||||
MM_BASE_BEARER_CONFIG, config,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_cinterion_init (MMBroadbandBearerCinterion *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_cinterion_class_init (MMBroadbandBearerCinterionClass *klass)
|
||||
{
|
||||
MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass);
|
||||
MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass);
|
||||
|
||||
base_bearer_class->load_connection_status = load_connection_status;
|
||||
base_bearer_class->load_connection_status_finish = load_connection_status_finish;
|
||||
#if defined WITH_SUSPEND_RESUME
|
||||
base_bearer_class->reload_connection_status = load_connection_status;
|
||||
base_bearer_class->reload_connection_status_finish = load_connection_status_finish;
|
||||
#endif
|
||||
|
||||
broadband_bearer_class->dial_3gpp = dial_3gpp;
|
||||
broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish;
|
||||
broadband_bearer_class->disconnect_3gpp = disconnect_3gpp;
|
||||
broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish;
|
||||
}
|
||||
@@ -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) 2016 Trimble Navigation Limited
|
||||
* Author: Matthew Stanger <Matthew_Stanger@trimble.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_BEARER_CINTERION_H
|
||||
#define MM_BROADBAND_BEARER_CINTERION_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "mm-broadband-bearer.h"
|
||||
#include "mm-broadband-modem-cinterion.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_BEARER_CINTERION (mm_broadband_bearer_cinterion_get_type ())
|
||||
#define MM_BROADBAND_BEARER_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_BEARER_CINTERION, MMBroadbandBearerCinterion))
|
||||
#define MM_BROADBAND_BEARER_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_BEARER_CINTERION, MMBroadbandBearerCinterionClass))
|
||||
#define MM_IS_BROADBAND_BEARER_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_BEARER_CINTERION))
|
||||
#define MM_IS_BROADBAND_BEARER_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_BEARER_CINTERION))
|
||||
#define MM_BROADBAND_BEARER_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_BEARER_CINTERION, MMBroadbandBearerCinterionClass))
|
||||
|
||||
typedef struct _MMBroadbandBearerCinterion MMBroadbandBearerCinterion;
|
||||
typedef struct _MMBroadbandBearerCinterionClass MMBroadbandBearerCinterionClass;
|
||||
|
||||
struct _MMBroadbandBearerCinterion {
|
||||
MMBroadbandBearer parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandBearerCinterionClass {
|
||||
MMBroadbandBearerClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_bearer_cinterion_get_type (void);
|
||||
|
||||
void mm_broadband_bearer_cinterion_new (MMBroadbandModemCinterion *modem,
|
||||
MMBearerProperties *config,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
MMBaseBearer *mm_broadband_bearer_cinterion_new_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_BROADBAND_BEARER_CINTERION_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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) 2011 Ammonit Measurement GmbH
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_CINTERION_H
|
||||
#define MM_BROADBAND_MODEM_CINTERION_H
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-modem-helpers-cinterion.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_CINTERION (mm_broadband_modem_cinterion_get_type ())
|
||||
#define MM_BROADBAND_MODEM_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_CINTERION, MMBroadbandModemCinterion))
|
||||
#define MM_BROADBAND_MODEM_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_CINTERION, MMBroadbandModemCinterionClass))
|
||||
#define MM_IS_BROADBAND_MODEM_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_CINTERION))
|
||||
#define MM_IS_BROADBAND_MODEM_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_CINTERION))
|
||||
#define MM_BROADBAND_MODEM_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_CINTERION, MMBroadbandModemCinterionClass))
|
||||
|
||||
typedef struct _MMBroadbandModemCinterion MMBroadbandModemCinterion;
|
||||
typedef struct _MMBroadbandModemCinterionClass MMBroadbandModemCinterionClass;
|
||||
typedef struct _MMBroadbandModemCinterionPrivate MMBroadbandModemCinterionPrivate;
|
||||
|
||||
struct _MMBroadbandModemCinterion {
|
||||
MMBroadbandModem parent;
|
||||
MMBroadbandModemCinterionPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemCinterionClass{
|
||||
MMBroadbandModemClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_cinterion_get_type (void);
|
||||
|
||||
MMBroadbandModemCinterion *mm_broadband_modem_cinterion_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
MMCinterionModemFamily mm_broadband_modem_cinterion_get_family (MMBroadbandModemCinterion * modem);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_CINTERION_H */
|
||||
@@ -0,0 +1,167 @@
|
||||
/* -*- 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) 2021 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ModemManager.h"
|
||||
#include "mm-log.h"
|
||||
#include "mm-errors-types.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-location.h"
|
||||
#include "mm-iface-modem-voice.h"
|
||||
#include "mm-broadband-modem-mbim-cinterion.h"
|
||||
#include "mm-shared-cinterion.h"
|
||||
|
||||
static void iface_modem_init (MMIfaceModem *iface);
|
||||
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
||||
static void iface_modem_voice_init (MMIfaceModemVoice *iface);
|
||||
static void iface_modem_time_init (MMIfaceModemTime *iface);
|
||||
static void shared_cinterion_init (MMSharedCinterion *iface);
|
||||
|
||||
static MMIfaceModem *iface_modem_parent;
|
||||
static MMIfaceModemLocation *iface_modem_location_parent;
|
||||
static MMIfaceModemVoice *iface_modem_voice_parent;
|
||||
static MMIfaceModemTime *iface_modem_time_parent;
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimCinterion, mm_broadband_modem_mbim_cinterion, MM_TYPE_BROADBAND_MODEM_MBIM, 0,
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBroadbandModemMbimCinterion *
|
||||
mm_broadband_modem_mbim_cinterion_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION,
|
||||
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,
|
||||
/* MBIM bearer supports NET only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
|
||||
MM_BROADBAND_MODEM_MBIM_INTEL_FIRMWARE_UPDATE_UNSUPPORTED, TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_cinterion_init (MMBroadbandModemMbimCinterion *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_init (MMIfaceModem *iface)
|
||||
{
|
||||
iface_modem_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->reset = mm_shared_cinterion_modem_reset;
|
||||
iface->reset_finish = mm_shared_cinterion_modem_reset_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModem *
|
||||
peek_parent_interface (MMSharedCinterion *self)
|
||||
{
|
||||
return iface_modem_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_location_init (MMIfaceModemLocation *iface)
|
||||
{
|
||||
iface_modem_location_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->load_capabilities = mm_shared_cinterion_location_load_capabilities;
|
||||
iface->load_capabilities_finish = mm_shared_cinterion_location_load_capabilities_finish;
|
||||
iface->enable_location_gathering = mm_shared_cinterion_enable_location_gathering;
|
||||
iface->enable_location_gathering_finish = mm_shared_cinterion_enable_location_gathering_finish;
|
||||
iface->disable_location_gathering = mm_shared_cinterion_disable_location_gathering;
|
||||
iface->disable_location_gathering_finish = mm_shared_cinterion_disable_location_gathering_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModemLocation *
|
||||
peek_parent_location_interface (MMSharedCinterion *self)
|
||||
{
|
||||
return iface_modem_location_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_voice_init (MMIfaceModemVoice *iface)
|
||||
{
|
||||
iface_modem_voice_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->create_call = mm_shared_cinterion_create_call;
|
||||
|
||||
iface->check_support = mm_shared_cinterion_voice_check_support;
|
||||
iface->check_support_finish = mm_shared_cinterion_voice_check_support_finish;
|
||||
iface->enable_unsolicited_events = mm_shared_cinterion_voice_enable_unsolicited_events;
|
||||
iface->enable_unsolicited_events_finish = mm_shared_cinterion_voice_enable_unsolicited_events_finish;
|
||||
iface->disable_unsolicited_events = mm_shared_cinterion_voice_disable_unsolicited_events;
|
||||
iface->disable_unsolicited_events_finish = mm_shared_cinterion_voice_disable_unsolicited_events_finish;
|
||||
iface->setup_unsolicited_events = mm_shared_cinterion_voice_setup_unsolicited_events;
|
||||
iface->setup_unsolicited_events_finish = mm_shared_cinterion_voice_setup_unsolicited_events_finish;
|
||||
iface->cleanup_unsolicited_events = mm_shared_cinterion_voice_cleanup_unsolicited_events;
|
||||
iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_voice_cleanup_unsolicited_events_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModemVoice *
|
||||
peek_parent_voice_interface (MMSharedCinterion *self)
|
||||
{
|
||||
return iface_modem_voice_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_time_init (MMIfaceModemTime *iface)
|
||||
{
|
||||
iface_modem_time_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->setup_unsolicited_events = mm_shared_cinterion_time_setup_unsolicited_events;
|
||||
iface->setup_unsolicited_events_finish = mm_shared_cinterion_time_setup_unsolicited_events_finish;
|
||||
iface->cleanup_unsolicited_events = mm_shared_cinterion_time_cleanup_unsolicited_events;
|
||||
iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_time_cleanup_unsolicited_events_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModemTime *
|
||||
peek_parent_time_interface (MMSharedCinterion *self)
|
||||
{
|
||||
return iface_modem_time_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
shared_cinterion_init (MMSharedCinterion *iface)
|
||||
{
|
||||
iface->peek_parent_interface = peek_parent_interface;
|
||||
iface->peek_parent_location_interface = peek_parent_location_interface;
|
||||
iface->peek_parent_voice_interface = peek_parent_voice_interface;
|
||||
iface->peek_parent_time_interface = peek_parent_time_interface;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_cinterion_class_init (MMBroadbandModemMbimCinterionClass *klass)
|
||||
{
|
||||
}
|
||||
@@ -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:
|
||||
*
|
||||
* Copyright (C) 2021 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_MBIM_CINTERION_MBIM_H
|
||||
#define MM_BROADBAND_MODEM_MBIM_CINTERION_MBIM_H
|
||||
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION (mm_broadband_modem_mbim_cinterion_get_type ())
|
||||
#define MM_BROADBAND_MODEM_MBIM_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION, MMBroadbandModemMbimCinterion))
|
||||
#define MM_BROADBAND_MODEM_MBIM_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION, MMBroadbandModemMbimCinterionClass))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION))
|
||||
#define MM_BROADBAND_MODEM_MBIM_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION, MMBroadbandModemMbimCinterionClass))
|
||||
|
||||
typedef struct _MMBroadbandModemMbimCinterion MMBroadbandModemMbimCinterion;
|
||||
typedef struct _MMBroadbandModemMbimCinterionClass MMBroadbandModemMbimCinterionClass;
|
||||
|
||||
struct _MMBroadbandModemMbimCinterion {
|
||||
MMBroadbandModemMbim parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemMbimCinterionClass{
|
||||
MMBroadbandModemMbimClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_mbim_cinterion_get_type (void);
|
||||
|
||||
MMBroadbandModemMbimCinterion *mm_broadband_modem_mbim_cinterion_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_MBIM_CINTERION_H */
|
||||
@@ -0,0 +1,167 @@
|
||||
/* -*- 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) 2014 Ammonit Measurement GmbH
|
||||
* Author: Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ModemManager.h"
|
||||
#include "mm-log.h"
|
||||
#include "mm-errors-types.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-location.h"
|
||||
#include "mm-iface-modem-voice.h"
|
||||
#include "mm-broadband-modem-qmi-cinterion.h"
|
||||
#include "mm-shared-cinterion.h"
|
||||
|
||||
static void iface_modem_init (MMIfaceModem *iface);
|
||||
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
||||
static void iface_modem_voice_init (MMIfaceModemVoice *iface);
|
||||
static void iface_modem_time_init (MMIfaceModemTime *iface);
|
||||
static void shared_cinterion_init (MMSharedCinterion *iface);
|
||||
|
||||
static MMIfaceModem *iface_modem_parent;
|
||||
static MMIfaceModemLocation *iface_modem_location_parent;
|
||||
static MMIfaceModemVoice *iface_modem_voice_parent;
|
||||
static MMIfaceModemTime *iface_modem_time_parent;
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmiCinterion, mm_broadband_modem_qmi_cinterion, MM_TYPE_BROADBAND_MODEM_QMI, 0,
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBroadbandModemQmiCinterion *
|
||||
mm_broadband_modem_qmi_cinterion_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_QMI_CINTERION,
|
||||
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,
|
||||
/* QMI bearer supports NET only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_qmi_cinterion_init (MMBroadbandModemQmiCinterion *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_init (MMIfaceModem *iface)
|
||||
{
|
||||
iface_modem_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->reset = mm_shared_cinterion_modem_reset;
|
||||
iface->reset_finish = mm_shared_cinterion_modem_reset_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModem *
|
||||
peek_parent_interface (MMSharedCinterion *self)
|
||||
{
|
||||
return iface_modem_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_location_init (MMIfaceModemLocation *iface)
|
||||
{
|
||||
iface_modem_location_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->load_capabilities = mm_shared_cinterion_location_load_capabilities;
|
||||
iface->load_capabilities_finish = mm_shared_cinterion_location_load_capabilities_finish;
|
||||
iface->enable_location_gathering = mm_shared_cinterion_enable_location_gathering;
|
||||
iface->enable_location_gathering_finish = mm_shared_cinterion_enable_location_gathering_finish;
|
||||
iface->disable_location_gathering = mm_shared_cinterion_disable_location_gathering;
|
||||
iface->disable_location_gathering_finish = mm_shared_cinterion_disable_location_gathering_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModemLocation *
|
||||
peek_parent_location_interface (MMSharedCinterion *self)
|
||||
{
|
||||
return iface_modem_location_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_voice_init (MMIfaceModemVoice *iface)
|
||||
{
|
||||
iface_modem_voice_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->create_call = mm_shared_cinterion_create_call;
|
||||
|
||||
iface->check_support = mm_shared_cinterion_voice_check_support;
|
||||
iface->check_support_finish = mm_shared_cinterion_voice_check_support_finish;
|
||||
iface->enable_unsolicited_events = mm_shared_cinterion_voice_enable_unsolicited_events;
|
||||
iface->enable_unsolicited_events_finish = mm_shared_cinterion_voice_enable_unsolicited_events_finish;
|
||||
iface->disable_unsolicited_events = mm_shared_cinterion_voice_disable_unsolicited_events;
|
||||
iface->disable_unsolicited_events_finish = mm_shared_cinterion_voice_disable_unsolicited_events_finish;
|
||||
iface->setup_unsolicited_events = mm_shared_cinterion_voice_setup_unsolicited_events;
|
||||
iface->setup_unsolicited_events_finish = mm_shared_cinterion_voice_setup_unsolicited_events_finish;
|
||||
iface->cleanup_unsolicited_events = mm_shared_cinterion_voice_cleanup_unsolicited_events;
|
||||
iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_voice_cleanup_unsolicited_events_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModemVoice *
|
||||
peek_parent_voice_interface (MMSharedCinterion *self)
|
||||
{
|
||||
return iface_modem_voice_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_time_init (MMIfaceModemTime *iface)
|
||||
{
|
||||
iface_modem_time_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->setup_unsolicited_events = mm_shared_cinterion_time_setup_unsolicited_events;
|
||||
iface->setup_unsolicited_events_finish = mm_shared_cinterion_time_setup_unsolicited_events_finish;
|
||||
iface->cleanup_unsolicited_events = mm_shared_cinterion_time_cleanup_unsolicited_events;
|
||||
iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_time_cleanup_unsolicited_events_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModemTime *
|
||||
peek_parent_time_interface (MMSharedCinterion *self)
|
||||
{
|
||||
return iface_modem_time_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
shared_cinterion_init (MMSharedCinterion *iface)
|
||||
{
|
||||
iface->peek_parent_interface = peek_parent_interface;
|
||||
iface->peek_parent_location_interface = peek_parent_location_interface;
|
||||
iface->peek_parent_voice_interface = peek_parent_voice_interface;
|
||||
iface->peek_parent_time_interface = peek_parent_time_interface;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_qmi_cinterion_class_init (MMBroadbandModemQmiCinterionClass *klass)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2014 Ammonit Measurement GmbH
|
||||
* Author: Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_QMI_CINTERION_QMI_H
|
||||
#define MM_BROADBAND_MODEM_QMI_CINTERION_QMI_H
|
||||
|
||||
#include "mm-broadband-modem-qmi.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_QMI_CINTERION (mm_broadband_modem_qmi_cinterion_get_type ())
|
||||
#define MM_BROADBAND_MODEM_QMI_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION, MMBroadbandModemQmiCinterion))
|
||||
#define MM_BROADBAND_MODEM_QMI_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION, MMBroadbandModemQmiCinterionClass))
|
||||
#define MM_IS_BROADBAND_MODEM_QMI_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION))
|
||||
#define MM_IS_BROADBAND_MODEM_QMI_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION))
|
||||
#define MM_BROADBAND_MODEM_QMI_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION, MMBroadbandModemQmiCinterionClass))
|
||||
|
||||
typedef struct _MMBroadbandModemQmiCinterion MMBroadbandModemQmiCinterion;
|
||||
typedef struct _MMBroadbandModemQmiCinterionClass MMBroadbandModemQmiCinterionClass;
|
||||
|
||||
struct _MMBroadbandModemQmiCinterion {
|
||||
MMBroadbandModemQmi parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemQmiCinterionClass{
|
||||
MMBroadbandModemQmiClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_qmi_cinterion_get_type (void);
|
||||
|
||||
MMBroadbandModemQmiCinterion *mm_broadband_modem_qmi_cinterion_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_QMI_CINTERION_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,211 @@
|
||||
/* -*- 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) 2014 Aleksander Morgado <aleksander@aleksander.es>
|
||||
* Copyright (C) 2016 Trimble Navigation Limited
|
||||
* Copyright (C) 2016 Matthew Stanger <matthew_stanger@trimble.com>
|
||||
* Copyright (C) 2019 Purism SPC
|
||||
*/
|
||||
|
||||
#ifndef MM_MODEM_HELPERS_CINTERION_H
|
||||
#define MM_MODEM_HELPERS_CINTERION_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#include <mm-base-bearer.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
typedef enum {
|
||||
MM_CINTERION_MODEM_FAMILY_DEFAULT = 0,
|
||||
MM_CINTERION_MODEM_FAMILY_IMT = 1,
|
||||
} MMCinterionModemFamily;
|
||||
|
||||
typedef enum {
|
||||
MM_CINTERION_RADIO_BAND_FORMAT_SINGLE = 0,
|
||||
MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE = 1,
|
||||
} MMCinterionRadioBandFormat;
|
||||
|
||||
typedef enum {
|
||||
MM_CINTERION_RB_BLOCK_LEGACY = 0,
|
||||
MM_CINTERION_RB_BLOCK_GSM = 0,
|
||||
MM_CINTERION_RB_BLOCK_UMTS = 1,
|
||||
MM_CINTERION_RB_BLOCK_LTE_LOW = 2,
|
||||
MM_CINTERION_RB_BLOCK_LTE_HIGH = 3,
|
||||
MM_CINTERION_RB_BLOCK_N = 4
|
||||
} MMCinterionRbBlock;
|
||||
|
||||
typedef enum {
|
||||
MM_CINTERION_RADIO_GEN_NONE = 0,
|
||||
MM_CINTERION_RADIO_GEN_2G = 2,
|
||||
MM_CINTERION_RADIO_GEN_3G = 3,
|
||||
MM_CINTERION_RADIO_GEN_4G = 4,
|
||||
} MMCinterionRadioGen;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SCFG test parser */
|
||||
|
||||
gboolean mm_cinterion_parse_scfg_test (const gchar *response,
|
||||
MMCinterionModemFamily modem_family,
|
||||
MMModemCharset charset,
|
||||
GArray **supported_bands,
|
||||
MMCinterionRadioBandFormat *format,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SCFG response parser */
|
||||
|
||||
gboolean mm_cinterion_parse_scfg_response (const gchar *response,
|
||||
MMCinterionModemFamily modem_family,
|
||||
MMModemCharset charset,
|
||||
GArray **bands,
|
||||
MMCinterionRadioBandFormat format,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* +CNMI test parser */
|
||||
|
||||
gboolean mm_cinterion_parse_cnmi_test (const gchar *response,
|
||||
GArray **supported_mode,
|
||||
GArray **supported_mt,
|
||||
GArray **supported_bm,
|
||||
GArray **supported_ds,
|
||||
GArray **supported_bfr,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SXRAT test parser */
|
||||
|
||||
gboolean mm_cinterion_parse_sxrat_test (const gchar *response,
|
||||
GArray **supported_rat,
|
||||
GArray **supported_pref1,
|
||||
GArray **supported_pref2,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Build Cinterion-specific band value */
|
||||
|
||||
gboolean mm_cinterion_build_band (GArray *bands,
|
||||
guint *supported,
|
||||
gboolean only_2g,
|
||||
MMCinterionRadioBandFormat format,
|
||||
MMCinterionModemFamily modem_family,
|
||||
guint *out_band,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Single ^SIND response parser */
|
||||
|
||||
gboolean mm_cinterion_parse_sind_response (const gchar *response,
|
||||
gchar **description,
|
||||
guint *mode,
|
||||
guint *value,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SWWAN response parser */
|
||||
|
||||
MMBearerConnectionStatus mm_cinterion_parse_swwan_response (const gchar *response,
|
||||
guint swwan_index,
|
||||
gpointer log_object,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SGAUTH response parser */
|
||||
|
||||
gboolean mm_cinterion_parse_sgauth_response (const gchar *response,
|
||||
guint cid,
|
||||
MMBearerAllowedAuth *out_auth,
|
||||
gchar **out_username,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SMONG response parser */
|
||||
|
||||
gboolean mm_cinterion_parse_smong_response (const gchar *response,
|
||||
MMModemAccessTechnology *access_tech,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SIND psinfo helper */
|
||||
|
||||
MMModemAccessTechnology mm_cinterion_get_access_technology_from_sind_psinfo (guint val,
|
||||
gpointer log_object);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SLCC URC helpers */
|
||||
|
||||
GRegex *mm_cinterion_get_slcc_regex (void);
|
||||
|
||||
/* MMCallInfo list management */
|
||||
gboolean mm_cinterion_parse_slcc_list (const gchar *str,
|
||||
gpointer log_object,
|
||||
GList **out_list,
|
||||
GError **error);
|
||||
void mm_cinterion_call_info_list_free (GList *call_info_list);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* +CTZU URC helpers */
|
||||
|
||||
GRegex *mm_cinterion_get_ctzu_regex (void);
|
||||
gboolean mm_cinterion_parse_ctzu_urc (GMatchInfo *match_info,
|
||||
gchar **iso8601p,
|
||||
MMNetworkTimezone **tzp,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SMONI helper */
|
||||
|
||||
gboolean mm_cinterion_parse_smoni_query_response (const gchar *response,
|
||||
MMCinterionRadioGen *out_tech,
|
||||
gdouble *out_rssi,
|
||||
gdouble *out_ecn0,
|
||||
gdouble *out_rscp,
|
||||
gdouble *out_rsrp,
|
||||
gdouble *out_rsrq,
|
||||
GError **error);
|
||||
|
||||
gboolean mm_cinterion_smoni_response_to_signal_info (const gchar *response,
|
||||
MMSignal **out_gsm,
|
||||
MMSignal **out_umts,
|
||||
MMSignal **out_lte,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SCFG="MEopMode/Prov/Cfg" helper */
|
||||
|
||||
gboolean mm_cinterion_provcfg_response_to_cid (const gchar *response,
|
||||
MMCinterionModemFamily modem_family,
|
||||
MMModemCharset charset,
|
||||
gpointer log_object,
|
||||
gint *cid,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Auth related helpers */
|
||||
|
||||
MMBearerAllowedAuth mm_auth_type_from_cinterion_auth_type (guint cinterion_auth);
|
||||
|
||||
gchar *mm_cinterion_build_auth_string (gpointer log_object,
|
||||
MMCinterionModemFamily modem_family,
|
||||
MMBearerProperties *config,
|
||||
guint cid);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SXRAT set command helper */
|
||||
|
||||
gchar *mm_cinterion_build_sxrat_set_command (MMModemMode allowed,
|
||||
MMModemMode preferred,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_MODEM_HELPERS_CINTERION_H */
|
||||
@@ -0,0 +1,218 @@
|
||||
/* -*- 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) 2011 Ammonit Measurement GmbH
|
||||
* Copyright (C) 2011 - 2012 Google Inc.
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-plugin-cinterion.h"
|
||||
#include "mm-broadband-modem-cinterion.h"
|
||||
#include "mm-log-object.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
#include "mm-broadband-modem-qmi-cinterion.h"
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
#include "mm-broadband-modem-mbim-cinterion.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginCinterion, mm_plugin_cinterion, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Custom init */
|
||||
|
||||
#define TAG_CINTERION_APP_PORT "cinterion-app-port"
|
||||
#define TAG_CINTERION_MODEM_PORT "cinterion-modem-port"
|
||||
|
||||
static gboolean
|
||||
cinterion_custom_init_finish (MMPortProbe *probe,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sqport_ready (MMPortSerialAt *port,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMPortProbe *probe;
|
||||
const gchar *response;
|
||||
|
||||
probe = g_task_get_source_object (task);
|
||||
|
||||
/* Ignore errors, just avoid tagging */
|
||||
response = mm_port_serial_at_command_finish (port, res, NULL);
|
||||
if (response) {
|
||||
/* A valid reply to AT^SQPORT tells us this is an AT port already */
|
||||
mm_port_probe_set_result_at (probe, TRUE);
|
||||
|
||||
if (strstr (response, "Application"))
|
||||
g_object_set_data (G_OBJECT (probe), TAG_CINTERION_APP_PORT, GUINT_TO_POINTER (TRUE));
|
||||
else if (strstr (response, "Modem"))
|
||||
g_object_set_data (G_OBJECT (probe), TAG_CINTERION_MODEM_PORT, GUINT_TO_POINTER (TRUE));
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
cinterion_custom_init (MMPortProbe *probe,
|
||||
MMPortSerialAt *port,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (probe, cancellable, callback, user_data);
|
||||
|
||||
mm_port_serial_at_command (
|
||||
port,
|
||||
"AT^SQPORT?",
|
||||
3,
|
||||
FALSE, /* raw */
|
||||
FALSE, /* allow cached */
|
||||
cancellable,
|
||||
(GAsyncReadyCallback) sqport_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered Cinterion modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_cinterion_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
if (mm_port_probe_list_has_mbim_port (probes)) {
|
||||
mm_obj_dbg (self, "MBIM-powered Cinterion modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_cinterion_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
return MM_BASE_MODEM (mm_broadband_modem_cinterion_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
grab_port (MMPlugin *self,
|
||||
MMBaseModem *modem,
|
||||
MMPortProbe *probe,
|
||||
GError **error)
|
||||
{
|
||||
MMPortSerialAtFlag pflags = MM_PORT_SERIAL_AT_FLAG_NONE;
|
||||
MMPortType ptype;
|
||||
|
||||
ptype = mm_port_probe_get_port_type (probe);
|
||||
|
||||
if (g_object_get_data (G_OBJECT (probe), TAG_CINTERION_APP_PORT)) {
|
||||
mm_obj_dbg (self, "port '%s/%s' flagged as primary",
|
||||
mm_port_probe_get_port_subsys (probe),
|
||||
mm_port_probe_get_port_name (probe));
|
||||
pflags = MM_PORT_SERIAL_AT_FLAG_PRIMARY;
|
||||
} else if (g_object_get_data (G_OBJECT (probe), TAG_CINTERION_MODEM_PORT)) {
|
||||
mm_obj_dbg (self, "port '%s/%s' flagged as PPP",
|
||||
mm_port_probe_get_port_subsys (probe),
|
||||
mm_port_probe_get_port_name (probe));
|
||||
pflags = MM_PORT_SERIAL_AT_FLAG_PPP;
|
||||
}
|
||||
|
||||
return mm_base_modem_grab_port (modem,
|
||||
mm_port_probe_peek_port (probe),
|
||||
ptype,
|
||||
pflags,
|
||||
error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", "wwan", NULL };
|
||||
static const gchar *vendor_strings[] = { "cinterion", "siemens", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x1e2d, 0x0681, 0x1269, 0 };
|
||||
static const MMAsyncMethod custom_init = {
|
||||
.async = G_CALLBACK (cinterion_custom_init),
|
||||
.finish = G_CALLBACK (cinterion_custom_init_finish),
|
||||
};
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_CINTERION,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_STRINGS, vendor_strings,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
MM_PLUGIN_ALLOWED_MBIM, TRUE,
|
||||
MM_PLUGIN_CUSTOM_INIT, &custom_init,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_cinterion_init (MMPluginCinterion *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_cinterion_class_init (MMPluginCinterionClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
plugin_class->grab_port = grab_port;
|
||||
}
|
||||
@@ -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) 2011 Ammonit Measurement GmbH
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_CINTERION_H
|
||||
#define MM_PLUGIN_CINTERION_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_CINTERION (mm_plugin_cinterion_get_type ())
|
||||
#define MM_PLUGIN_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_CINTERION, MMPluginCinterion))
|
||||
#define MM_PLUGIN_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_CINTERION, MMPluginCinterionClass))
|
||||
#define MM_IS_PLUGIN_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_CINTERION))
|
||||
#define MM_IS_PLUGIN_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_CINTERION))
|
||||
#define MM_PLUGIN_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_CINTERION, MMPluginCinterionClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginCinterion;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginCinterionClass;
|
||||
|
||||
GType mm_plugin_cinterion_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_CINTERION_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,153 @@
|
||||
/* -*- 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) 2014 Ammonit Measurement GmbH
|
||||
* Copyright (C) 2014 - 2018 Aleksander Morgado <aleksander@aleksander.es>
|
||||
* Copyright (C) 2019 Purism SPC
|
||||
*/
|
||||
|
||||
#ifndef MM_SHARED_CINTERION_H
|
||||
#define MM_SHARED_CINTERION_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-location.h"
|
||||
#include "mm-iface-modem-voice.h"
|
||||
#include "mm-iface-modem-time.h"
|
||||
|
||||
#define MM_TYPE_SHARED_CINTERION (mm_shared_cinterion_get_type ())
|
||||
#define MM_SHARED_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SHARED_CINTERION, MMSharedCinterion))
|
||||
#define MM_IS_SHARED_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SHARED_CINTERION))
|
||||
#define MM_SHARED_CINTERION_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_SHARED_CINTERION, MMSharedCinterion))
|
||||
|
||||
typedef struct _MMSharedCinterion MMSharedCinterion;
|
||||
|
||||
struct _MMSharedCinterion {
|
||||
GTypeInterface g_iface;
|
||||
|
||||
/* Peek modem interface of the parent class of the object */
|
||||
MMIfaceModem * (* peek_parent_interface) (MMSharedCinterion *self);
|
||||
|
||||
/* Peek location interface of the parent class of the object */
|
||||
MMIfaceModemLocation * (* peek_parent_location_interface) (MMSharedCinterion *self);
|
||||
|
||||
/* Peek voice interface of the parent class of the object */
|
||||
MMIfaceModemVoice * (* peek_parent_voice_interface) (MMSharedCinterion *self);
|
||||
|
||||
/* Peek time interface of the parent class of the object */
|
||||
MMIfaceModemTime * (* peek_parent_time_interface) (MMSharedCinterion *self);
|
||||
};
|
||||
|
||||
GType mm_shared_cinterion_get_type (void);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Modem interface */
|
||||
|
||||
void mm_shared_cinterion_modem_reset (MMIfaceModem *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_modem_reset_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Location interface */
|
||||
|
||||
void mm_shared_cinterion_location_load_capabilities (MMIfaceModemLocation *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
MMModemLocationSource mm_shared_cinterion_location_load_capabilities_finish (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void mm_shared_cinterion_enable_location_gathering (MMIfaceModemLocation *self,
|
||||
MMModemLocationSource source,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_enable_location_gathering_finish (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void mm_shared_cinterion_disable_location_gathering (MMIfaceModemLocation *self,
|
||||
MMModemLocationSource source,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_disable_location_gathering_finish (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Voice interface */
|
||||
|
||||
MMBaseCall *mm_shared_cinterion_create_call (MMIfaceModemVoice *self,
|
||||
MMCallDirection direction,
|
||||
const gchar *number);
|
||||
|
||||
void mm_shared_cinterion_voice_check_support (MMIfaceModemVoice *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_voice_check_support_finish (MMIfaceModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void mm_shared_cinterion_voice_setup_unsolicited_events (MMIfaceModemVoice *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_voice_setup_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void mm_shared_cinterion_voice_cleanup_unsolicited_events (MMIfaceModemVoice *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_voice_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void mm_shared_cinterion_voice_enable_unsolicited_events (MMIfaceModemVoice *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_voice_enable_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void mm_shared_cinterion_voice_disable_unsolicited_events (MMIfaceModemVoice *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_voice_disable_unsolicited_events_finish (MMIfaceModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Time interface */
|
||||
|
||||
void mm_shared_cinterion_time_setup_unsolicited_events (MMIfaceModemTime *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_time_setup_unsolicited_events_finish (MMIfaceModemTime *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void mm_shared_cinterion_time_cleanup_unsolicited_events (MMIfaceModemTime *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_cinterion_time_cleanup_unsolicited_events_finish (MMIfaceModemTime *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_SHARED_CINTERION_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION!="add|change|move|bind", GOTO="mm_dell_port_types_end"
|
||||
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="413c", GOTO="mm_dell_vendorcheck"
|
||||
GOTO="mm_dell_port_types_end"
|
||||
|
||||
LABEL="mm_dell_vendorcheck"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
|
||||
|
||||
# Dell DW5821e (default 0x81d7, with esim support 0x81e0)
|
||||
# if 02: primary port
|
||||
# if 03: secondary port
|
||||
# if 04: raw NMEA port
|
||||
# if 05: diag/qcdm port
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81d7", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81d7", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81d7", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81d7", ENV{.MM_USBIFNUM}=="05", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81e0", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81e0", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81e0", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81e0", ENV{.MM_USBIFNUM}=="05", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
|
||||
# Dell DW5820e
|
||||
# if 02: AT port
|
||||
# if 04: debug port (ignore)
|
||||
# if 06: AT port
|
||||
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="81d9", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
GOTO="mm_dell_port_types_end"
|
||||
LABEL="mm_dell_port_types_end"
|
||||
@@ -0,0 +1,528 @@
|
||||
/* -*- 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) 2015-2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-plugin-dell.h"
|
||||
#include "mm-common-novatel.h"
|
||||
#include "mm-private-boxed-types.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-broadband-modem-novatel.h"
|
||||
#include "mm-common-novatel.h"
|
||||
#include "mm-broadband-modem-sierra.h"
|
||||
#include "mm-common-sierra.h"
|
||||
#include "mm-broadband-modem-telit.h"
|
||||
#include "mm-broadband-modem-xmm.h"
|
||||
#include "mm-common-telit.h"
|
||||
#include "mm-log-object.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
#include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
#include "mm-broadband-modem-mbim-xmm.h"
|
||||
#include "mm-broadband-modem-mbim-foxconn.h"
|
||||
#endif
|
||||
|
||||
#define MAX_PORT_PROBE_TIMEOUTS 3
|
||||
|
||||
G_DEFINE_TYPE (MMPluginDell, mm_plugin_dell, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
#define TAG_DELL_MANUFACTURER "dell-manufacturer"
|
||||
typedef enum {
|
||||
DELL_MANUFACTURER_UNKNOWN = 0,
|
||||
DELL_MANUFACTURER_NOVATEL = 1,
|
||||
DELL_MANUFACTURER_SIERRA = 2,
|
||||
DELL_MANUFACTURER_ERICSSON = 3,
|
||||
DELL_MANUFACTURER_TELIT = 4
|
||||
} DellManufacturer;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Custom init */
|
||||
|
||||
typedef struct {
|
||||
MMPortSerialAt *port;
|
||||
guint gmi_retries;
|
||||
guint cgmi_retries;
|
||||
guint ati_retries;
|
||||
guint timeouts;
|
||||
} CustomInitContext;
|
||||
|
||||
static void
|
||||
custom_init_context_free (CustomInitContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->port);
|
||||
g_slice_free (CustomInitContext, ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dell_custom_init_finish (MMPortProbe *probe,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
novatel_custom_init_ready (MMPortProbe *probe,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_common_novatel_custom_init_finish (probe, res, &error))
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
sierra_custom_init_ready (MMPortProbe *probe,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_common_sierra_custom_init_finish (probe, res, &error))
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
telit_custom_init_ready (MMPortProbe *probe,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!telit_custom_init_finish (probe, res, &error))
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void custom_init_step (GTask *task);
|
||||
|
||||
static void
|
||||
custom_init_step_next_command (GTask *task)
|
||||
{
|
||||
CustomInitContext *ctx;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
ctx->timeouts = 0;
|
||||
if (ctx->gmi_retries > 0)
|
||||
ctx->gmi_retries = 0;
|
||||
else if (ctx->cgmi_retries > 0)
|
||||
ctx->cgmi_retries = 0;
|
||||
else if (ctx->ati_retries > 0)
|
||||
ctx->ati_retries = 0;
|
||||
custom_init_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
response_ready (MMPortSerialAt *port,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
CustomInitContext *ctx;
|
||||
MMPortProbe *probe;
|
||||
const gchar *response;
|
||||
GError *error = NULL;
|
||||
gchar *lower;
|
||||
DellManufacturer manufacturer;
|
||||
|
||||
probe = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
response = mm_port_serial_at_command_finish (port, res, &error);
|
||||
if (error) {
|
||||
/* Non-timeout error, jump to next command */
|
||||
if (!g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) {
|
||||
mm_obj_dbg (probe, "error probing AT port: %s", error->message);
|
||||
g_error_free (error);
|
||||
custom_init_step_next_command (task);
|
||||
return;
|
||||
}
|
||||
/* Directly retry same command on timeout */
|
||||
ctx->timeouts++;
|
||||
custom_init_step (task);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Guess manufacturer from response */
|
||||
lower = g_ascii_strdown (response, -1);
|
||||
if (strstr (lower, "novatel"))
|
||||
manufacturer = DELL_MANUFACTURER_NOVATEL;
|
||||
else if (strstr (lower, "sierra"))
|
||||
manufacturer = DELL_MANUFACTURER_SIERRA;
|
||||
else if (strstr (lower, "ericsson"))
|
||||
manufacturer = DELL_MANUFACTURER_ERICSSON;
|
||||
else if (strstr (lower, "telit"))
|
||||
manufacturer = DELL_MANUFACTURER_TELIT;
|
||||
else
|
||||
manufacturer = DELL_MANUFACTURER_UNKNOWN;
|
||||
g_free (lower);
|
||||
|
||||
/* Tag based on manufacturer */
|
||||
if (manufacturer != DELL_MANUFACTURER_UNKNOWN) {
|
||||
g_object_set_data (G_OBJECT (probe), TAG_DELL_MANUFACTURER, GUINT_TO_POINTER (manufacturer));
|
||||
|
||||
/* Run additional custom init, if needed */
|
||||
|
||||
if (manufacturer == DELL_MANUFACTURER_NOVATEL) {
|
||||
mm_common_novatel_custom_init (probe,
|
||||
ctx->port,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) novatel_custom_init_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (manufacturer == DELL_MANUFACTURER_SIERRA) {
|
||||
mm_common_sierra_custom_init (probe,
|
||||
ctx->port,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) sierra_custom_init_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (manufacturer == DELL_MANUFACTURER_TELIT) {
|
||||
telit_custom_init (probe,
|
||||
ctx->port,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) telit_custom_init_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finish custom_init */
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we got a response, but we didn't get an expected string, try with next command */
|
||||
custom_init_step_next_command (task);
|
||||
}
|
||||
|
||||
static void
|
||||
custom_init_step (GTask *task)
|
||||
{
|
||||
CustomInitContext *ctx;
|
||||
MMPortProbe *probe;
|
||||
|
||||
probe = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* If cancelled, end without error right away */
|
||||
if (g_cancellable_is_cancelled (g_task_get_cancellable (task))) {
|
||||
mm_obj_dbg (probe, "no need to keep on running custom init: cancelled");
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined WITH_QMI
|
||||
/* If device has a QMI port, don't run anything else, as we don't care */
|
||||
if (mm_port_probe_list_has_qmi_port (mm_device_peek_port_probe_list (mm_port_probe_peek_device (probe)))) {
|
||||
mm_obj_dbg (probe, "no need to run custom init: device has QMI port");
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
/* If device has a MBIM port, don't run anything else, as we don't care */
|
||||
if (mm_port_probe_list_has_mbim_port (mm_device_peek_port_probe_list (mm_port_probe_peek_device (probe)))) {
|
||||
mm_obj_dbg (probe, "no need to run custom init: device has MBIM port");
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ctx->timeouts >= MAX_PORT_PROBE_TIMEOUTS) {
|
||||
mm_obj_dbg (probe, "couldn't detect real manufacturer: too many timeouts");
|
||||
mm_port_probe_set_result_at (probe, FALSE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ctx->gmi_retries > 0) {
|
||||
ctx->gmi_retries--;
|
||||
mm_port_serial_at_command (ctx->port,
|
||||
"AT+GMI",
|
||||
3,
|
||||
FALSE, /* raw */
|
||||
FALSE, /* allow_cached */
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback)response_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->cgmi_retries > 0) {
|
||||
ctx->cgmi_retries--;
|
||||
mm_port_serial_at_command (ctx->port,
|
||||
"AT+CGMI",
|
||||
3,
|
||||
FALSE, /* raw */
|
||||
FALSE, /* allow_cached */
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback)response_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->ati_retries > 0) {
|
||||
ctx->ati_retries--;
|
||||
/* Note: in Ericsson devices, ATI3 seems to reply the vendor string */
|
||||
mm_port_serial_at_command (ctx->port,
|
||||
"ATI1I2I3",
|
||||
3,
|
||||
FALSE, /* raw */
|
||||
FALSE, /* allow_cached */
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback)response_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (probe, "couldn't detect real manufacturer: all retries consumed");
|
||||
out:
|
||||
/* Finish custom_init */
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
dell_custom_init (MMPortProbe *probe,
|
||||
MMPortSerialAt *port,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
CustomInitContext *ctx;
|
||||
|
||||
ctx = g_slice_new0 (CustomInitContext);
|
||||
ctx->port = g_object_ref (port);
|
||||
ctx->gmi_retries = 3;
|
||||
ctx->cgmi_retries = 1;
|
||||
ctx->ati_retries = 1;
|
||||
|
||||
task = g_task_new (probe, cancellable, callback, user_data);
|
||||
g_task_set_check_cancellable (task, FALSE);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) custom_init_context_free);
|
||||
|
||||
custom_init_step (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
port_probe_list_has_manufacturer_port (GList *probes,
|
||||
DellManufacturer manufacturer)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = probes; l; l = g_list_next (l)) {
|
||||
if (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (l->data), TAG_DELL_MANUFACTURER)) == manufacturer)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
/* Note: at this point we don't make any difference between different
|
||||
* Dell-branded QMI or MBIM modems; they may come from Novatel, Ericsson or
|
||||
* Sierra. */
|
||||
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered Dell-branded modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
if (mm_port_probe_list_has_mbim_port (probes)) {
|
||||
/* Specific implementation for the DW5821e and DW5829e */
|
||||
if (vendor == 0x413c && (product == 0x81d7 || product == 0x81e0 || product == 0x81e4 || product == 0x81e6)) {
|
||||
mm_obj_dbg (self, "MBIM-powered DW5821e/DW5829e (T77W968) modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_foxconn_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
if (mm_port_probe_list_is_xmm (probes)) {
|
||||
mm_obj_dbg (self, "MBIM-powered XMM-based modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_xmm_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "MBIM-powered Dell-branded modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (port_probe_list_has_manufacturer_port (probes, DELL_MANUFACTURER_NOVATEL)) {
|
||||
mm_obj_dbg (self, "Novatel-powered Dell-branded modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_novatel_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
if (port_probe_list_has_manufacturer_port (probes, DELL_MANUFACTURER_SIERRA)) {
|
||||
mm_obj_dbg (self, "Sierra-powered Dell-branded modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_sierra_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
if (port_probe_list_has_manufacturer_port (probes, DELL_MANUFACTURER_TELIT)) {
|
||||
mm_obj_dbg (self, "Telit-powered Dell-branded modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_telit_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
if (mm_port_probe_list_is_xmm (probes)) {
|
||||
mm_obj_dbg (self, "XMM-based modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_xmm_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "Dell-branded generic modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
grab_port (MMPlugin *self,
|
||||
MMBaseModem *modem,
|
||||
MMPortProbe *probe,
|
||||
GError **error)
|
||||
{
|
||||
if (MM_IS_BROADBAND_MODEM_SIERRA (modem))
|
||||
return mm_common_sierra_grab_port (self, modem, probe, error);
|
||||
|
||||
if (MM_IS_BROADBAND_MODEM_TELIT (modem))
|
||||
return telit_grab_port (self, modem, probe, error);
|
||||
|
||||
return mm_base_modem_grab_port (modem,
|
||||
mm_port_probe_peek_port (probe),
|
||||
mm_port_probe_get_port_type (probe),
|
||||
MM_PORT_SERIAL_AT_FLAG_NONE,
|
||||
error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", NULL };
|
||||
static const guint16 vendors[] = { 0x413c, 0 };
|
||||
static const MMAsyncMethod custom_init = {
|
||||
.async = G_CALLBACK (dell_custom_init),
|
||||
.finish = G_CALLBACK (dell_custom_init_finish),
|
||||
};
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_DELL,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendors,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_CUSTOM_INIT, &custom_init,
|
||||
MM_PLUGIN_ALLOWED_QCDM, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
MM_PLUGIN_ALLOWED_MBIM, TRUE,
|
||||
MM_PLUGIN_XMM_PROBE, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_dell_init (MMPluginDell *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_dell_class_init (MMPluginDellClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
plugin_class->grab_port = grab_port;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* -*- 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) 2015 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_DELL_H
|
||||
#define MM_PLUGIN_DELL_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_DELL (mm_plugin_dell_get_type ())
|
||||
#define MM_PLUGIN_DELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_DELL, MMPluginDell))
|
||||
#define MM_PLUGIN_DELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_DELL, MMPluginDellClass))
|
||||
#define MM_IS_PLUGIN_DELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_DELL))
|
||||
#define MM_IS_PLUGIN_DELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_DELL))
|
||||
#define MM_PLUGIN_DELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_DELL, MMPluginDellClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginDell;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginDellClass;
|
||||
|
||||
GType mm_plugin_dell_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_DELL_H */
|
||||
@@ -0,0 +1,16 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION!="add|change|move|bind", GOTO="mm_dlink_port_types_end"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2001", GOTO="mm_dlink_port_types"
|
||||
GOTO="mm_dlink_port_types_end"
|
||||
|
||||
LABEL="mm_dlink_port_types"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
|
||||
|
||||
# D-Link DWM-222
|
||||
ATTRS{idVendor}=="2001", ATTRS{idProduct}=="7e35", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="2001", ATTRS{idProduct}=="7e35", ENV{.MM_USBIFNUM}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="2001", ATTRS{idProduct}=="7e35", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="2001", ATTRS{idProduct}=="7e35", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
LABEL="mm_dlink_port_types_end"
|
||||
@@ -0,0 +1,94 @@
|
||||
/* -*- 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) 2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-plugin-dlink.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
# include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginDlink, mm_plugin_dlink, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered D-Link modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x2001, 0 };
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_DLINK,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_dlink_init (MMPluginDlink *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_dlink_class_init (MMPluginDlinkClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -*- 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) 2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_DLINK_H
|
||||
#define MM_PLUGIN_DLINK_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_DLINK (mm_plugin_dlink_get_type ())
|
||||
#define MM_PLUGIN_DLINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_DLINK, MMPluginDlink))
|
||||
#define MM_PLUGIN_DLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_DLINK, MMPluginDlinkClass))
|
||||
#define MM_IS_PLUGIN_DLINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_DLINK))
|
||||
#define MM_IS_PLUGIN_DLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_DLINK))
|
||||
#define MM_PLUGIN_DLINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_DLINK, MMPluginDlinkClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginDlink;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginDlinkClass;
|
||||
|
||||
GType mm_plugin_dlink_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_DLINK_H */
|
||||
@@ -0,0 +1,109 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
ACTION!="add|change|move|bind", GOTO="mm_fibocom_port_types_end"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2cb7", GOTO="mm_fibocom_port_types"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1782", GOTO="mm_fibocom_port_types"
|
||||
GOTO="mm_fibocom_port_types_end"
|
||||
|
||||
LABEL="mm_fibocom_port_types"
|
||||
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
|
||||
|
||||
# Fibocom L850-GL attach APN with toggle modem power
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0007", ENV{ID_MM_FIBOCOM_INITIAL_EPS_OFF_ON}="1"
|
||||
|
||||
# Fibocom L850-GL
|
||||
# ttyACM0 (if #2): AT port
|
||||
# ttyACM1 (if #4): debug port (ignore)
|
||||
# ttyACM2 (if #6): AT port
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0007", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
# Fibocom NL668-AM
|
||||
# ttyACM0 (if #2): AT port
|
||||
# ttyACM1 (if #3): AT port
|
||||
# ttyACM2 (if #4): debug port (ignore)
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a0", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a0", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a0", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
# Fibocom FM150
|
||||
# ttyUSB0 (if #0): QCDM port
|
||||
# ttyUSB1 (if #1): AT port
|
||||
# ttyUSB2 (if #2): AT port
|
||||
# ttyUSB2 (if #3): Ignore
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0104", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
# Fibocom FM101-GL (MBIM)
|
||||
# ttyUSB0 (if #2): AT port
|
||||
# ttyUSB1 (if #3): AT port
|
||||
# ttyUSB2 (if #4): debug port (ignore)
|
||||
# ttyUSB3 (if #5): debug port (ignore)
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a2", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a2", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a2", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a2", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
# Fibocom FM101-GL (ADB)
|
||||
# ttyUSB0 (if #2): debug port (ignore)
|
||||
# ttyUSB1 (if #3): AT port
|
||||
# ttyUSB2 (if #4): debug port (ignore)
|
||||
# ttyUSB3 (if #5): debug port (ignore)
|
||||
# ttyUSB4 (if #6): debug port (ignore)
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a4", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a4", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a4", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a4", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="01a4", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
|
||||
# Fibocom MA510-GL (GTUSBMODE=31)
|
||||
# ttyUSB0 (if #0): debug port (ignore)
|
||||
# ttyUSB1 (if #1): AT port
|
||||
# ttyUSB2 (if #2): AT port
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0106", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0106", ENV{.MM_USBIFNUM}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0106", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0106", ENV{ID_MM_FIBOCOM_INITIAL_EPS_CID}="1"
|
||||
|
||||
# Fibocom MA510-GL (GTUSBMODE=32)
|
||||
# ttyUSB1 (if #0): AT port
|
||||
# ttyUSB2 (if #1): AT port
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="010a", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="010a", ENV{.MM_USBIFNUM}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="010a", ENV{ID_MM_FIBOCOM_INITIAL_EPS_CID}="1"
|
||||
|
||||
# Fibocom L610 (GTUSBMODE=31)
|
||||
# ttyUSB0 (if #0): AT port
|
||||
# ttyUSB1 (if #1): NV
|
||||
# ttyUSB2 (if #2): MOS
|
||||
# ttyUSB3 (if #3): Diagnostic
|
||||
# ttyUSB4 (if #4): Logging
|
||||
# ttyUSB5 (if #5): AT port
|
||||
# ttyUSB6 (if #6): AT port
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d10", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d10", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d10", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d10", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d10", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d10", ENV{.MM_USBIFNUM}=="05", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d10", ENV{.MM_USBIFNUM}=="06", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
|
||||
# Fibocom L610 (GTUSBMODE={32,33} - ECM/RNDIS)
|
||||
# ttyUSB0 (if #2): AT port
|
||||
# ttyUSB1 (if #3): NV
|
||||
# ttyUSB2 (if #4): MOS
|
||||
# ttyUSB3 (if #5): Diagnostic
|
||||
# ttyUSB4 (if #6): Logging
|
||||
# ttyUSB5 (if #7): AT port
|
||||
# ttyUSB6 (if #8): AT port
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d11", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d11", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d11", ENV{.MM_USBIFNUM}=="04", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d11", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d11", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d11", ENV{.MM_USBIFNUM}=="07", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="1782", ATTRS{idProduct}=="4d11", ENV{.MM_USBIFNUM}=="08", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
|
||||
LABEL="mm_fibocom_port_types_end"
|
||||
@@ -0,0 +1,540 @@
|
||||
/* -*- 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) 2022 Disruptive Technologies Research AS
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "mm-broadband-bearer-fibocom-ecm.h"
|
||||
#include "mm-broadband-modem-fibocom.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-iface-modem-3gpp.h"
|
||||
#include "mm-log.h"
|
||||
|
||||
G_DEFINE_TYPE (MMBroadbandBearerFibocomEcm, mm_broadband_bearer_fibocom_ecm, MM_TYPE_BROADBAND_BEARER)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Common helper functions */
|
||||
|
||||
static gboolean
|
||||
parse_gtrndis_read_response (const gchar *response,
|
||||
guint *state,
|
||||
guint *cid,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GRegex) r = NULL;
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
|
||||
r = g_regex_new ("\\+GTRNDIS:\\s*(\\d+)(?:,(\\d+))?",
|
||||
G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL);
|
||||
g_assert (r != NULL);
|
||||
|
||||
if (!g_regex_match (r, response, 0, &match_info)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Invalid +GTRNDIS response: %s", response);
|
||||
return FALSE;
|
||||
}
|
||||
if (!mm_get_uint_from_match_info (match_info, 1, state)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Failed to match state in +GTRNDIS response: %s", response);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (*state) {
|
||||
if (!mm_get_uint_from_match_info (match_info, 2, cid)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Failed to match cid in +GTRNDIS response: %s", response);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
*cid = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Connection status monitoring */
|
||||
|
||||
static MMBearerConnectionStatus
|
||||
load_connection_status_finish (MMBaseBearer *bearer,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
GError *inner_error = NULL;
|
||||
gssize value;
|
||||
|
||||
value = g_task_propagate_int (G_TASK (res), &inner_error);
|
||||
if (inner_error) {
|
||||
g_propagate_error (error, inner_error);
|
||||
return MM_BEARER_CONNECTION_STATUS_UNKNOWN;
|
||||
}
|
||||
return (MMBearerConnectionStatus) value;
|
||||
}
|
||||
|
||||
static void
|
||||
gtrndis_query_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseBearer *bearer;
|
||||
GError *error = NULL;
|
||||
const gchar *result;
|
||||
guint state;
|
||||
guint cid;
|
||||
|
||||
bearer = g_task_get_source_object (task);
|
||||
result = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (!result)
|
||||
g_task_return_error (task, error);
|
||||
else if (!parse_gtrndis_read_response (result, &state, &cid, &error))
|
||||
g_task_return_error (task, error);
|
||||
else if (!state || (gint) cid != mm_base_bearer_get_profile_id (bearer))
|
||||
g_task_return_int (task, MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
|
||||
else
|
||||
g_task_return_int (task, MM_BEARER_CONNECTION_STATUS_CONNECTED);
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
load_connection_status (MMBaseBearer *bearer,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
MMBaseModem *modem = NULL;
|
||||
|
||||
task = g_task_new (bearer, NULL, callback, user_data);
|
||||
|
||||
g_object_get (MM_BASE_BEARER (bearer),
|
||||
MM_BASE_BEARER_MODEM, &modem,
|
||||
NULL);
|
||||
|
||||
mm_base_modem_at_command (modem,
|
||||
"+GTRNDIS?",
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback) gtrndis_query_ready,
|
||||
task);
|
||||
g_object_unref (modem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP Connect */
|
||||
|
||||
typedef struct {
|
||||
MMBroadbandModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
MMPortSerialAt *secondary;
|
||||
MMBearerIpFamily ip_family;
|
||||
} ConnectContext;
|
||||
|
||||
static void
|
||||
connect_context_free (ConnectContext *ctx)
|
||||
{
|
||||
g_clear_object (&ctx->modem);
|
||||
g_clear_object (&ctx->primary);
|
||||
g_clear_object (&ctx->secondary);
|
||||
g_slice_free (ConnectContext, ctx);
|
||||
}
|
||||
|
||||
static MMBearerConnectResult *
|
||||
connect_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_connect_3gpp_ready (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
MMBearerConnectResult *result;
|
||||
|
||||
result = MM_BROADBAND_BEARER_CLASS (mm_broadband_bearer_fibocom_ecm_parent_class)->connect_3gpp_finish (self, res, &error);
|
||||
if (result)
|
||||
g_task_return_pointer (task, result, (GDestroyNotify) mm_bearer_connect_result_unref);
|
||||
else
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp_ready (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean result;
|
||||
ConnectContext *ctx;
|
||||
|
||||
result = MM_BROADBAND_BEARER_GET_CLASS (self)->disconnect_3gpp_finish (self, res, &error);
|
||||
if (!result) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
MM_BROADBAND_BEARER_CLASS (mm_broadband_bearer_fibocom_ecm_parent_class)->connect_3gpp (
|
||||
self,
|
||||
ctx->modem,
|
||||
ctx->primary,
|
||||
ctx->secondary,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) parent_connect_3gpp_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
gtrndis_check_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBroadbandBearer *self;
|
||||
ConnectContext *ctx;
|
||||
GError *error = NULL;
|
||||
const gchar *response;
|
||||
guint state;
|
||||
guint cid;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (!response) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!parse_gtrndis_read_response (response, &state, &cid, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
/* RNDIS is already active, disconnect first. */
|
||||
mm_obj_dbg (self, "RNDIS active, tearing down existing connection...");
|
||||
MM_BROADBAND_BEARER_GET_CLASS (self)->disconnect_3gpp (
|
||||
MM_BROADBAND_BEARER (self),
|
||||
ctx->modem,
|
||||
ctx->primary,
|
||||
ctx->secondary,
|
||||
NULL, /* data port */
|
||||
cid,
|
||||
(GAsyncReadyCallback) disconnect_3gpp_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Execute the regular connection flow if RNDIS is inactive. */
|
||||
mm_obj_dbg (self, "RNDIS inactive");
|
||||
MM_BROADBAND_BEARER_CLASS (mm_broadband_bearer_fibocom_ecm_parent_class)->connect_3gpp (
|
||||
MM_BROADBAND_BEARER (self),
|
||||
ctx->modem,
|
||||
ctx->primary,
|
||||
ctx->secondary,
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback) parent_connect_3gpp_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_3gpp (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
ConnectContext *ctx;
|
||||
GTask *task;
|
||||
|
||||
ctx = g_slice_new0 (ConnectContext);
|
||||
ctx->modem = g_object_ref (modem);
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->secondary = secondary ? g_object_ref (secondary) : NULL;
|
||||
ctx->ip_family = mm_bearer_properties_get_ip_type (mm_base_bearer_peek_config (MM_BASE_BEARER (self)));
|
||||
mm_3gpp_normalize_ip_family (&ctx->ip_family);
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) connect_context_free);
|
||||
|
||||
/* First, we must check whether RNDIS is already active */
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (modem),
|
||||
"+GTRNDIS?",
|
||||
3,
|
||||
FALSE, /* allow_cached */
|
||||
(GAsyncReadyCallback) gtrndis_check_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Dial context and task */
|
||||
|
||||
typedef struct {
|
||||
MMBroadbandModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
guint cid;
|
||||
MMPort *data;
|
||||
} DialContext;
|
||||
|
||||
static void
|
||||
dial_task_free (DialContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->modem);
|
||||
g_object_unref (ctx->primary);
|
||||
if (ctx->data)
|
||||
g_object_unref (ctx->data);
|
||||
g_slice_free (DialContext, ctx);
|
||||
}
|
||||
|
||||
static GTask *
|
||||
dial_task_new (MMBroadbandBearerFibocomEcm *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
guint cid,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
DialContext *ctx;
|
||||
GTask *task;
|
||||
|
||||
ctx = g_slice_new0 (DialContext);
|
||||
ctx->modem = g_object_ref (modem);
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->cid = cid;
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) dial_task_free);
|
||||
|
||||
ctx->data = mm_base_modem_get_best_data_port (MM_BASE_MODEM (modem), MM_PORT_TYPE_NET);
|
||||
if (!ctx->data) {
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_NOT_FOUND,
|
||||
"No valid data port found to launch connection");
|
||||
g_object_unref (task);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP Dialing (sub-step of the 3GPP Connection sequence) */
|
||||
|
||||
static MMPort *
|
||||
dial_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
gtrndis_verify_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
DialContext *ctx;
|
||||
GError *error = NULL;
|
||||
const gchar *response;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
|
||||
if (!response)
|
||||
g_task_return_error (task, error);
|
||||
else {
|
||||
response = mm_strip_tag (response, "+GTRNDIS:");
|
||||
if (strtol (response, NULL, 10) != 1)
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Connection status verification failed");
|
||||
else
|
||||
g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref);
|
||||
}
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
gtrndis_activate_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_base_modem_at_command_finish (modem, res, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_base_modem_at_command (modem,
|
||||
"+GTRNDIS?",
|
||||
6, /* timeout [s] */
|
||||
FALSE, /* allow_cached */
|
||||
(GAsyncReadyCallback) gtrndis_verify_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
dial_3gpp (MMBroadbandBearer *self,
|
||||
MMBaseModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
guint cid,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
g_autofree gchar *cmd = NULL;
|
||||
|
||||
task = dial_task_new (MM_BROADBAND_BEARER_FIBOCOM_ECM (self),
|
||||
MM_BROADBAND_MODEM (modem),
|
||||
primary,
|
||||
cid,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data);
|
||||
if (!task)
|
||||
return;
|
||||
|
||||
cmd = g_strdup_printf ("+GTRNDIS=1,%u", cid);
|
||||
mm_base_modem_at_command (modem,
|
||||
cmd,
|
||||
MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT,
|
||||
FALSE, /* allow_cached */
|
||||
(GAsyncReadyCallback) gtrndis_activate_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP Disconnect sequence */
|
||||
|
||||
static gboolean
|
||||
disconnect_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
gtrndis_deactivate_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_base_modem_at_command_finish (modem, res, &error))
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp (MMBroadbandBearer *self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
MMPort *data,
|
||||
guint cid,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
g_autofree gchar *cmd = NULL;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
cmd = g_strdup_printf ("+GTRNDIS=0,%u", cid);
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (modem),
|
||||
cmd,
|
||||
MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT,
|
||||
FALSE, /* allow_cached */
|
||||
(GAsyncReadyCallback) gtrndis_deactivate_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseBearer *
|
||||
mm_broadband_bearer_fibocom_ecm_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_base_bearer_export (MM_BASE_BEARER (bearer));
|
||||
|
||||
return MM_BASE_BEARER (bearer);
|
||||
}
|
||||
|
||||
void
|
||||
mm_broadband_bearer_fibocom_ecm_new (MMBroadbandModemFibocom *modem,
|
||||
MMBearerProperties *config,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
MM_TYPE_BROADBAND_BEARER_FIBOCOM_ECM,
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data,
|
||||
MM_BASE_BEARER_MODEM, modem,
|
||||
MM_BASE_BEARER_CONFIG, config,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_fibocom_ecm_init (MMBroadbandBearerFibocomEcm *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_fibocom_ecm_class_init (MMBroadbandBearerFibocomEcmClass *klass)
|
||||
{
|
||||
MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass);
|
||||
MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass);
|
||||
|
||||
base_bearer_class->load_connection_status = load_connection_status;
|
||||
base_bearer_class->load_connection_status_finish = load_connection_status_finish;
|
||||
|
||||
broadband_bearer_class->connect_3gpp = connect_3gpp;
|
||||
broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish;
|
||||
broadband_bearer_class->dial_3gpp = dial_3gpp;
|
||||
broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish;
|
||||
broadband_bearer_class->disconnect_3gpp = disconnect_3gpp;
|
||||
broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/* -*- 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) 2022 Disruptive Technologies Research AS
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_BEARER_FIBOCOM_ECM_H
|
||||
#define MM_BROADBAND_BEARER_FIBOCOM_ECM_H
|
||||
|
||||
#include "mm-broadband-bearer.h"
|
||||
#include "mm-broadband-modem-fibocom.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_BEARER_FIBOCOM_ECM (mm_broadband_bearer_fibocom_ecm_get_type ())
|
||||
#define MM_BROADBAND_BEARER_FIBOCOM_ECM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_BEARER_FIBOCOM_ECM, MMBroadbandBearerFibocomEcm))
|
||||
#define MM_BROADBAND_BEARER_FIBOCOM_ECM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_BEARER_FIBOCOM_ECM, MMBroadbandBearerFibocomEcmClass))
|
||||
#define MM_IS_BROADBAND_BEARER_FIBOCOM_ECM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_BEARER_FIBOCOM_ECM))
|
||||
#define MM_IS_BROADBAND_BEARER_FIBOCOM_ECM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_BEARER_FIBOCOM_ECM))
|
||||
#define MM_BROADBAND_BEARER_FIBOCOM_ECM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_BEARER_FIBOCOM_ECM, MMBroadbandBearerFibocomEcmClass))
|
||||
|
||||
typedef struct _MMBroadbandBearerFibocomEcm MMBroadbandBearerFibocomEcm;
|
||||
typedef struct _MMBroadbandBearerFibocomEcmClass MMBroadbandBearerFibocomEcmClass;
|
||||
|
||||
struct _MMBroadbandBearerFibocomEcm {
|
||||
MMBroadbandBearer parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandBearerFibocomEcmClass {
|
||||
MMBroadbandBearerClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_bearer_fibocom_ecm_get_type (void);
|
||||
|
||||
void mm_broadband_bearer_fibocom_ecm_new (MMBroadbandModemFibocom *modem,
|
||||
MMBearerProperties *properties,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
MMBaseBearer *mm_broadband_bearer_fibocom_ecm_new_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_BROADBAND_BEARER_FIBOCOM_ECM_H */
|
||||
@@ -0,0 +1,763 @@
|
||||
/* -*- 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) 2022 Disruptive Technologies Research AS
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "mm-broadband-modem-fibocom.h"
|
||||
#include "mm-broadband-bearer-fibocom-ecm.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-3gpp.h"
|
||||
#include "mm-iface-modem-3gpp-profile-manager.h"
|
||||
#include "mm-log.h"
|
||||
|
||||
static void iface_modem_init (MMIfaceModem *iface);
|
||||
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
||||
static void iface_modem_3gpp_profile_manager_init (MMIfaceModem3gppProfileManager *iface);
|
||||
|
||||
static MMIfaceModem3gppProfileManager *iface_modem_3gpp_profile_manager_parent;
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemFibocom, mm_broadband_modem_fibocom, 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_PROFILE_MANAGER, iface_modem_3gpp_profile_manager_init))
|
||||
|
||||
typedef enum {
|
||||
FEATURE_SUPPORT_UNKNOWN,
|
||||
FEATURE_NOT_SUPPORTED,
|
||||
FEATURE_SUPPORTED,
|
||||
} FeatureSupport;
|
||||
|
||||
struct _MMBroadbandModemFibocomPrivate {
|
||||
FeatureSupport gtrndis_support;
|
||||
GRegex *sim_ready_regex;
|
||||
FeatureSupport initial_eps_bearer_support;
|
||||
gint initial_eps_bearer_cid;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Create Bearer (Modem interface) */
|
||||
|
||||
static MMBaseBearer *
|
||||
modem_create_bearer_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
broadband_bearer_fibocom_ecm_new_ready (GObject *source,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseBearer *bearer = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
bearer = mm_broadband_bearer_fibocom_ecm_new_finish (res, &error);
|
||||
if (!bearer)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_pointer (task, bearer, g_object_unref);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
broadband_bearer_new_ready (GObject *source,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseBearer *bearer = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
bearer = mm_broadband_bearer_new_finish (res, &error);
|
||||
if (!bearer)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_pointer (task, bearer, g_object_unref);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
common_create_bearer (GTask *task)
|
||||
{
|
||||
MMBroadbandModemFibocom *self;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
switch (self->priv->gtrndis_support) {
|
||||
case FEATURE_SUPPORTED:
|
||||
mm_obj_dbg (self, "+GTRNDIS supported, creating Fibocom ECM bearer");
|
||||
mm_broadband_bearer_fibocom_ecm_new (self,
|
||||
g_task_get_task_data (task),
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback) broadband_bearer_fibocom_ecm_new_ready,
|
||||
task);
|
||||
return;
|
||||
case FEATURE_NOT_SUPPORTED:
|
||||
mm_obj_dbg (self, "+GTRNDIS not supported, creating generic PPP bearer");
|
||||
mm_broadband_bearer_new (MM_BROADBAND_MODEM (self),
|
||||
g_task_get_task_data (task),
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback) broadband_bearer_new_ready,
|
||||
task);
|
||||
return;
|
||||
case FEATURE_SUPPORT_UNKNOWN:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtrndis_test_ready (MMBaseModem *_self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
|
||||
|
||||
if (!mm_base_modem_at_command_finish (_self, res, NULL)) {
|
||||
mm_obj_dbg (self, "+GTRNDIS unsupported");
|
||||
self->priv->gtrndis_support = FEATURE_NOT_SUPPORTED;
|
||||
} else {
|
||||
mm_obj_dbg (self, "+GTRNDIS supported");
|
||||
self->priv->gtrndis_support = FEATURE_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Go on and create the bearer */
|
||||
common_create_bearer (task);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_create_bearer (MMIfaceModem *_self,
|
||||
MMBearerProperties *properties,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, g_object_ref (properties), g_object_unref);
|
||||
|
||||
if (self->priv->gtrndis_support != FEATURE_SUPPORT_UNKNOWN) {
|
||||
common_create_bearer (task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mm_base_modem_peek_best_data_port (MM_BASE_MODEM (self), MM_PORT_TYPE_NET)) {
|
||||
mm_obj_dbg (self, "skipping +GTRNDIS check as no data port is available");
|
||||
self->priv->gtrndis_support = FEATURE_NOT_SUPPORTED;
|
||||
common_create_bearer (task);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "checking +GTRNDIS support...");
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"+GTRNDIS=?",
|
||||
6, /* timeout [s] */
|
||||
TRUE, /* allow_cached */
|
||||
(GAsyncReadyCallback) gtrndis_test_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Reset / Power (Modem interface) */
|
||||
|
||||
static gboolean
|
||||
modem_common_power_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),
|
||||
"+CFUN=15",
|
||||
15,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_power_down (MMIfaceModem *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"+CFUN=4",
|
||||
15,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_power_off (MMIfaceModem *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"+CPWROFF",
|
||||
3,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Load initial EPS bearer properties (as agreed with network) */
|
||||
|
||||
static MMBearerProperties *
|
||||
modem_3gpp_load_initial_eps_bearer_finish (MMIfaceModem3gpp *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return MM_BEARER_PROPERTIES (g_task_propagate_pointer (G_TASK (res), error));
|
||||
}
|
||||
|
||||
static void
|
||||
load_initial_eps_cgcontrdp_ready (MMBaseModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const gchar *response;
|
||||
g_autofree gchar *apn = NULL;
|
||||
MMBearerProperties *properties;
|
||||
|
||||
response = mm_base_modem_at_command_finish (self, res, &error);
|
||||
if (!response || !mm_3gpp_parse_cgcontrdp_response (response, NULL, NULL, &apn, NULL, NULL, NULL, NULL, NULL, &error))
|
||||
g_task_return_error (task, error);
|
||||
else {
|
||||
properties = mm_bearer_properties_new ();
|
||||
mm_bearer_properties_set_apn (properties, apn);
|
||||
g_task_return_pointer (task, properties, g_object_unref);
|
||||
}
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_3gpp_load_initial_eps_bearer (MMIfaceModem3gpp *_self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
|
||||
GTask *task;
|
||||
g_autofree gchar *cmd = NULL;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
if (self->priv->initial_eps_bearer_support != FEATURE_SUPPORTED) {
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_UNSUPPORTED,
|
||||
"Initial EPS bearer context ID unknown");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (self->priv->initial_eps_bearer_cid >= 0);
|
||||
cmd = g_strdup_printf ("+CGCONTRDP=%d", self->priv->initial_eps_bearer_cid);
|
||||
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
cmd,
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback) load_initial_eps_cgcontrdp_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Load initial EPS bearer settings (currently configured in modem) */
|
||||
|
||||
static MMBearerProperties *
|
||||
modem_3gpp_load_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return MM_BEARER_PROPERTIES (g_task_propagate_pointer (G_TASK (res), error));
|
||||
}
|
||||
|
||||
static void
|
||||
load_initial_eps_bearer_get_profile_ready (MMIfaceModem3gppProfileManager *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
g_autoptr(MM3gppProfile) profile = NULL;
|
||||
MMBearerProperties *properties;
|
||||
|
||||
profile = mm_iface_modem_3gpp_profile_manager_get_profile_finish (self, res, &error);
|
||||
if (!profile) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
properties = mm_bearer_properties_new_from_profile (profile, &error);
|
||||
if (!properties)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_pointer (task, properties, g_object_unref);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_3gpp_load_initial_eps_bearer_settings (MMIfaceModem3gpp *_self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
|
||||
MMPortSerialAt *port;
|
||||
MMKernelDevice *device;
|
||||
GTask *task;
|
||||
|
||||
/* Initial EPS bearer CID initialization run once only */
|
||||
if (G_UNLIKELY (self->priv->initial_eps_bearer_support == FEATURE_SUPPORT_UNKNOWN)) {
|
||||
/* There doesn't seem to be a programmatic way to find the initial EPS
|
||||
* bearer's CID, so we'll use a udev variable. */
|
||||
port = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
||||
device = mm_port_peek_kernel_device (MM_PORT (port));
|
||||
if (mm_kernel_device_has_global_property (device, "ID_MM_FIBOCOM_INITIAL_EPS_CID")) {
|
||||
self->priv->initial_eps_bearer_support = FEATURE_SUPPORTED;
|
||||
self->priv->initial_eps_bearer_cid = mm_kernel_device_get_global_property_as_int (
|
||||
device, "ID_MM_FIBOCOM_INITIAL_EPS_CID");
|
||||
}
|
||||
else
|
||||
self->priv->initial_eps_bearer_support = FEATURE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
if (self->priv->initial_eps_bearer_support != FEATURE_SUPPORTED) {
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_UNSUPPORTED,
|
||||
"Initial EPS bearer context ID unknown");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (self->priv->initial_eps_bearer_cid >= 0);
|
||||
mm_iface_modem_3gpp_profile_manager_get_profile (
|
||||
MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self),
|
||||
self->priv->initial_eps_bearer_cid,
|
||||
(GAsyncReadyCallback) load_initial_eps_bearer_get_profile_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Set initial EPS bearer settings */
|
||||
|
||||
typedef enum {
|
||||
SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LOAD_POWER_STATE = 0,
|
||||
SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_DOWN,
|
||||
SET_INITIAL_EPS_BEARER_SETTINGS_STEP_MODIFY_PROFILE,
|
||||
SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_UP,
|
||||
SET_INITIAL_EPS_BEARER_SETTINGS_STEP_FINISH,
|
||||
} SetInitialEpsStep;
|
||||
|
||||
typedef struct {
|
||||
MM3gppProfile *profile;
|
||||
SetInitialEpsStep step;
|
||||
MMModemPowerState power_state;
|
||||
} SetInitialEpsContext;
|
||||
|
||||
static void
|
||||
set_initial_eps_context_free (SetInitialEpsContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->profile);
|
||||
g_slice_free (SetInitialEpsContext, ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
modem_3gpp_set_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void set_initial_eps_step (GTask *task);
|
||||
|
||||
static void
|
||||
set_initial_eps_bearer_power_up_ready (MMBaseModem *_self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
|
||||
SetInitialEpsContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish (MM_IFACE_MODEM (self), res, &error)) {
|
||||
g_prefix_error (&error, "Couldn't power up modem: ");
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->step++;
|
||||
set_initial_eps_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
set_initial_eps_bearer_modify_profile_ready (MMIfaceModem3gppProfileManager *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
SetInitialEpsContext *ctx;
|
||||
g_autoptr(MM3gppProfile) stored = NULL;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
stored = mm_iface_modem_3gpp_profile_manager_set_profile_finish (self, res, &error);
|
||||
if (!stored) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->step++;
|
||||
set_initial_eps_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
set_initial_eps_bearer_power_down_ready (MMBaseModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
SetInitialEpsContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish (MM_IFACE_MODEM (self), res, &error)) {
|
||||
g_prefix_error (&error, "Couldn't power down modem: ");
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->step++;
|
||||
set_initial_eps_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
set_initial_eps_bearer_load_power_state_ready (MMBaseModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
SetInitialEpsContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
ctx->power_state = MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish (MM_IFACE_MODEM (self), res, &error);
|
||||
if (error) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->step++;
|
||||
set_initial_eps_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
set_initial_eps_step (GTask *task)
|
||||
{
|
||||
MMBroadbandModemFibocom *self;
|
||||
SetInitialEpsContext *ctx;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
switch (ctx->step) {
|
||||
case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LOAD_POWER_STATE:
|
||||
mm_obj_dbg (self, "querying current power state...");
|
||||
g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state);
|
||||
g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish);
|
||||
MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state (
|
||||
MM_IFACE_MODEM (self),
|
||||
(GAsyncReadyCallback) set_initial_eps_bearer_load_power_state_ready,
|
||||
task);
|
||||
return;
|
||||
|
||||
case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_DOWN:
|
||||
if (ctx->power_state == MM_MODEM_POWER_STATE_ON) {
|
||||
mm_obj_dbg (self, "powering down before changing initial EPS bearer settings...");
|
||||
g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down);
|
||||
g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish);
|
||||
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down (
|
||||
MM_IFACE_MODEM (self),
|
||||
(GAsyncReadyCallback) set_initial_eps_bearer_power_down_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
ctx->step++;
|
||||
/* fall through */
|
||||
|
||||
case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_MODIFY_PROFILE:
|
||||
mm_obj_dbg (self, "modifying initial EPS bearer settings profile...");
|
||||
mm_iface_modem_3gpp_profile_manager_set_profile (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self),
|
||||
ctx->profile,
|
||||
"profile-id",
|
||||
TRUE,
|
||||
(GAsyncReadyCallback) set_initial_eps_bearer_modify_profile_ready,
|
||||
task);
|
||||
return;
|
||||
|
||||
case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_UP:
|
||||
if (ctx->power_state == MM_MODEM_POWER_STATE_ON) {
|
||||
mm_obj_dbg (self, "powering up after changing initial EPS bearer settings...");
|
||||
g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up);
|
||||
g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish);
|
||||
MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up (
|
||||
MM_IFACE_MODEM (self),
|
||||
(GAsyncReadyCallback) set_initial_eps_bearer_power_up_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
ctx->step++;
|
||||
/* fall through */
|
||||
|
||||
case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_FINISH:
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
modem_3gpp_set_initial_eps_bearer_settings (MMIfaceModem3gpp *_self,
|
||||
MMBearerProperties *properties,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
|
||||
GTask *task;
|
||||
MM3gppProfile *profile;
|
||||
MMBearerIpFamily ip_family;
|
||||
SetInitialEpsContext *ctx;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
if (self->priv->initial_eps_bearer_support != FEATURE_SUPPORTED) {
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_UNSUPPORTED,
|
||||
"Initial EPS bearer context ID unknown");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
profile = mm_bearer_properties_peek_3gpp_profile (properties);
|
||||
g_assert (self->priv->initial_eps_bearer_cid >= 0);
|
||||
mm_3gpp_profile_set_profile_id (profile, self->priv->initial_eps_bearer_cid);
|
||||
ip_family = mm_3gpp_profile_get_ip_type (profile);
|
||||
if (ip_family == MM_BEARER_IP_FAMILY_NONE || ip_family == MM_BEARER_IP_FAMILY_ANY)
|
||||
mm_3gpp_profile_set_ip_type (profile, MM_BEARER_IP_FAMILY_IPV4);
|
||||
|
||||
/* Setup context */
|
||||
ctx = g_slice_new0 (SetInitialEpsContext);
|
||||
ctx->profile = g_object_ref (profile);
|
||||
ctx->step = SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LOAD_POWER_STATE;
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) set_initial_eps_context_free);
|
||||
|
||||
set_initial_eps_step (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Deactivate profile (3GPP profile management interface) */
|
||||
|
||||
static gboolean
|
||||
modem_3gpp_profile_manager_deactivate_profile_finish (MMIfaceModem3gppProfileManager *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
profile_manager_parent_deactivate_profile_ready (MMIfaceModem3gppProfileManager *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
if (iface_modem_3gpp_profile_manager_parent->deactivate_profile_finish(self, res, &error))
|
||||
g_task_return_boolean (task, TRUE);
|
||||
else
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_3gpp_profile_manager_deactivate_profile (MMIfaceModem3gppProfileManager *_self,
|
||||
MM3gppProfile *profile,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
|
||||
GTask *task;
|
||||
gint profile_id;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
profile_id = mm_3gpp_profile_get_profile_id (profile);
|
||||
|
||||
if (self->priv->initial_eps_bearer_support == FEATURE_SUPPORTED) {
|
||||
g_assert (self->priv->initial_eps_bearer_cid >= 0);
|
||||
if (self->priv->initial_eps_bearer_cid == profile_id) {
|
||||
mm_obj_dbg (self, "skipping profile deactivation (initial EPS bearer)");
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
iface_modem_3gpp_profile_manager_parent->deactivate_profile (
|
||||
_self,
|
||||
profile,
|
||||
(GAsyncReadyCallback) profile_manager_parent_deactivate_profile_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
setup_ports (MMBroadbandModem *_self)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = (MM_BROADBAND_MODEM_FIBOCOM (_self));
|
||||
MMPortSerialAt *ports[2];
|
||||
guint i;
|
||||
|
||||
/* Call parent's setup ports first always */
|
||||
MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_fibocom_parent_class)->setup_ports (_self);
|
||||
|
||||
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
||||
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (ports); i++) {
|
||||
if (!ports[i])
|
||||
continue;
|
||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||
ports[i],
|
||||
self->priv->sim_ready_regex,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBroadbandModemFibocom *
|
||||
mm_broadband_modem_fibocom_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_FIBOCOM,
|
||||
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_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_fibocom_init (MMBroadbandModemFibocom *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
MM_TYPE_BROADBAND_MODEM_FIBOCOM,
|
||||
MMBroadbandModemFibocomPrivate);
|
||||
|
||||
self->priv->gtrndis_support = FEATURE_SUPPORT_UNKNOWN;
|
||||
self->priv->sim_ready_regex = g_regex_new ("\\r\\n\\+SIM READY\\r\\n",
|
||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||
self->priv->initial_eps_bearer_support = FEATURE_SUPPORT_UNKNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
finalize (GObject *object)
|
||||
{
|
||||
MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (object);
|
||||
|
||||
g_regex_unref (self->priv->sim_ready_regex);
|
||||
|
||||
G_OBJECT_CLASS (mm_broadband_modem_fibocom_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_init (MMIfaceModem *iface)
|
||||
{
|
||||
iface->create_bearer = modem_create_bearer;
|
||||
iface->create_bearer_finish = modem_create_bearer_finish;
|
||||
iface->reset = modem_reset;
|
||||
iface->reset_finish = modem_common_power_finish;
|
||||
iface->modem_power_down = modem_power_down;
|
||||
iface->modem_power_down_finish = modem_common_power_finish;
|
||||
iface->modem_power_off = modem_power_off;
|
||||
iface->modem_power_off_finish = modem_common_power_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
|
||||
{
|
||||
iface->load_initial_eps_bearer = modem_3gpp_load_initial_eps_bearer;
|
||||
iface->load_initial_eps_bearer_finish = modem_3gpp_load_initial_eps_bearer_finish;
|
||||
iface->load_initial_eps_bearer_settings = modem_3gpp_load_initial_eps_bearer_settings;
|
||||
iface->load_initial_eps_bearer_settings_finish = modem_3gpp_load_initial_eps_bearer_settings_finish;
|
||||
iface->set_initial_eps_bearer_settings = modem_3gpp_set_initial_eps_bearer_settings;
|
||||
iface->set_initial_eps_bearer_settings_finish = modem_3gpp_set_initial_eps_bearer_settings_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_3gpp_profile_manager_init (MMIfaceModem3gppProfileManager *iface)
|
||||
{
|
||||
iface_modem_3gpp_profile_manager_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->deactivate_profile = modem_3gpp_profile_manager_deactivate_profile;
|
||||
iface->deactivate_profile_finish = modem_3gpp_profile_manager_deactivate_profile_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_fibocom_class_init (MMBroadbandModemFibocomClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (G_OBJECT_CLASS (klass),
|
||||
sizeof (MMBroadbandModemFibocomPrivate));
|
||||
|
||||
/* Virtual methods */
|
||||
object_class->finalize = finalize;
|
||||
broadband_modem_class->setup_ports = setup_ports;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* -*- 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) 2022 Disruptive Technologies Research AS
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_FIBOCOM_H
|
||||
#define MM_BROADBAND_MODEM_FIBOCOM_H
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_FIBOCOM (mm_broadband_modem_fibocom_get_type ())
|
||||
#define MM_BROADBAND_MODEM_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_FIBOCOM, MMBroadbandModemFibocom))
|
||||
#define MM_BROADBAND_MODEM_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_FIBOCOM, MMBroadbandModemFibocomClass))
|
||||
#define MM_IS_BROADBAND_MODEM_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_FIBOCOM))
|
||||
#define MM_IS_BROADBAND_MODEM_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_FIBOCOM))
|
||||
#define MM_BROADBAND_MODEM_FIBOCOM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_FIBOCOM, MMBroadbandModemFibocomClass))
|
||||
|
||||
typedef struct _MMBroadbandModemFibocom MMBroadbandModemFibocom;
|
||||
typedef struct _MMBroadbandModemFibocomClass MMBroadbandModemFibocomClass;
|
||||
typedef struct _MMBroadbandModemFibocomPrivate MMBroadbandModemFibocomPrivate;
|
||||
|
||||
struct _MMBroadbandModemFibocom {
|
||||
MMBroadbandModem parent;
|
||||
MMBroadbandModemFibocomPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemFibocomClass{
|
||||
MMBroadbandModemClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_fibocom_get_type (void);
|
||||
|
||||
MMBroadbandModemFibocom *mm_broadband_modem_fibocom_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_FIBOCOM_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2022 Fibocom Wireless Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ModemManager.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-3gpp.h"
|
||||
#include "mm-broadband-modem-mbim-fibocom.h"
|
||||
#include "mm-shared-fibocom.h"
|
||||
|
||||
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
||||
static void shared_fibocom_init (MMSharedFibocom *iface);
|
||||
|
||||
static MMIfaceModem3gpp *iface_modem_3gpp_parent;
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimFibocom, mm_broadband_modem_mbim_fibocom, MM_TYPE_BROADBAND_MODEM_MBIM, 0,
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_FIBOCOM, shared_fibocom_init))
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
MMBroadbandModemMbimFibocom *
|
||||
mm_broadband_modem_mbim_fibocom_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_MBIM_FIBOCOM,
|
||||
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,
|
||||
/* MBIM bearer supports NET only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
|
||||
MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, TRUE,
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
MM_BROADBAND_MODEM_MBIM_QMI_UNSUPPORTED, TRUE,
|
||||
#endif
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_fibocom_init (MMBroadbandModemMbimFibocom *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
|
||||
{
|
||||
iface_modem_3gpp_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->set_initial_eps_bearer_settings = mm_shared_fibocom_set_initial_eps_bearer_settings;
|
||||
iface->set_initial_eps_bearer_settings_finish = mm_shared_fibocom_set_initial_eps_bearer_settings_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModem3gpp *
|
||||
peek_parent_3gpp_interface (MMSharedFibocom *self)
|
||||
{
|
||||
return iface_modem_3gpp_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
shared_fibocom_init (MMSharedFibocom *iface)
|
||||
{
|
||||
iface->peek_parent_3gpp_interface = peek_parent_3gpp_interface;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_fibocom_class_init (MMBroadbandModemMbimFibocomClass *klass)
|
||||
{
|
||||
}
|
||||
@@ -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:
|
||||
*
|
||||
* Copyright (C) 2022 Fibocom Wireless Inc.
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_MBIM_FIBOCOM_H
|
||||
#define MM_BROADBAND_MODEM_MBIM_FIBOCOM_H
|
||||
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_MBIM_FIBOCOM (mm_broadband_modem_mbim_fibocom_get_type ())
|
||||
#define MM_BROADBAND_MODEM_MBIM_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FIBOCOM, MMBroadbandModemMbimFibocom))
|
||||
#define MM_BROADBAND_MODEM_MBIM_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_FIBOCOM, MMBroadbandModemMbimFibocomClass))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FIBOCOM))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_FIBOCOM))
|
||||
#define MM_BROADBAND_MODEM_MBIM_FIBOCOM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FIBOCOM, MMBroadbandModemMbimFibocomClass))
|
||||
|
||||
typedef struct _MMBroadbandModemMbimFibocom MMBroadbandModemMbimFibocom;
|
||||
typedef struct _MMBroadbandModemMbimFibocomClass MMBroadbandModemMbimFibocomClass;
|
||||
|
||||
struct _MMBroadbandModemMbimFibocom {
|
||||
MMBroadbandModemMbim parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemMbimFibocomClass{
|
||||
MMBroadbandModemMbimClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_mbim_fibocom_get_type (void);
|
||||
|
||||
MMBroadbandModemMbimFibocom *mm_broadband_modem_mbim_fibocom_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_MBIM_FIBOCOM_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2022 Fibocom Wireless Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ModemManager.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-3gpp.h"
|
||||
#include "mm-broadband-modem-mbim-xmm-fibocom.h"
|
||||
#include "mm-shared-fibocom.h"
|
||||
|
||||
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
||||
static void shared_fibocom_init (MMSharedFibocom *iface);
|
||||
|
||||
static MMIfaceModem3gpp *iface_modem_3gpp_parent;
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimXmmFibocom, mm_broadband_modem_mbim_xmm_fibocom, MM_TYPE_BROADBAND_MODEM_MBIM_XMM, 0,
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_FIBOCOM, shared_fibocom_init))
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
MMBroadbandModemMbimXmmFibocom *
|
||||
mm_broadband_modem_mbim_xmm_fibocom_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_MBIM_XMM_FIBOCOM,
|
||||
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,
|
||||
/* MBIM bearer supports NET only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
|
||||
MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, TRUE,
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
MM_BROADBAND_MODEM_MBIM_QMI_UNSUPPORTED, TRUE,
|
||||
#endif
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_xmm_fibocom_init (MMBroadbandModemMbimXmmFibocom *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
|
||||
{
|
||||
iface_modem_3gpp_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->set_initial_eps_bearer_settings = mm_shared_fibocom_set_initial_eps_bearer_settings;
|
||||
iface->set_initial_eps_bearer_settings_finish = mm_shared_fibocom_set_initial_eps_bearer_settings_finish;
|
||||
}
|
||||
|
||||
static MMIfaceModem3gpp *
|
||||
peek_parent_3gpp_interface (MMSharedFibocom *self)
|
||||
{
|
||||
return iface_modem_3gpp_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
shared_fibocom_init (MMSharedFibocom *iface)
|
||||
{
|
||||
iface->peek_parent_3gpp_interface = peek_parent_3gpp_interface;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_xmm_fibocom_class_init (MMBroadbandModemMbimXmmFibocomClass *klass)
|
||||
{
|
||||
}
|
||||
@@ -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:
|
||||
*
|
||||
* Copyright (C) 2022 Fibocom Wireless Inc.
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_MBIM_XMM_FIBOCOM_H
|
||||
#define MM_BROADBAND_MODEM_MBIM_XMM_FIBOCOM_H
|
||||
|
||||
#include "mm-broadband-modem-mbim-xmm.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_MBIM_XMM_FIBOCOM (mm_broadband_modem_mbim_xmm_fibocom_get_type ())
|
||||
#define MM_BROADBAND_MODEM_MBIM_XMM_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_XMM_FIBOCOM, MMBroadbandModemMbimXmmFibocom))
|
||||
#define MM_BROADBAND_MODEM_MBIM_XMM_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_XMM_FIBOCOM, MMBroadbandModemMbimXmmFibocomClass))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_XMM_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_XMM_FIBOCOM))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_XMM_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_XMM_FIBOCOM))
|
||||
#define MM_BROADBAND_MODEM_MBIM_XMM_FIBOCOM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_XMM_FIBOCOM, MMBroadbandModemMbimXmmFibocomClass))
|
||||
|
||||
typedef struct _MMBroadbandModemMbimXmmFibocom MMBroadbandModemMbimXmmFibocom;
|
||||
typedef struct _MMBroadbandModemMbimXmmFibocomClass MMBroadbandModemMbimXmmFibocomClass;
|
||||
|
||||
struct _MMBroadbandModemMbimXmmFibocom {
|
||||
MMBroadbandModemMbimXmm parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemMbimXmmFibocomClass{
|
||||
MMBroadbandModemMbimXmmClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_mbim_xmm_fibocom_get_type (void);
|
||||
|
||||
MMBroadbandModemMbimXmmFibocom *mm_broadband_modem_mbim_xmm_fibocom_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_MBIM_XMM_FIBOCOM_H */
|
||||
@@ -0,0 +1,136 @@
|
||||
/* -*- 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) 2018-2020 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-plugin-fibocom.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-broadband-modem-xmm.h"
|
||||
#include "mm-broadband-modem-fibocom.h"
|
||||
|
||||
#if defined WITH_MBIM
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
#include "mm-broadband-modem-mbim-fibocom.h"
|
||||
#include "mm-broadband-modem-mbim-xmm.h"
|
||||
#include "mm-broadband-modem-mbim-xmm-fibocom.h"
|
||||
#endif
|
||||
|
||||
#if defined WITH_QMI
|
||||
#include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginFibocom, mm_plugin_fibocom, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_MBIM
|
||||
if (mm_port_probe_list_has_mbim_port (probes)) {
|
||||
if (mm_port_probe_list_is_xmm (probes)) {
|
||||
mm_obj_dbg (self, "MBIM-powered XMM-based Fibocom modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_xmm_fibocom_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
mm_obj_dbg (self, "MBIM-powered Fibocom modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_fibocom_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered Fibocom modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mm_port_probe_list_is_xmm (probes)) {
|
||||
mm_obj_dbg (self, "XMM-based Fibocom modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_xmm_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "Fibocom modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_fibocom_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x2cb7, 0x1782, 0 };
|
||||
static const gchar *drivers[] = { "cdc_mbim", "qmi_wwan", "cdc_ether", "option", NULL };
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_FIBOCOM,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_DRIVERS, drivers,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_ALLOWED_MBIM, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
MM_PLUGIN_XMM_PROBE, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_fibocom_init (MMPluginFibocom *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_fibocom_class_init (MMPluginFibocomClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -*- 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) 2018 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_FIBOCOM_H
|
||||
#define MM_PLUGIN_FIBOCOM_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_FIBOCOM (mm_plugin_fibocom_get_type ())
|
||||
#define MM_PLUGIN_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_FIBOCOM, MMPluginFibocom))
|
||||
#define MM_PLUGIN_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_FIBOCOM, MMPluginFibocomClass))
|
||||
#define MM_IS_PLUGIN_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_FIBOCOM))
|
||||
#define MM_IS_PLUGIN_FIBOCOM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_FIBOCOM))
|
||||
#define MM_PLUGIN_FIBOCOM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_FIBOCOM, MMPluginFibocomClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginFibocom;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginFibocomClass;
|
||||
|
||||
GType mm_plugin_fibocom_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_FIBOCOM_H */
|
||||
@@ -0,0 +1,246 @@
|
||||
/* -*- 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) 2022 Fibocom Wireless Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-3gpp.h"
|
||||
#include "mm-shared-fibocom.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Private data context */
|
||||
|
||||
#define PRIVATE_TAG "shared-intel-private-tag"
|
||||
static GQuark private_quark;
|
||||
|
||||
typedef struct {
|
||||
/* 3GPP interface support */
|
||||
MMIfaceModem3gpp *iface_modem_3gpp_parent;
|
||||
} Private;
|
||||
|
||||
static void
|
||||
private_free (Private *priv)
|
||||
{
|
||||
g_slice_free (Private, priv);
|
||||
}
|
||||
|
||||
static Private *
|
||||
get_private (MMSharedFibocom *self)
|
||||
{
|
||||
Private *priv;
|
||||
|
||||
if (G_UNLIKELY (!private_quark))
|
||||
private_quark = g_quark_from_static_string (PRIVATE_TAG);
|
||||
|
||||
priv = g_object_get_qdata (G_OBJECT (self), private_quark);
|
||||
if (!priv) {
|
||||
priv = g_slice_new0 (Private);
|
||||
|
||||
/* Setup parent class' MMIfaceModem3gpp */
|
||||
g_assert (MM_SHARED_FIBOCOM_GET_INTERFACE (self)->peek_parent_3gpp_interface);
|
||||
priv->iface_modem_3gpp_parent = MM_SHARED_FIBOCOM_GET_INTERFACE (self)->peek_parent_3gpp_interface (self);
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free);
|
||||
}
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
MMBearerProperties *config;
|
||||
gboolean initial_eps_off_on;
|
||||
} SetInitialEpsBearerSettingsContext;
|
||||
|
||||
static void
|
||||
set_initial_eps_bearer_settings_context_free (SetInitialEpsBearerSettingsContext *ctx)
|
||||
{
|
||||
g_clear_object (&ctx->config);
|
||||
g_slice_free (SetInitialEpsBearerSettingsContext, ctx);
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_shared_fibocom_set_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
after_attach_apn_modem_power_up_ready (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_iface_modem_set_power_state_finish (self, res, &error)) {
|
||||
mm_obj_warn (self, "failed to power up modem after attach APN settings update: %s", error->message);
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "success toggling modem power up after attach APN");
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_set_initial_eps_bearer_settings_ready (MMIfaceModem3gpp *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
SetInitialEpsBearerSettingsContext *ctx;
|
||||
Private *priv;
|
||||
GError *error = NULL;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
priv = get_private (MM_SHARED_FIBOCOM (self));
|
||||
|
||||
if (!priv->iface_modem_3gpp_parent->set_initial_eps_bearer_settings_finish (self, res, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->initial_eps_off_on) {
|
||||
mm_obj_dbg (self, "toggle modem power up after attach APN");
|
||||
mm_iface_modem_set_power_state (MM_IFACE_MODEM (self),
|
||||
MM_MODEM_POWER_STATE_ON,
|
||||
(GAsyncReadyCallback) after_attach_apn_modem_power_up_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_set_initial_eps_bearer_settings (GTask *task)
|
||||
{
|
||||
MMSharedFibocom *self;
|
||||
SetInitialEpsBearerSettingsContext *ctx;
|
||||
Private *priv;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
priv = get_private (self);
|
||||
|
||||
g_assert (priv->iface_modem_3gpp_parent);
|
||||
g_assert (priv->iface_modem_3gpp_parent->set_initial_eps_bearer_settings);
|
||||
g_assert (priv->iface_modem_3gpp_parent->set_initial_eps_bearer_settings_finish);
|
||||
|
||||
priv->iface_modem_3gpp_parent->set_initial_eps_bearer_settings (MM_IFACE_MODEM_3GPP (self),
|
||||
ctx->config,
|
||||
(GAsyncReadyCallback)parent_set_initial_eps_bearer_settings_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
before_attach_apn_modem_power_down_ready (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_iface_modem_set_power_state_finish (self, res, &error)) {
|
||||
mm_obj_warn (self, "failed to power down modem before attach APN settings update: %s", error->message);
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
mm_obj_dbg (self, "success toggling modem power down before attach APN");
|
||||
|
||||
parent_set_initial_eps_bearer_settings (task);
|
||||
}
|
||||
|
||||
void
|
||||
mm_shared_fibocom_set_initial_eps_bearer_settings (MMIfaceModem3gpp *self,
|
||||
MMBearerProperties *config,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
SetInitialEpsBearerSettingsContext *ctx;
|
||||
GTask *task;
|
||||
MMPortMbim *port;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
/* This shared logic is only expected in MBIM capable devices */
|
||||
g_assert (MM_IS_BROADBAND_MODEM_MBIM (self));
|
||||
port = mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (self));
|
||||
if (!port) {
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"No valid MBIM port found");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_slice_new0 (SetInitialEpsBearerSettingsContext);
|
||||
ctx->config = g_object_ref (config);
|
||||
ctx->initial_eps_off_on = mm_kernel_device_get_property_as_boolean (mm_port_peek_kernel_device (MM_PORT (port)), "ID_MM_FIBOCOM_INITIAL_EPS_OFF_ON");
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)set_initial_eps_bearer_settings_context_free);
|
||||
|
||||
if (ctx->initial_eps_off_on) {
|
||||
mm_obj_dbg (self, "toggle modem power down before attach APN");
|
||||
mm_iface_modem_set_power_state (MM_IFACE_MODEM (self),
|
||||
MM_MODEM_POWER_STATE_LOW,
|
||||
(GAsyncReadyCallback) before_attach_apn_modem_power_down_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
parent_set_initial_eps_bearer_settings (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
shared_fibocom_init (gpointer g_iface)
|
||||
{
|
||||
}
|
||||
|
||||
GType
|
||||
mm_shared_fibocom_get_type (void)
|
||||
{
|
||||
static GType shared_fibocom_type = 0;
|
||||
|
||||
if (!G_UNLIKELY (shared_fibocom_type)) {
|
||||
static const GTypeInfo info = {
|
||||
sizeof (MMSharedFibocom), /* class_size */
|
||||
shared_fibocom_init, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
};
|
||||
|
||||
shared_fibocom_type = g_type_register_static (G_TYPE_INTERFACE, "MMSharedFibocom", &info, 0);
|
||||
g_type_interface_add_prerequisite (shared_fibocom_type, MM_TYPE_IFACE_MODEM);
|
||||
g_type_interface_add_prerequisite (shared_fibocom_type, MM_TYPE_IFACE_MODEM_3GPP);
|
||||
}
|
||||
|
||||
return shared_fibocom_type;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* -*- 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) 2022 Fibocom Wireless Inc.
|
||||
*/
|
||||
|
||||
#ifndef MM_SHARED_FIBOCOM_H
|
||||
#define MM_SHARED_FIBOCOM_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-iface-modem-3gpp.h"
|
||||
#include "mm-iface-modem.h"
|
||||
|
||||
#define MM_TYPE_SHARED_FIBOCOM (mm_shared_fibocom_get_type ())
|
||||
#define MM_SHARED_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SHARED_FIBOCOM, MMSharedFibocom))
|
||||
#define MM_IS_SHARED_FIBOCOM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SHARED_FIBOCOM))
|
||||
#define MM_SHARED_FIBOCOM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_SHARED_FIBOCOM, MMSharedFibocom))
|
||||
|
||||
typedef struct _MMSharedFibocom MMSharedFibocom;
|
||||
|
||||
struct _MMSharedFibocom {
|
||||
GTypeInterface g_iface;
|
||||
|
||||
/* Peek 3GPP interface of the parent class of the object */
|
||||
MMIfaceModem3gpp * (* peek_parent_3gpp_interface) (MMSharedFibocom *self);
|
||||
};
|
||||
|
||||
GType mm_shared_fibocom_get_type (void);
|
||||
|
||||
void mm_shared_fibocom_set_initial_eps_bearer_settings (MMIfaceModem3gpp *self,
|
||||
MMBearerProperties *config,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_shared_fibocom_set_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_SHARED_FIBOCOM_H */
|
||||
@@ -0,0 +1,20 @@
|
||||
/* -*- 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) 2022 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include "mm-shared.h"
|
||||
|
||||
MM_SHARED_DEFINE_MAJOR_VERSION
|
||||
MM_SHARED_DEFINE_MINOR_VERSION
|
||||
MM_SHARED_DEFINE_NAME(Intel)
|
||||
@@ -0,0 +1,26 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION!="add|change|move|bind", GOTO="mm_foxconn_port_types_end"
|
||||
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0489", GOTO="mm_foxconn_vendorcheck"
|
||||
GOTO="mm_foxconn_port_types_end"
|
||||
|
||||
LABEL="mm_foxconn_vendorcheck"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
|
||||
|
||||
# Foxconn T77w968 (default 0xe0b4, with esim support 0xe0b5)
|
||||
# if 02: primary port
|
||||
# if 03: secondary port
|
||||
# if 04: raw NMEA port
|
||||
# if 05: diag/qcdm port
|
||||
ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b4", ENV{.MM_USBIFNUM}=="05", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
ATTRS{idVendor}=="0489", ATTRS{idProduct}=="e0b5", ENV{.MM_USBIFNUM}=="05", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1"
|
||||
|
||||
GOTO="mm_foxconn_port_types_end"
|
||||
LABEL="mm_foxconn_port_types_end"
|
||||
@@ -0,0 +1,612 @@
|
||||
/* -*- 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) 2018-2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-errors-types.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-location.h"
|
||||
#include "mm-broadband-modem-mbim-foxconn.h"
|
||||
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
# include "mm-iface-modem-firmware.h"
|
||||
# include "mm-shared-qmi.h"
|
||||
# include "mm-log.h"
|
||||
#endif
|
||||
|
||||
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
||||
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
|
||||
#endif
|
||||
|
||||
static MMIfaceModemLocation *iface_modem_location_parent;
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimFoxconn, mm_broadband_modem_mbim_foxconn, MM_TYPE_BROADBAND_MODEM_MBIM, 0,
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_FIRMWARE, iface_modem_firmware_init)
|
||||
#endif
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init))
|
||||
|
||||
typedef enum {
|
||||
FEATURE_SUPPORT_UNKNOWN,
|
||||
FEATURE_NOT_SUPPORTED,
|
||||
FEATURE_SUPPORTED
|
||||
} FeatureSupport;
|
||||
|
||||
struct _MMBroadbandModemMbimFoxconnPrivate {
|
||||
FeatureSupport unmanaged_gps_support;
|
||||
};
|
||||
|
||||
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Firmware update settings
|
||||
*
|
||||
* We only support reporting firmware update settings when QMI support is built,
|
||||
* because this is the only clean way to get the expected firmware version to
|
||||
* report.
|
||||
*/
|
||||
|
||||
static MMFirmwareUpdateSettings *
|
||||
firmware_load_update_settings_finish (MMIfaceModemFirmware *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
needs_qdu_and_mcfg_apps_version (MMIfaceModemFirmware *self)
|
||||
{
|
||||
guint vendor_id;
|
||||
guint product_id;
|
||||
|
||||
/* 0x105b is the T99W175 module, T99W175 supports QDU and requires MCFG+APPS version.
|
||||
* T99W265(0x0489:0xe0da ; 0x0489:0xe0db): supports QDU and requires MCFG+APPS version.
|
||||
* else support FASTBOOT and QMI PDC, and require only MCFG version.
|
||||
*/
|
||||
vendor_id = mm_base_modem_get_vendor_id (MM_BASE_MODEM (self));
|
||||
product_id = mm_base_modem_get_product_id (MM_BASE_MODEM (self));
|
||||
return (vendor_id == 0x105b || (vendor_id == 0x0489 && (product_id == 0xe0da || product_id == 0xe0db)));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Need APPS version for the development of different functions when T77W968 support FASTBOOT and QMI PDC.
|
||||
* Such as: T77W968.F1.0.0.5.2.GC.013.037 and T77W968.F1.0.0.5.2.GC.013.049, the MCFG version(T77W968.F1.0.0.5.2.GC.013) is same,
|
||||
* but the APPS version(037 and 049) is different.
|
||||
*
|
||||
* For T77W968.F1.0.0.5.2.GC.013.049, before the change, "fwupdmgr get-devices" can obtain Current version is T77W968.F1.0.0.5.2.GC.013,
|
||||
* it only include the MCFG version.
|
||||
* After add need APPS version, it shows Current version is T77W968.F1.0.0.5.2.GC.013.049, including the MCFG+APPS version.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
needs_fastboot_and_qmi_pdc_mcfg_apps_version (MMIfaceModemFirmware *self)
|
||||
{
|
||||
guint vendor_id;
|
||||
guint product_id;
|
||||
|
||||
/* T77W968(0x413c:0x81d7 ; 0x413c:0x81e0 ; 0x413c:0x81e4 ; 0x413c:0x81e6): supports FASTBOOT and QMI PDC,
|
||||
* and requires MCFG+APPS version.
|
||||
* else support FASTBOOT and QMI PDC, and require only MCFG version.
|
||||
*/
|
||||
vendor_id = mm_base_modem_get_vendor_id (MM_BASE_MODEM (self));
|
||||
product_id = mm_base_modem_get_product_id (MM_BASE_MODEM (self));
|
||||
return (vendor_id == 0x413c && (product_id == 0x81d7 || product_id == 0x81e0 || product_id == 0x81e4 || product_id == 0x81e6));
|
||||
}
|
||||
|
||||
static MMFirmwareUpdateSettings *
|
||||
create_update_settings (MMIfaceModemFirmware *self,
|
||||
const gchar *version_str)
|
||||
{
|
||||
MMModemFirmwareUpdateMethod methods = MM_MODEM_FIRMWARE_UPDATE_METHOD_NONE;
|
||||
MMFirmwareUpdateSettings *update_settings = NULL;
|
||||
|
||||
if (needs_qdu_and_mcfg_apps_version (self))
|
||||
methods = MM_MODEM_FIRMWARE_UPDATE_METHOD_MBIM_QDU;
|
||||
else
|
||||
methods = MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT | MM_MODEM_FIRMWARE_UPDATE_METHOD_QMI_PDC;
|
||||
|
||||
update_settings = mm_firmware_update_settings_new (methods);
|
||||
if (methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT)
|
||||
mm_firmware_update_settings_set_fastboot_at (update_settings, "AT^FASTBOOT");
|
||||
mm_firmware_update_settings_set_version (update_settings, version_str);
|
||||
return update_settings;
|
||||
}
|
||||
|
||||
static void
|
||||
dms_foxconn_get_firmware_version_ready (QmiClientDms *client,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
g_autoptr(QmiMessageDmsFoxconnGetFirmwareVersionOutput) output = NULL;
|
||||
GError *error = NULL;
|
||||
const gchar *str;
|
||||
|
||||
output = qmi_client_dms_foxconn_get_firmware_version_finish (client, res, &error);
|
||||
if (!output || !qmi_message_dms_foxconn_get_firmware_version_output_get_result (output, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_message_dms_foxconn_get_firmware_version_output_get_version (output, &str, NULL);
|
||||
|
||||
g_task_return_pointer (task,
|
||||
create_update_settings (g_task_get_source_object (task), str),
|
||||
g_object_unref);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
fox_get_firmware_version_ready (QmiClientFox *client,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
g_autoptr(QmiMessageFoxGetFirmwareVersionOutput) output = NULL;
|
||||
GError *error = NULL;
|
||||
const gchar *str;
|
||||
|
||||
output = qmi_client_fox_get_firmware_version_finish (client, res, &error);
|
||||
if (!output || !qmi_message_fox_get_firmware_version_output_get_result (output, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
qmi_message_fox_get_firmware_version_output_get_version (output, &str, NULL);
|
||||
|
||||
g_task_return_pointer (task,
|
||||
create_update_settings (g_task_get_source_object (task), str),
|
||||
g_object_unref);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
mbim_port_allocate_qmi_client_ready (MMPortMbim *mbim,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMIfaceModemFirmware *self;
|
||||
QmiClient *fox_client = NULL;
|
||||
QmiClient *dms_client = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
if (!mm_port_mbim_allocate_qmi_client_finish (mbim, res, &error))
|
||||
mm_obj_dbg (self, "Allocate FOX client failed: %s", error->message);
|
||||
|
||||
/* Try to get firmware version over fox service, if it failed to peek client, try dms service. */
|
||||
fox_client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), QMI_SERVICE_FOX, MM_PORT_QMI_FLAG_DEFAULT, NULL);
|
||||
if (!fox_client) {
|
||||
dms_client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), QMI_SERVICE_DMS, MM_PORT_QMI_FLAG_DEFAULT, NULL);
|
||||
if (!dms_client) {
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Unable to load version info: no FOX or DMS client available");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fox_client) {
|
||||
g_autoptr(QmiMessageFoxGetFirmwareVersionInput) input = NULL;
|
||||
|
||||
input = qmi_message_fox_get_firmware_version_input_new ();
|
||||
qmi_message_fox_get_firmware_version_input_set_version_type (input,
|
||||
(needs_qdu_and_mcfg_apps_version (self) ?
|
||||
QMI_FOX_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG_APPS :
|
||||
QMI_FOX_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG),
|
||||
NULL);
|
||||
qmi_client_fox_get_firmware_version (QMI_CLIENT_FOX (fox_client),
|
||||
input,
|
||||
10,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)fox_get_firmware_version_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dms_client) {
|
||||
g_autoptr(QmiMessageDmsFoxconnGetFirmwareVersionInput) input = NULL;
|
||||
|
||||
input = qmi_message_dms_foxconn_get_firmware_version_input_new ();
|
||||
qmi_message_dms_foxconn_get_firmware_version_input_set_version_type (input,
|
||||
((needs_qdu_and_mcfg_apps_version (self) || needs_fastboot_and_qmi_pdc_mcfg_apps_version (self)) ?
|
||||
QMI_DMS_FOXCONN_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG_APPS:
|
||||
QMI_DMS_FOXCONN_FIRMWARE_VERSION_TYPE_FIRMWARE_MCFG),
|
||||
NULL);
|
||||
qmi_client_dms_foxconn_get_firmware_version (QMI_CLIENT_DMS (dms_client),
|
||||
input,
|
||||
10,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)dms_foxconn_get_firmware_version_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
firmware_load_update_settings (MMIfaceModemFirmware *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
MMPortMbim *mbim;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
mbim = mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (self));
|
||||
mm_port_mbim_allocate_qmi_client (mbim,
|
||||
QMI_SERVICE_FOX,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)mbim_port_allocate_qmi_client_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Location capabilities loading (Location interface) */
|
||||
|
||||
static MMModemLocationSource
|
||||
location_load_capabilities_finish (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
GError *inner_error = NULL;
|
||||
gssize value;
|
||||
|
||||
value = g_task_propagate_int (G_TASK (res), &inner_error);
|
||||
if (inner_error) {
|
||||
g_propagate_error (error, inner_error);
|
||||
return MM_MODEM_LOCATION_SOURCE_NONE;
|
||||
}
|
||||
return (MMModemLocationSource)value;
|
||||
}
|
||||
|
||||
static void
|
||||
custom_location_load_capabilities (GTask *task,
|
||||
MMModemLocationSource sources)
|
||||
{
|
||||
MMBroadbandModemMbimFoxconn *self;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
/* If we have a GPS port and an AT port, enable unmanaged GPS support */
|
||||
if (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)) &&
|
||||
mm_base_modem_peek_port_gps (MM_BASE_MODEM (self))) {
|
||||
self->priv->unmanaged_gps_support = FEATURE_SUPPORTED;
|
||||
sources |= MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED;
|
||||
}
|
||||
|
||||
/* So we're done, complete */
|
||||
g_task_return_int (task, sources);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_load_capabilities_ready (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMModemLocationSource sources;
|
||||
GError *error = NULL;
|
||||
|
||||
sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error);
|
||||
if (error) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
custom_location_load_capabilities (task, sources);
|
||||
}
|
||||
|
||||
static void
|
||||
location_load_capabilities (MMIfaceModemLocation *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
/* Chain up parent's setup, if any. If MM is built without QMI support,
|
||||
* the MBIM modem won't have any location capabilities. */
|
||||
if (iface_modem_location_parent &&
|
||||
iface_modem_location_parent->load_capabilities &&
|
||||
iface_modem_location_parent->load_capabilities_finish) {
|
||||
iface_modem_location_parent->load_capabilities (self,
|
||||
(GAsyncReadyCallback)parent_load_capabilities_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
custom_location_load_capabilities (task, MM_MODEM_LOCATION_SOURCE_NONE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Disable location gathering (Location interface) */
|
||||
|
||||
static gboolean
|
||||
disable_location_gathering_finish (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_disable_location_gathering_ready (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!iface_modem_location_parent->disable_location_gathering_finish (self, res, &error))
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_disable_location_gathering (GTask *task)
|
||||
{
|
||||
MMIfaceModemLocation *self;
|
||||
MMModemLocationSource source;
|
||||
|
||||
self = MM_IFACE_MODEM_LOCATION (g_task_get_source_object (task));
|
||||
source = GPOINTER_TO_UINT (g_task_get_task_data (task));
|
||||
|
||||
if (iface_modem_location_parent &&
|
||||
iface_modem_location_parent->disable_location_gathering &&
|
||||
iface_modem_location_parent->disable_location_gathering_finish) {
|
||||
iface_modem_location_parent->disable_location_gathering (
|
||||
self,
|
||||
source,
|
||||
(GAsyncReadyCallback)parent_disable_location_gathering_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
unmanaged_gps_disabled_ready (MMBaseModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_base_modem_at_command_finish (self, res, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
parent_disable_location_gathering (task);
|
||||
}
|
||||
|
||||
static void
|
||||
disable_location_gathering (MMIfaceModemLocation *_self,
|
||||
MMModemLocationSource source,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandModemMbimFoxconn *self = MM_BROADBAND_MODEM_MBIM_FOXCONN (_self);
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, GUINT_TO_POINTER (source), NULL);
|
||||
|
||||
/* We only support Unmanaged GPS at this level */
|
||||
if ((self->priv->unmanaged_gps_support != FEATURE_SUPPORTED) ||
|
||||
(source != MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) {
|
||||
parent_disable_location_gathering (task);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (_self),
|
||||
"^NV=30007,01,\"00\"",
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)unmanaged_gps_disabled_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Enable location gathering (Location interface) */
|
||||
|
||||
static gboolean
|
||||
enable_location_gathering_finish (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
unmanaged_gps_enabled_ready (MMBaseModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_base_modem_at_command_finish (self, res, &error))
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
custom_enable_location_gathering (GTask *task)
|
||||
{
|
||||
MMBroadbandModemMbimFoxconn *self;
|
||||
MMModemLocationSource source;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
source = GPOINTER_TO_UINT (g_task_get_task_data (task));
|
||||
|
||||
/* We only support Unmanaged GPS at this level */
|
||||
if ((self->priv->unmanaged_gps_support != FEATURE_SUPPORTED) ||
|
||||
(source != MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) {
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"^NV=30007,01,\"01\"",
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)unmanaged_gps_enabled_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_enable_location_gathering_ready (MMIfaceModemLocation *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!iface_modem_location_parent->enable_location_gathering_finish (self, res, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
custom_enable_location_gathering (task);
|
||||
}
|
||||
|
||||
static void
|
||||
enable_location_gathering (MMIfaceModemLocation *self,
|
||||
MMModemLocationSource source,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, GUINT_TO_POINTER (source), NULL);
|
||||
|
||||
/* Chain up parent's gathering enable */
|
||||
if (iface_modem_location_parent &&
|
||||
iface_modem_location_parent->enable_location_gathering &&
|
||||
iface_modem_location_parent->enable_location_gathering_finish) {
|
||||
iface_modem_location_parent->enable_location_gathering (
|
||||
self,
|
||||
source,
|
||||
(GAsyncReadyCallback)parent_enable_location_gathering_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
custom_enable_location_gathering (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBroadbandModemMbimFoxconn *
|
||||
mm_broadband_modem_mbim_foxconn_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
const gchar *carrier_config_mapping = NULL;
|
||||
|
||||
/* T77W968 (DW5821e/DW5829e is also T77W968) modules use t77w968 carrier mapping table. */
|
||||
if ((vendor_id == 0x0489 && (product_id == 0xe0b4 || product_id == 0xe0b5)) ||
|
||||
(vendor_id == 0x413c && (product_id == 0x81d7 || product_id == 0x81e0 || product_id == 0x81e4 || product_id == 0x81e6)))
|
||||
carrier_config_mapping = PKGDATADIR "/mm-foxconn-t77w968-carrier-mapping.conf";
|
||||
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN,
|
||||
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,
|
||||
/* MBIM bearer supports NET only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
|
||||
MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, TRUE,
|
||||
MM_IFACE_MODEM_LOCATION_ALLOW_GPS_UNMANAGED_ALWAYS, TRUE,
|
||||
MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING, carrier_config_mapping,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_foxconn_init (MMBroadbandModemMbimFoxconn *self)
|
||||
{
|
||||
/* Initialize private data */
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN, MMBroadbandModemMbimFoxconnPrivate);
|
||||
self->priv->unmanaged_gps_support = FEATURE_SUPPORT_UNKNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_location_init (MMIfaceModemLocation *iface)
|
||||
{
|
||||
iface_modem_location_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->load_capabilities = location_load_capabilities;
|
||||
iface->load_capabilities_finish = location_load_capabilities_finish;
|
||||
iface->enable_location_gathering = enable_location_gathering;
|
||||
iface->enable_location_gathering_finish = enable_location_gathering_finish;
|
||||
iface->disable_location_gathering = disable_location_gathering;
|
||||
iface->disable_location_gathering_finish = disable_location_gathering_finish;
|
||||
}
|
||||
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
|
||||
static void
|
||||
iface_modem_firmware_init (MMIfaceModemFirmware *iface)
|
||||
{
|
||||
iface->load_update_settings = firmware_load_update_settings;
|
||||
iface->load_update_settings_finish = firmware_load_update_settings_finish;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_foxconn_class_init (MMBroadbandModemMbimFoxconnClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (MMBroadbandModemMbimFoxconnPrivate));
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* -*- 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) 2018-2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_MBIM_FOXCONN_H
|
||||
#define MM_BROADBAND_MODEM_MBIM_FOXCONN_H
|
||||
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN (mm_broadband_modem_mbim_foxconn_get_type ())
|
||||
#define MM_BROADBAND_MODEM_MBIM_FOXCONN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN, MMBroadbandModemMbimFoxconn))
|
||||
#define MM_BROADBAND_MODEM_MBIM_FOXCONN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN, MMBroadbandModemMbimFoxconnClass))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_FOXCONN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_FOXCONN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN))
|
||||
#define MM_BROADBAND_MODEM_MBIM_FOXCONN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_FOXCONN, MMBroadbandModemMbimFoxconnClass))
|
||||
|
||||
typedef struct _MMBroadbandModemMbimFoxconn MMBroadbandModemMbimFoxconn;
|
||||
typedef struct _MMBroadbandModemMbimFoxconnClass MMBroadbandModemMbimFoxconnClass;
|
||||
typedef struct _MMBroadbandModemMbimFoxconnPrivate MMBroadbandModemMbimFoxconnPrivate;
|
||||
|
||||
struct _MMBroadbandModemMbimFoxconn {
|
||||
MMBroadbandModemMbim parent;
|
||||
MMBroadbandModemMbimFoxconnPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemMbimFoxconnClass{
|
||||
MMBroadbandModemMbimClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_mbim_foxconn_get_type (void);
|
||||
|
||||
MMBroadbandModemMbimFoxconn *mm_broadband_modem_mbim_foxconn_new (const gchar *device,
|
||||
const gchar **driver,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_MBIM_FOXCONN_H */
|
||||
@@ -0,0 +1,319 @@
|
||||
|
||||
#
|
||||
# T77W968 carrier mapping table
|
||||
#
|
||||
# This table maps the MCCMNC of the SIM card with the corresponding
|
||||
# configuration description as reported by the QMI PDC service in
|
||||
# this module.
|
||||
#
|
||||
|
||||
[foxconn t77w968]
|
||||
|
||||
# AT&T
|
||||
302220=ATT
|
||||
302221=ATT
|
||||
31030=ATT
|
||||
31070=ATT
|
||||
31090=ATT
|
||||
310150=ATT
|
||||
310170=ATT
|
||||
310280=ATT
|
||||
310380=ATT
|
||||
310410=ATT
|
||||
310560=ATT
|
||||
310650=ATT
|
||||
310680=ATT
|
||||
310980=ATT
|
||||
311180=ATT
|
||||
90118=ATT
|
||||
|
||||
# FirstNet
|
||||
312670=A2
|
||||
313100=A2
|
||||
313110=A2
|
||||
313120=A2
|
||||
313130=A2
|
||||
313140=A2
|
||||
|
||||
# Verizon
|
||||
310590=Verizon
|
||||
310890=Verizon
|
||||
311270=Verizon
|
||||
311480=Verizon
|
||||
312770=Verizon
|
||||
|
||||
# Vodafone
|
||||
20205=Vodafone
|
||||
20404=Vodafone
|
||||
20601=Vodafone
|
||||
20810=Vodafone
|
||||
21401=Vodafone
|
||||
21670=Vodafone
|
||||
21910=Vodafone
|
||||
22005=Vodafone
|
||||
22210=Vodafone
|
||||
22601=Vodafone
|
||||
23003=Vodafone
|
||||
23201=Vodafone
|
||||
23415=Vodafone
|
||||
23801=Vodafone
|
||||
24405=Vodafone
|
||||
24602=Vodafone
|
||||
24705=Vodafone
|
||||
24802=Vodafone
|
||||
25001=Vodafone
|
||||
26202=Vodafone
|
||||
26209=Vodafone
|
||||
26801=Vodafone
|
||||
27077=Vodafone
|
||||
27201=Vodafone
|
||||
27402=Vodafone
|
||||
27602=Vodafone
|
||||
27801=Vodafone
|
||||
28001=Vodafone
|
||||
28401=Vodafone
|
||||
28602=Vodafone
|
||||
28802=Vodafone
|
||||
29340=Vodafone
|
||||
29403=Vodafone
|
||||
40004=Vodafone
|
||||
40401=Vodafone
|
||||
40405=Vodafone
|
||||
40411=Vodafone
|
||||
40413=Vodafone
|
||||
40415=Vodafone
|
||||
40420=Vodafone
|
||||
40427=Vodafone
|
||||
40430=Vodafone
|
||||
40443=Vodafone
|
||||
40446=Vodafone
|
||||
40460=Vodafone
|
||||
40484=Vodafone
|
||||
40486=Vodafone
|
||||
40488=Vodafone
|
||||
40566=Vodafone
|
||||
40567=Vodafone
|
||||
405750=Vodafone
|
||||
405751=Vodafone
|
||||
405752=Vodafone
|
||||
405753=Vodafone
|
||||
405754=Vodafone
|
||||
405755=Vodafone
|
||||
405756=Vodafone
|
||||
41302=Vodafone
|
||||
42403=Vodafone
|
||||
42602=Vodafone
|
||||
42702=Vodafone
|
||||
46601=Vodafone
|
||||
46603=Vodafone
|
||||
50213=Vodafone
|
||||
50219=Vodafone
|
||||
50503=Vodafone
|
||||
52503=Vodafone
|
||||
52505=Vodafone
|
||||
53001=Vodafone
|
||||
54201=Vodafone
|
||||
60202=Vodafone
|
||||
62002=Vodafone
|
||||
63001=Vodafone
|
||||
63902=Vodafone
|
||||
64004=Vodafone
|
||||
64304=Vodafone
|
||||
64710=Vodafone
|
||||
65101=Vodafone
|
||||
65501=Vodafone
|
||||
73001=Vodafone
|
||||
90128=Vodafone
|
||||
|
||||
# Orange
|
||||
20610=Orange
|
||||
20801=Orange
|
||||
20802=Orange
|
||||
21403=Orange
|
||||
21409=Orange
|
||||
22610=Orange
|
||||
23101=Orange
|
||||
23105=Orange
|
||||
23430=Orange
|
||||
23433=Orange
|
||||
23434=Orange
|
||||
25901=Orange
|
||||
26003=Orange
|
||||
26005=Orange
|
||||
27099=Orange
|
||||
28310=Orange
|
||||
|
||||
# Telefonica Movistar
|
||||
21405=Telefonica
|
||||
21407=Telefonica
|
||||
|
||||
# Swisscom
|
||||
22801=Swisscom
|
||||
29501=Swisscom
|
||||
|
||||
# Telstra
|
||||
50501=Telstra
|
||||
50506=Telstra
|
||||
50571=Telstra
|
||||
50572=Telstra
|
||||
|
||||
# Sprint
|
||||
310120=Sprint
|
||||
|
||||
# Optus
|
||||
50202=Optus
|
||||
|
||||
# NTT DoCoMo
|
||||
44002=Docomo
|
||||
44003=Docomo
|
||||
44009=Docomo
|
||||
44010=Docomo
|
||||
44011=Docomo
|
||||
44012=Docomo
|
||||
44013=Docomo
|
||||
44014=Docomo
|
||||
44015=Docomo
|
||||
44016=Docomo
|
||||
44017=Docomo
|
||||
44018=Docomo
|
||||
44019=Docomo
|
||||
44022=Docomo
|
||||
44023=Docomo
|
||||
44024=Docomo
|
||||
44025=Docomo
|
||||
44026=Docomo
|
||||
44027=Docomo
|
||||
44028=Docomo
|
||||
44029=Docomo
|
||||
44030=Docomo
|
||||
44031=Docomo
|
||||
44032=Docomo
|
||||
44033=Docomo
|
||||
44034=Docomo
|
||||
44035=Docomo
|
||||
44036=Docomo
|
||||
44037=Docomo
|
||||
44038=Docomo
|
||||
44039=Docomo
|
||||
44049=Docomo
|
||||
44058=Docomo
|
||||
44060=Docomo
|
||||
44061=Docomo
|
||||
44062=Docomo
|
||||
44063=Docomo
|
||||
44064=Docomo
|
||||
44065=Docomo
|
||||
44066=Docomo
|
||||
44067=Docomo
|
||||
44068=Docomo
|
||||
44069=Docomo
|
||||
44087=Docomo
|
||||
44099=Docomo
|
||||
44140=Docomo
|
||||
44141=Docomo
|
||||
44142=Docomo
|
||||
44143=Docomo
|
||||
44144=Docomo
|
||||
44145=Docomo
|
||||
44190=Docomo
|
||||
44101=Docomo
|
||||
44192=Docomo
|
||||
44193=Docomo
|
||||
44194=Docomo
|
||||
44198=Docomo
|
||||
44199=Docomo
|
||||
|
||||
# KDDI
|
||||
44007=KDDI
|
||||
44008=KDDI
|
||||
44050=KDDI
|
||||
44051=KDDI
|
||||
44052=KDDI
|
||||
44053=KDDI
|
||||
44054=KDDI
|
||||
44055=KDDI
|
||||
44056=KDDI
|
||||
44070=KDDI
|
||||
44071=KDDI
|
||||
44072=KDDI
|
||||
44073=KDDI
|
||||
44074=KDDI
|
||||
44075=KDDI
|
||||
44076=KDDI
|
||||
44077=KDDI
|
||||
44078=KDDI
|
||||
44079=KDDI
|
||||
44080=KDDI
|
||||
44081=KDDI
|
||||
44082=KDDI
|
||||
44083=KDDI
|
||||
44084=KDDI
|
||||
44085=KDDI
|
||||
44086=KDDI
|
||||
44088=KDDI
|
||||
44089=KDDI
|
||||
44150=KDDI
|
||||
44151=KDDI
|
||||
44170=KDDI
|
||||
|
||||
# SoftBank
|
||||
44000=SBM
|
||||
44004=SBM
|
||||
44006=SBM
|
||||
44020=SBM
|
||||
44021=SBM
|
||||
44040=SBM
|
||||
44041=SBM
|
||||
44042=SBM
|
||||
44043=SBM
|
||||
44044=SBM
|
||||
44045=SBM
|
||||
44046=SBM
|
||||
44047=SBM
|
||||
44048=SBM
|
||||
44090=SBM
|
||||
44092=SBM
|
||||
44093=SBM
|
||||
44094=SBM
|
||||
44095=SBM
|
||||
44096=SBM
|
||||
44097=SBM
|
||||
44098=SBM
|
||||
44101=SBM
|
||||
44161=SBM
|
||||
44162=SBM
|
||||
44163=SBM
|
||||
44164=SBM
|
||||
44165=SBM
|
||||
|
||||
# EE UK
|
||||
23430=EE
|
||||
23431=EE
|
||||
23432=EE
|
||||
23433=EE
|
||||
23434=EE
|
||||
23476=EE
|
||||
23501=EE
|
||||
23502=EE
|
||||
23577=EE
|
||||
|
||||
# Deutsche Telekom
|
||||
20201=DT
|
||||
20416=DT
|
||||
20420=DT
|
||||
21630=DT
|
||||
21901=DT
|
||||
22603=DT
|
||||
22606=DT
|
||||
23001=DT
|
||||
23102=DT
|
||||
23203=DT
|
||||
23207=DT
|
||||
26002=DT
|
||||
26201=DT
|
||||
27601=DT
|
||||
29401=DT
|
||||
29702=DT
|
||||
|
||||
# Others
|
||||
generic=GCF
|
||||
@@ -0,0 +1,121 @@
|
||||
/* -*- 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) 2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-plugin-foxconn.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
#include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
#include "mm-broadband-modem-mbim-foxconn.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginFoxconn, mm_plugin_foxconn, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered Foxconn-branded modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
if (mm_port_probe_list_has_mbim_port (probes)) {
|
||||
mm_obj_dbg (self, "MBIM-powered Foxconn-branded modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_foxconn_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
mm_obj_dbg (self, "Foxconn-branded generic modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", "wwan", NULL };
|
||||
static const guint16 vendor_ids[] = {
|
||||
0x0489, /* usb vid */
|
||||
0x105b, /* pci vid */
|
||||
0 };
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_FOXCONN,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QCDM, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
MM_PLUGIN_ALLOWED_MBIM, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_foxconn_init (MMPluginFoxconn *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_foxconn_class_init (MMPluginFoxconnClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* -*- 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) 2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_FOXCONN_H
|
||||
#define MM_PLUGIN_FOXCONN_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_FOXCONN (mm_plugin_foxconn_get_type ())
|
||||
#define MM_PLUGIN_FOXCONN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_FOXCONN, MMPluginFoxconn))
|
||||
#define MM_PLUGIN_FOXCONN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_FOXCONN, MMPluginFoxconnClass))
|
||||
#define MM_IS_PLUGIN_FOXCONN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_FOXCONN))
|
||||
#define MM_IS_PLUGIN_FOXCONN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_FOXCONN))
|
||||
#define MM_PLUGIN_FOXCONN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_FOXCONN, MMPluginFoxconnClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginFoxconn;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginFoxconnClass;
|
||||
|
||||
GType mm_plugin_foxconn_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_FOXCONN_H */
|
||||
@@ -0,0 +1,20 @@
|
||||
/* -*- 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) 2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include "mm-shared.h"
|
||||
|
||||
MM_SHARED_DEFINE_MAJOR_VERSION
|
||||
MM_SHARED_DEFINE_MINOR_VERSION
|
||||
MM_SHARED_DEFINE_NAME(Foxconn)
|
||||
@@ -0,0 +1,120 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2010 Dan Williams <dcbw@redhat.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-plugin-generic.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-serial-parsers.h"
|
||||
#include "mm-log-object.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
#include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginGeneric, mm_plugin_generic, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered generic modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
if (mm_port_probe_list_has_mbim_port (probes)) {
|
||||
mm_obj_dbg (self, "MBIM-powered generic modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", "wwan", NULL };
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_GENERIC,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_IS_GENERIC, TRUE,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_REQUIRED_QCDM, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
MM_PLUGIN_ALLOWED_MBIM, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_generic_init (MMPluginGeneric *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_generic_class_init (MMPluginGenericClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -*- 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) 2009 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_GENERIC_H
|
||||
#define MM_PLUGIN_GENERIC_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_GENERIC (mm_plugin_generic_get_type ())
|
||||
#define MM_PLUGIN_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_GENERIC, MMPluginGeneric))
|
||||
#define MM_PLUGIN_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_GENERIC, MMPluginGenericClass))
|
||||
#define MM_IS_PLUGIN_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_GENERIC))
|
||||
#define MM_IS_PLUGIN_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_GENERIC))
|
||||
#define MM_PLUGIN_GENERIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_GENERIC, MMPluginGenericClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginGeneric;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginGenericClass;
|
||||
|
||||
GType mm_plugin_generic_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_GENERIC_H */
|
||||
@@ -0,0 +1,90 @@
|
||||
/* -*- 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) 2016 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "test-port-context.h"
|
||||
#include "test-fixture.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_enable_disable (TestFixture *fixture)
|
||||
{
|
||||
GError *error = NULL;
|
||||
MMObject *obj;
|
||||
MMModem *modem;
|
||||
TestPortContext *port0;
|
||||
gchar *ports [] = { NULL, NULL };
|
||||
|
||||
/* Create port name, and add process ID so that multiple runs of this test
|
||||
* in the same system don't clash with each other */
|
||||
ports[0] = g_strdup_printf ("abstract:port0:%ld", (glong) getpid ());
|
||||
g_debug ("test service generic: using abstract port at '%s'", ports[0]);
|
||||
|
||||
/* Setup new port context */
|
||||
port0 = test_port_context_new (ports[0]);
|
||||
test_port_context_load_commands (port0, COMMON_GSM_PORT_CONF);
|
||||
test_port_context_start (port0);
|
||||
|
||||
/* Ensure no modem is modem exported */
|
||||
test_fixture_no_modem (fixture);
|
||||
|
||||
/* Set the test profile */
|
||||
test_fixture_set_profile (fixture,
|
||||
"test-enable-disable",
|
||||
"generic",
|
||||
(const gchar *const *)ports);
|
||||
|
||||
/* Wait and get the modem object */
|
||||
obj = test_fixture_get_modem (fixture);
|
||||
|
||||
/* Get Modem interface, and enable */
|
||||
modem = mm_object_get_modem (obj);
|
||||
g_assert (modem != NULL);
|
||||
mm_modem_enable_sync (modem, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
/* And disable */
|
||||
mm_modem_disable_sync (modem, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_object_unref (modem);
|
||||
g_object_unref (obj);
|
||||
|
||||
/* Stop port context */
|
||||
test_port_context_stop (port0);
|
||||
test_port_context_free (port0);
|
||||
|
||||
g_free (ports[0]);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
TEST_ADD ("/MM/Service/Generic/enable-disable", test_enable_disable);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION!="add|change|move|bind", GOTO="mm_gosuncn_port_types_end"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="305a", GOTO="mm_gosuncn_port_types"
|
||||
GOTO="mm_gosuncn_port_types_end"
|
||||
|
||||
LABEL="mm_gosuncn_port_types"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
|
||||
|
||||
# Gosuncn GM800
|
||||
# Interfaces #3 and #4 are MBIM
|
||||
ATTRS{idVendor}=="305a", ATTRS{idProduct}=="1405", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
ATTRS{idVendor}=="305a", ATTRS{idProduct}=="1405", ENV{.MM_USBIFNUM}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
ATTRS{idVendor}=="305a", ATTRS{idProduct}=="1405", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
|
||||
ATTRS{idVendor}=="305a", ATTRS{idProduct}=="1405", ENV{.MM_USBIFNUM}=="05", ENV{ID_MM_PORT_IGNORE}="1"
|
||||
|
||||
LABEL="mm_gosuncn_port_types_end"
|
||||
@@ -0,0 +1,114 @@
|
||||
/* -*- 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) 2020 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-plugin-gosuncn.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
# include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
# include "mm-broadband-modem-mbim.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginGosuncn, mm_plugin_gosuncn, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered Gosuncn modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
if (mm_port_probe_list_has_mbim_port (probes)) {
|
||||
mm_obj_dbg (self, "MBIM-powered Gosuncn modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fallback to default modem in the worst case */
|
||||
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x305a, 0 };
|
||||
static const gchar *drivers[] = { "qmi_wwan", "cdc_mbim", NULL };
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_GOSUNCN,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_DRIVERS, drivers,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QCDM, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
MM_PLUGIN_ALLOWED_MBIM, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_gosuncn_init (MMPluginGosuncn *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_gosuncn_class_init (MMPluginGosuncnClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -*- 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) 2020 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_GOSUNCN_H
|
||||
#define MM_PLUGIN_GOSUNCN_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_GOSUNCN (mm_plugin_gosuncn_get_type ())
|
||||
#define MM_PLUGIN_GOSUNCN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_GOSUNCN, MMPluginGosuncn))
|
||||
#define MM_PLUGIN_GOSUNCN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_GOSUNCN, MMPluginGosuncnClass))
|
||||
#define MM_IS_PLUGIN_GOSUNCN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_GOSUNCN))
|
||||
#define MM_IS_PLUGIN_GOSUNCN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_GOSUNCN))
|
||||
#define MM_PLUGIN_GOSUNCN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_GOSUNCN, MMPluginGosuncnClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginGosuncn;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginGosuncnClass;
|
||||
|
||||
GType mm_plugin_gosuncn_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_GOSUNCN_H */
|
||||
@@ -0,0 +1,13 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
|
||||
ACTION!="add|change|move|bind", GOTO="mm_haier_port_types_end"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="201e", GOTO="mm_haier_port_types"
|
||||
GOTO="mm_haier_port_types_end"
|
||||
|
||||
LABEL="mm_haier_port_types"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
|
||||
|
||||
# Haier CE81B
|
||||
ATTRS{idVendor}=="201e", ATTRS{idProduct}=="10f8", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
|
||||
LABEL="mm_haier_port_types_end"
|
||||
@@ -0,0 +1,76 @@
|
||||
/* -*- 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) 2014 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-plugin-haier.h"
|
||||
|
||||
G_DEFINE_TYPE (MMPluginHaier, mm_plugin_haier, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x201e, 0 };
|
||||
|
||||
return MM_PLUGIN (g_object_new (MM_TYPE_PLUGIN_HAIER,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_haier_init (MMPluginHaier *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_haier_class_init (MMPluginHaierClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -*- 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) 2014 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_HAIER_H
|
||||
#define MM_PLUGIN_HAIER_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_HAIER (mm_plugin_haier_get_type ())
|
||||
#define MM_PLUGIN_HAIER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_HAIER, MMPluginHaier))
|
||||
#define MM_PLUGIN_HAIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_HAIER, MMPluginHaierClass))
|
||||
#define MM_IS_PLUGIN_HAIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_HAIER))
|
||||
#define MM_IS_PLUGIN_HAIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_HAIER))
|
||||
#define MM_PLUGIN_HAIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_HAIER, MMPluginHaierClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginHaier;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginHaierClass;
|
||||
|
||||
GType mm_plugin_haier_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_HAIER_H */
|
||||
@@ -0,0 +1,37 @@
|
||||
# do not edit this file, it will be overwritten on update
|
||||
ACTION!="add|change|move|bind", GOTO="mm_huawei_port_types_end"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="12d1", GOTO="mm_huawei_port_types"
|
||||
GOTO="mm_huawei_port_types_end"
|
||||
|
||||
LABEL="mm_huawei_port_types"
|
||||
|
||||
# MU609 does not support getportmode (crashes modem with default firmware)
|
||||
ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1573", ENV{ID_MM_HUAWEI_DISABLE_GETPORTMODE}="1"
|
||||
|
||||
# Mark the modem and at port flags for ModemManager
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="01", ATTRS{bInterfaceProtocol}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PPP}="1"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="01", ATTRS{bInterfaceProtocol}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="02", ATTRS{bInterfaceProtocol}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PPP}="1"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="02", ATTRS{bInterfaceProtocol}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
|
||||
|
||||
# GPS NMEA port on MU609
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="01", ATTRS{bInterfaceProtocol}=="05", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
# GPS NMEA port on MU909
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="01", ATTRS{bInterfaceProtocol}=="14", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
# GPS NMEA port on MU906e
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="ff", ATTRS{bInterfaceSubClass}=="06", ATTRS{bInterfaceProtocol}=="14", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1"
|
||||
|
||||
# Only the standard ECM or NCM port can support dial-up with AT NDISDUP through AT port
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="02", ATTRS{bInterfaceSubClass}=="06",ATTRS{bInterfaceProtocol}=="00", ENV{ID_MM_HUAWEI_NDISDUP_SUPPORTED}="1"
|
||||
SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="02", ATTRS{bInterfaceSubClass}=="0d",ATTRS{bInterfaceProtocol}=="00", ENV{ID_MM_HUAWEI_NDISDUP_SUPPORTED}="1"
|
||||
|
||||
# Airtel branded E3372h-607, using huawei-cdc-ncm driver but with unresponsive cdc-wdm port
|
||||
ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", ENV{ID_MM_HUAWEI_NDISDUP_SUPPORTED}="1"
|
||||
|
||||
# R215, Disable CPOL based features
|
||||
ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1588", ENV{ID_MM_PREFERRED_NETWORKS_CPOL_DISABLED}="1"
|
||||
|
||||
# E226, Disable CPOL based features
|
||||
ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1003", ENV{ID_MM_PREFERRED_NETWORKS_CPOL_DISABLED}="1"
|
||||
|
||||
LABEL="mm_huawei_port_types_end"
|
||||
@@ -0,0 +1,879 @@
|
||||
/* -*- 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) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Lanedo GmbH
|
||||
* Copyright (C) 2012 Huawei Technologies Co., Ltd
|
||||
*
|
||||
* Author: Franko fang <huanahu@huawei.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>
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-broadband-bearer-huawei.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-modem-helpers-huawei.h"
|
||||
#include "mm-daemon-enums-types.h"
|
||||
|
||||
G_DEFINE_TYPE (MMBroadbandBearerHuawei, mm_broadband_bearer_huawei, MM_TYPE_BROADBAND_BEARER)
|
||||
|
||||
struct _MMBroadbandBearerHuaweiPrivate {
|
||||
gpointer connect_pending;
|
||||
gpointer disconnect_pending;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static MMPortSerialAt *
|
||||
get_dial_port (MMBroadbandModemHuawei *modem,
|
||||
MMPort *data,
|
||||
MMPortSerialAt *primary)
|
||||
{
|
||||
MMPortSerialAt *dial_port;
|
||||
|
||||
/* See if we have a cdc-wdm AT port for the interface */
|
||||
dial_port = (mm_broadband_modem_huawei_peek_port_at_for_data (
|
||||
MM_BROADBAND_MODEM_HUAWEI (modem), data));
|
||||
if (dial_port)
|
||||
return g_object_ref (dial_port);
|
||||
|
||||
/* Otherwise, fallback to using the primary port for dialing */
|
||||
return g_object_ref (primary);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Connect 3GPP */
|
||||
|
||||
typedef enum {
|
||||
CONNECT_3GPP_CONTEXT_STEP_FIRST = 0,
|
||||
CONNECT_3GPP_CONTEXT_STEP_NDISDUP,
|
||||
CONNECT_3GPP_CONTEXT_STEP_NDISSTATQRY,
|
||||
CONNECT_3GPP_CONTEXT_STEP_IP_CONFIG,
|
||||
CONNECT_3GPP_CONTEXT_STEP_LAST
|
||||
} Connect3gppContextStep;
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
MMPort *data;
|
||||
Connect3gppContextStep step;
|
||||
guint check_count;
|
||||
guint failed_ndisstatqry_count;
|
||||
MMBearerIpConfig *ipv4_config;
|
||||
} Connect3gppContext;
|
||||
|
||||
static void
|
||||
connect_3gpp_context_free (Connect3gppContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->modem);
|
||||
|
||||
g_clear_object (&ctx->ipv4_config);
|
||||
g_clear_object (&ctx->data);
|
||||
g_clear_object (&ctx->primary);
|
||||
|
||||
g_slice_free (Connect3gppContext, ctx);
|
||||
}
|
||||
|
||||
static MMBearerConnectResult *
|
||||
connect_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void connect_3gpp_context_step (GTask *task);
|
||||
|
||||
static void
|
||||
connect_dhcp_check_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
MMBroadbandBearerHuawei *self)
|
||||
{
|
||||
GTask *task;
|
||||
Connect3gppContext *ctx;
|
||||
const gchar *response;
|
||||
GError *error = NULL;
|
||||
|
||||
task = self->priv->connect_pending;
|
||||
g_assert (task != NULL);
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Balance refcount */
|
||||
g_object_unref (self);
|
||||
|
||||
/* Cache IPv4 details if available, otherwise clients will have to use DHCP */
|
||||
response = mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (response) {
|
||||
guint address = 0;
|
||||
guint prefix = 0;
|
||||
guint gateway = 0;
|
||||
guint dns1 = 0;
|
||||
guint dns2 = 0;
|
||||
|
||||
if (mm_huawei_parse_dhcp_response (response,
|
||||
&address,
|
||||
&prefix,
|
||||
&gateway,
|
||||
&dns1,
|
||||
&dns2,
|
||||
&error)) {
|
||||
GInetAddress *addr;
|
||||
gchar *strarr[3] = { NULL, NULL, NULL };
|
||||
guint n = 0;
|
||||
gchar *str;
|
||||
|
||||
mm_bearer_ip_config_set_method (ctx->ipv4_config, MM_BEARER_IP_METHOD_STATIC);
|
||||
|
||||
addr = g_inet_address_new_from_bytes ((guint8 *)&address, G_SOCKET_FAMILY_IPV4);
|
||||
str = g_inet_address_to_string (addr);
|
||||
mm_bearer_ip_config_set_address (ctx->ipv4_config, str);
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
|
||||
/* Netmask */
|
||||
mm_bearer_ip_config_set_prefix (ctx->ipv4_config, prefix);
|
||||
|
||||
/* Gateway */
|
||||
addr = g_inet_address_new_from_bytes ((guint8 *)&gateway, G_SOCKET_FAMILY_IPV4);
|
||||
str = g_inet_address_to_string (addr);
|
||||
mm_bearer_ip_config_set_gateway (ctx->ipv4_config, str);
|
||||
g_free (str);
|
||||
g_object_unref (addr);
|
||||
|
||||
/* DNS */
|
||||
if (dns1) {
|
||||
addr = g_inet_address_new_from_bytes ((guint8 *)&dns1, G_SOCKET_FAMILY_IPV4);
|
||||
strarr[n++] = g_inet_address_to_string (addr);
|
||||
g_object_unref (addr);
|
||||
}
|
||||
if (dns2) {
|
||||
addr = g_inet_address_new_from_bytes ((guint8 *)&dns2, G_SOCKET_FAMILY_IPV4);
|
||||
strarr[n++] = g_inet_address_to_string (addr);
|
||||
g_object_unref (addr);
|
||||
}
|
||||
mm_bearer_ip_config_set_dns (ctx->ipv4_config, (const gchar **)strarr);
|
||||
g_free (strarr[0]);
|
||||
g_free (strarr[1]);
|
||||
} else {
|
||||
mm_obj_dbg (self, "unexpected response to ^DHCP command: %s", error->message);
|
||||
}
|
||||
}
|
||||
|
||||
g_clear_error (&error);
|
||||
ctx->step++;
|
||||
connect_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
connect_retry_ndisstatqry_check_cb (MMBroadbandBearerHuawei *self)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
/* Recover context */
|
||||
task = self->priv->connect_pending;
|
||||
g_assert (task != NULL);
|
||||
|
||||
/* Balance refcount */
|
||||
g_object_unref (self);
|
||||
|
||||
/* Retry same step */
|
||||
connect_3gpp_context_step (task);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
connect_ndisstatqry_check_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
MMBroadbandBearerHuawei *self)
|
||||
{
|
||||
GTask *task;
|
||||
Connect3gppContext *ctx;
|
||||
const gchar *response;
|
||||
GError *error = NULL;
|
||||
gboolean ipv4_available = FALSE;
|
||||
gboolean ipv4_connected = FALSE;
|
||||
gboolean ipv6_available = FALSE;
|
||||
gboolean ipv6_connected = FALSE;
|
||||
|
||||
task = self->priv->connect_pending;
|
||||
g_assert (task != NULL);
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Balance refcount */
|
||||
g_object_unref (self);
|
||||
|
||||
response = mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (!response ||
|
||||
!mm_huawei_parse_ndisstatqry_response (response,
|
||||
&ipv4_available,
|
||||
&ipv4_connected,
|
||||
&ipv6_available,
|
||||
&ipv6_connected,
|
||||
&error)) {
|
||||
ctx->failed_ndisstatqry_count++;
|
||||
mm_obj_dbg (self, "unexpected response to ^NDISSTATQRY command: %s (%u attempts so far)",
|
||||
error->message, ctx->failed_ndisstatqry_count);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
/* Connected in IPv4? */
|
||||
if (ipv4_available && ipv4_connected) {
|
||||
/* Success! */
|
||||
ctx->step++;
|
||||
connect_3gpp_context_step (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup timeout to retry the same step */
|
||||
g_timeout_add_seconds (1,
|
||||
(GSourceFunc)connect_retry_ndisstatqry_check_cb,
|
||||
g_object_ref (self));
|
||||
}
|
||||
|
||||
static void
|
||||
connect_ndisdup_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
MMBroadbandBearerHuawei *self)
|
||||
{
|
||||
GTask *task;
|
||||
Connect3gppContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
task = self->priv->connect_pending;
|
||||
g_assert (task != NULL);
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Balance refcount */
|
||||
g_object_unref (self);
|
||||
|
||||
if (!mm_base_modem_at_command_full_finish (modem, res, &error)) {
|
||||
/* Clear task */
|
||||
self->priv->connect_pending = NULL;
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Go to next step */
|
||||
ctx->step++;
|
||||
connect_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
MM_BEARER_HUAWEI_AUTH_UNKNOWN = -1,
|
||||
MM_BEARER_HUAWEI_AUTH_NONE = 0,
|
||||
MM_BEARER_HUAWEI_AUTH_PAP = 1,
|
||||
MM_BEARER_HUAWEI_AUTH_CHAP = 2,
|
||||
MM_BEARER_HUAWEI_AUTH_MSCHAPV2 = 3,
|
||||
} MMBearerHuaweiAuthPref;
|
||||
|
||||
static gint
|
||||
huawei_parse_auth_type (MMBearerAllowedAuth mm_auth)
|
||||
{
|
||||
switch (mm_auth) {
|
||||
case MM_BEARER_ALLOWED_AUTH_NONE:
|
||||
return MM_BEARER_HUAWEI_AUTH_NONE;
|
||||
case MM_BEARER_ALLOWED_AUTH_PAP:
|
||||
return MM_BEARER_HUAWEI_AUTH_PAP;
|
||||
case MM_BEARER_ALLOWED_AUTH_CHAP:
|
||||
return MM_BEARER_HUAWEI_AUTH_CHAP;
|
||||
case MM_BEARER_ALLOWED_AUTH_MSCHAPV2:
|
||||
return MM_BEARER_HUAWEI_AUTH_MSCHAPV2;
|
||||
default:
|
||||
case MM_BEARER_ALLOWED_AUTH_UNKNOWN:
|
||||
case MM_BEARER_ALLOWED_AUTH_MSCHAP:
|
||||
case MM_BEARER_ALLOWED_AUTH_EAP:
|
||||
return MM_BEARER_HUAWEI_AUTH_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
connect_3gpp_context_step (GTask *task)
|
||||
{
|
||||
MMBroadbandBearerHuawei *self;
|
||||
Connect3gppContext *ctx;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Check for cancellation */
|
||||
if (g_cancellable_is_cancelled (g_task_get_cancellable (task))) {
|
||||
/* Clear task */
|
||||
self->priv->connect_pending = NULL;
|
||||
|
||||
/* If we already sent the connetion command, send the disconnection one */
|
||||
if (ctx->step > CONNECT_3GPP_CONTEXT_STEP_NDISDUP)
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
"^NDISDUP=1,0",
|
||||
MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
NULL, /* Do not care the AT response */
|
||||
NULL);
|
||||
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||
"Huawei connection operation has been cancelled");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ctx->step) {
|
||||
case CONNECT_3GPP_CONTEXT_STEP_FIRST: {
|
||||
MMBearerIpFamily ip_family;
|
||||
|
||||
ip_family = mm_bearer_properties_get_ip_type (mm_base_bearer_peek_config (MM_BASE_BEARER (self)));
|
||||
mm_3gpp_normalize_ip_family (&ip_family);
|
||||
if (ip_family != MM_BEARER_IP_FAMILY_IPV4) {
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_UNSUPPORTED,
|
||||
"Only IPv4 is supported by this modem");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store the task */
|
||||
self->priv->connect_pending = task;
|
||||
|
||||
ctx->step++;
|
||||
} /* fall through */
|
||||
|
||||
case CONNECT_3GPP_CONTEXT_STEP_NDISDUP: {
|
||||
const gchar *apn;
|
||||
const gchar *user;
|
||||
const gchar *passwd;
|
||||
MMBearerAllowedAuth auth;
|
||||
gint encoded_auth = MM_BEARER_HUAWEI_AUTH_UNKNOWN;
|
||||
gchar *command;
|
||||
|
||||
apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config (MM_BASE_BEARER (self)));
|
||||
user = mm_bearer_properties_get_user (mm_base_bearer_peek_config (MM_BASE_BEARER (self)));
|
||||
passwd = mm_bearer_properties_get_password (mm_base_bearer_peek_config (MM_BASE_BEARER (self)));
|
||||
auth = mm_bearer_properties_get_allowed_auth (mm_base_bearer_peek_config (MM_BASE_BEARER (self)));
|
||||
encoded_auth = huawei_parse_auth_type (auth);
|
||||
|
||||
/* Default to no authentication if not specified */
|
||||
if (encoded_auth == MM_BEARER_HUAWEI_AUTH_UNKNOWN)
|
||||
encoded_auth = MM_BEARER_HUAWEI_AUTH_NONE;
|
||||
|
||||
if (!user && !passwd)
|
||||
command = g_strdup_printf ("AT^NDISDUP=1,1,\"%s\"",
|
||||
apn == NULL ? "" : apn);
|
||||
else {
|
||||
if (encoded_auth == MM_BEARER_HUAWEI_AUTH_NONE) {
|
||||
encoded_auth = MM_BEARER_HUAWEI_AUTH_CHAP;
|
||||
mm_obj_dbg (self, "using default (CHAP) authentication method");
|
||||
}
|
||||
command = g_strdup_printf ("AT^NDISDUP=1,1,\"%s\",\"%s\",\"%s\",%d",
|
||||
apn == NULL ? "" : apn,
|
||||
user == NULL ? "" : user,
|
||||
passwd == NULL ? "" : passwd,
|
||||
encoded_auth);
|
||||
}
|
||||
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
command,
|
||||
3,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)connect_ndisdup_ready,
|
||||
g_object_ref (self));
|
||||
g_free (command);
|
||||
return;
|
||||
}
|
||||
|
||||
case CONNECT_3GPP_CONTEXT_STEP_NDISSTATQRY:
|
||||
/* Wait for dial up timeout, retries for 180 times
|
||||
* (1s between the retries, so it means 3 minutes).
|
||||
* If too many retries, failed
|
||||
*/
|
||||
if (ctx->check_count > MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT) {
|
||||
/* Clear context */
|
||||
self->priv->connect_pending = NULL;
|
||||
g_task_return_new_error (task,
|
||||
MM_MOBILE_EQUIPMENT_ERROR,
|
||||
MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT,
|
||||
"Connection attempt timed out");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Give up if too many unexpected responses to NIDSSTATQRY are encountered. */
|
||||
if (ctx->failed_ndisstatqry_count > 10) {
|
||||
/* Clear context */
|
||||
self->priv->connect_pending = NULL;
|
||||
g_task_return_new_error (task,
|
||||
MM_MOBILE_EQUIPMENT_ERROR,
|
||||
MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED,
|
||||
"Connection attempt not supported.");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if connected */
|
||||
ctx->check_count++;
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
"^NDISSTATQRY?",
|
||||
3,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)connect_ndisstatqry_check_ready,
|
||||
g_object_ref (self));
|
||||
return;
|
||||
|
||||
case CONNECT_3GPP_CONTEXT_STEP_IP_CONFIG:
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
"^DHCP?",
|
||||
3,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)connect_dhcp_check_ready,
|
||||
g_object_ref (self));
|
||||
return;
|
||||
|
||||
case CONNECT_3GPP_CONTEXT_STEP_LAST:
|
||||
/* Clear context */
|
||||
self->priv->connect_pending = NULL;
|
||||
|
||||
/* Setup result */
|
||||
g_task_return_pointer (
|
||||
task,
|
||||
mm_bearer_connect_result_new (ctx->data, ctx->ipv4_config, NULL),
|
||||
(GDestroyNotify)mm_bearer_connect_result_unref);
|
||||
|
||||
g_object_unref (task);
|
||||
return;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
connect_3gpp (MMBroadbandBearer *_self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandBearerHuawei *self = MM_BROADBAND_BEARER_HUAWEI (_self);
|
||||
Connect3gppContext *ctx;
|
||||
GTask *task;
|
||||
MMPort *data;
|
||||
|
||||
g_assert (primary != NULL);
|
||||
|
||||
/* We need a net data port */
|
||||
data = mm_base_modem_peek_best_data_port (MM_BASE_MODEM (modem), MM_PORT_TYPE_NET);
|
||||
if (!data) {
|
||||
g_task_report_new_error (self,
|
||||
callback,
|
||||
user_data,
|
||||
connect_3gpp,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_NOT_FOUND,
|
||||
"No valid data port found to launch connection");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup connection context */
|
||||
ctx = g_slice_new0 (Connect3gppContext);
|
||||
ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
|
||||
ctx->data = g_object_ref (data);
|
||||
ctx->step = CONNECT_3GPP_CONTEXT_STEP_FIRST;
|
||||
|
||||
g_assert (self->priv->connect_pending == NULL);
|
||||
g_assert (self->priv->disconnect_pending == NULL);
|
||||
|
||||
/* Get correct dial port to use */
|
||||
ctx->primary = get_dial_port (MM_BROADBAND_MODEM_HUAWEI (ctx->modem), ctx->data, primary);
|
||||
|
||||
|
||||
/* Default to automatic/DHCP addressing */
|
||||
ctx->ipv4_config = mm_bearer_ip_config_new ();
|
||||
mm_bearer_ip_config_set_method (ctx->ipv4_config, MM_BEARER_IP_METHOD_DHCP);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)connect_3gpp_context_free);
|
||||
g_task_set_check_cancellable (task, FALSE);
|
||||
|
||||
/* Run! */
|
||||
connect_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Disconnect 3GPP */
|
||||
|
||||
typedef enum {
|
||||
DISCONNECT_3GPP_CONTEXT_STEP_FIRST = 0,
|
||||
DISCONNECT_3GPP_CONTEXT_STEP_NDISDUP,
|
||||
DISCONNECT_3GPP_CONTEXT_STEP_NDISSTATQRY,
|
||||
DISCONNECT_3GPP_CONTEXT_STEP_LAST
|
||||
} Disconnect3gppContextStep;
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
Disconnect3gppContextStep step;
|
||||
guint check_count;
|
||||
guint failed_ndisstatqry_count;
|
||||
} Disconnect3gppContext;
|
||||
|
||||
static void
|
||||
disconnect_3gpp_context_free (Disconnect3gppContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->primary);
|
||||
g_object_unref (ctx->modem);
|
||||
g_slice_free (Disconnect3gppContext, ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
disconnect_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void disconnect_3gpp_context_step (GTask *task);
|
||||
|
||||
static gboolean
|
||||
disconnect_retry_ndisstatqry_check_cb (MMBroadbandBearerHuawei *self)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
/* Recover context */
|
||||
task = self->priv->disconnect_pending;
|
||||
g_assert (task != NULL);
|
||||
|
||||
/* Balance refcount */
|
||||
g_object_unref (self);
|
||||
|
||||
/* Retry same step */
|
||||
disconnect_3gpp_context_step (task);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_ndisstatqry_check_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
MMBroadbandBearerHuawei *self)
|
||||
{
|
||||
GTask *task;
|
||||
Disconnect3gppContext *ctx;
|
||||
const gchar *response;
|
||||
GError *error = NULL;
|
||||
gboolean ipv4_available = FALSE;
|
||||
gboolean ipv4_connected = FALSE;
|
||||
gboolean ipv6_available = FALSE;
|
||||
gboolean ipv6_connected = FALSE;
|
||||
|
||||
task = self->priv->disconnect_pending;
|
||||
g_assert (task != NULL);
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Balance refcount */
|
||||
g_object_unref (self);
|
||||
|
||||
response = mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (!response ||
|
||||
!mm_huawei_parse_ndisstatqry_response (response,
|
||||
&ipv4_available,
|
||||
&ipv4_connected,
|
||||
&ipv6_available,
|
||||
&ipv6_connected,
|
||||
&error)) {
|
||||
ctx->failed_ndisstatqry_count++;
|
||||
mm_obj_dbg (self, "unexpected response to ^NDISSTATQRY command: %s (%u attempts so far)",
|
||||
error->message, ctx->failed_ndisstatqry_count);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
/* Disconnected IPv4? */
|
||||
if (ipv4_available && !ipv4_connected) {
|
||||
/* Success! */
|
||||
ctx->step++;
|
||||
disconnect_3gpp_context_step (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup timeout to retry the same step */
|
||||
g_timeout_add_seconds (1,
|
||||
(GSourceFunc)disconnect_retry_ndisstatqry_check_cb,
|
||||
g_object_ref (self));
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_ndisdup_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
MMBroadbandBearerHuawei *self)
|
||||
{
|
||||
GTask *task;
|
||||
Disconnect3gppContext *ctx;
|
||||
|
||||
task = self->priv->disconnect_pending;
|
||||
g_assert (task != NULL);
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Balance refcount */
|
||||
g_object_unref (self);
|
||||
|
||||
/* Running NDISDUP=1,0 on an already disconnected bearer/context will
|
||||
* return ERROR! Ignore errors in the NDISDUP disconnection command,
|
||||
* because we're anyway going to check the bearer/context status
|
||||
* afterwards. */
|
||||
mm_base_modem_at_command_full_finish (modem, res, NULL);
|
||||
|
||||
/* Go to next step */
|
||||
ctx->step++;
|
||||
disconnect_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp_context_step (GTask *task)
|
||||
{
|
||||
MMBroadbandBearerHuawei *self;
|
||||
Disconnect3gppContext *ctx;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
switch (ctx->step) {
|
||||
case DISCONNECT_3GPP_CONTEXT_STEP_FIRST:
|
||||
/* Store the task */
|
||||
self->priv->disconnect_pending = task;
|
||||
ctx->step++;
|
||||
/* fall through */
|
||||
|
||||
case DISCONNECT_3GPP_CONTEXT_STEP_NDISDUP:
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
"^NDISDUP=1,0",
|
||||
3,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)disconnect_ndisdup_ready,
|
||||
g_object_ref (self));
|
||||
return;
|
||||
|
||||
case DISCONNECT_3GPP_CONTEXT_STEP_NDISSTATQRY:
|
||||
/* If too many retries (1s of wait between the retries), failed */
|
||||
if (ctx->check_count > MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT) {
|
||||
/* Clear task */
|
||||
self->priv->disconnect_pending = NULL;
|
||||
g_task_return_new_error (task,
|
||||
MM_MOBILE_EQUIPMENT_ERROR,
|
||||
MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT,
|
||||
"Disconnection attempt timed out");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Give up if too many unexpected responses to NIDSSTATQRY are encountered. */
|
||||
if (ctx->failed_ndisstatqry_count > 10) {
|
||||
/* Clear task */
|
||||
self->priv->disconnect_pending = NULL;
|
||||
g_task_return_new_error (task,
|
||||
MM_MOBILE_EQUIPMENT_ERROR,
|
||||
MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED,
|
||||
"Disconnection attempt not supported.");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if disconnected */
|
||||
ctx->check_count++;
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
"^NDISSTATQRY?",
|
||||
3,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)disconnect_ndisstatqry_check_ready,
|
||||
g_object_ref (self));
|
||||
return;
|
||||
|
||||
case DISCONNECT_3GPP_CONTEXT_STEP_LAST:
|
||||
/* Clear task */
|
||||
self->priv->disconnect_pending = NULL;
|
||||
/* Set data port as result */
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp (MMBroadbandBearer *_self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
MMPort *data,
|
||||
guint cid,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandBearerHuawei *self = MM_BROADBAND_BEARER_HUAWEI (_self);
|
||||
Disconnect3gppContext *ctx;
|
||||
GTask *task;
|
||||
|
||||
g_assert (primary != NULL);
|
||||
|
||||
ctx = g_slice_new0 (Disconnect3gppContext);
|
||||
ctx->modem = MM_BASE_MODEM (g_object_ref (modem));
|
||||
ctx->step = DISCONNECT_3GPP_CONTEXT_STEP_FIRST;
|
||||
|
||||
g_assert (self->priv->connect_pending == NULL);
|
||||
g_assert (self->priv->disconnect_pending == NULL);
|
||||
|
||||
/* Get correct dial port to use */
|
||||
ctx->primary = get_dial_port (MM_BROADBAND_MODEM_HUAWEI (ctx->modem), data, primary);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)disconnect_3gpp_context_free);
|
||||
|
||||
/* Start! */
|
||||
disconnect_3gpp_context_step (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
report_connection_status (MMBaseBearer *bearer,
|
||||
MMBearerConnectionStatus status,
|
||||
const GError *connection_error)
|
||||
{
|
||||
MMBroadbandBearerHuawei *self = MM_BROADBAND_BEARER_HUAWEI (bearer);
|
||||
|
||||
g_assert (status == MM_BEARER_CONNECTION_STATUS_CONNECTED ||
|
||||
status == MM_BEARER_CONNECTION_STATUS_DISCONNECTING ||
|
||||
status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
|
||||
|
||||
/* When a pending connection / disconnection attempt is in progress, we use
|
||||
* ^NDISSTATQRY? to check the connection status and thus temporarily ignore
|
||||
* ^NDISSTAT unsolicited messages */
|
||||
if (self->priv->connect_pending || self->priv->disconnect_pending)
|
||||
return;
|
||||
|
||||
mm_obj_dbg (self, "received spontaneous ^NDISSTAT (%s)", mm_bearer_connection_status_get_string (status));
|
||||
|
||||
/* Ignore 'CONNECTED' */
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_CONNECTED)
|
||||
return;
|
||||
|
||||
/* Report disconnected right away */
|
||||
MM_BASE_BEARER_CLASS (mm_broadband_bearer_huawei_parent_class)->report_connection_status (
|
||||
bearer,
|
||||
MM_BEARER_CONNECTION_STATUS_DISCONNECTED,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseBearer *
|
||||
mm_broadband_bearer_huawei_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_base_bearer_export (MM_BASE_BEARER (bearer));
|
||||
|
||||
return MM_BASE_BEARER (bearer);
|
||||
}
|
||||
|
||||
void
|
||||
mm_broadband_bearer_huawei_new (MMBroadbandModemHuawei *modem,
|
||||
MMBearerProperties *config,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
MM_TYPE_BROADBAND_BEARER_HUAWEI,
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data,
|
||||
MM_BASE_BEARER_MODEM, modem,
|
||||
MM_BASE_BEARER_CONFIG, config,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_huawei_init (MMBroadbandBearerHuawei *self)
|
||||
{
|
||||
/* Initialize private data */
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
MM_TYPE_BROADBAND_BEARER_HUAWEI,
|
||||
MMBroadbandBearerHuaweiPrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_huawei_class_init (MMBroadbandBearerHuaweiClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass);
|
||||
MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (MMBroadbandBearerHuaweiPrivate));
|
||||
|
||||
base_bearer_class->report_connection_status = report_connection_status;
|
||||
base_bearer_class->load_connection_status = NULL;
|
||||
base_bearer_class->load_connection_status_finish = NULL;
|
||||
#if defined WITH_SUSPEND_RESUME
|
||||
base_bearer_class->reload_connection_status = NULL;
|
||||
base_bearer_class->reload_connection_status_finish = NULL;
|
||||
#endif
|
||||
|
||||
broadband_bearer_class->connect_3gpp = connect_3gpp;
|
||||
broadband_bearer_class->connect_3gpp_finish = connect_3gpp_finish;
|
||||
broadband_bearer_class->disconnect_3gpp = disconnect_3gpp;
|
||||
broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* -*- 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) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Lanedo GmbH
|
||||
* Copyright (C) 2012 Huawei Technologies Co., Ltd
|
||||
*
|
||||
* Author: Franko Fang <huananhu@huawei.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_BEARER_HUAWEI_H
|
||||
#define MM_BROADBAND_BEARER_HUAWEI_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "mm-broadband-bearer.h"
|
||||
#include "mm-broadband-modem-huawei.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_BEARER_HUAWEI (mm_broadband_bearer_huawei_get_type ())
|
||||
#define MM_BROADBAND_BEARER_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_BEARER_HUAWEI, MMBroadbandBearerHuawei))
|
||||
#define MM_BROADBAND_BEARER_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_BEARER_HUAWEI, MMBroadbandBearerHuaweiClass))
|
||||
#define MM_IS_BROADBAND_BEARER_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_BEARER_HUAWEI))
|
||||
#define MM_IS_BROADBAND_BEARER_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_BEARER_HUAWEI))
|
||||
#define MM_BROADBAND_BEARER_HUAWEI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_BEARER_HUAWEI, MMBroadbandBearerHuaweiClass))
|
||||
|
||||
typedef struct _MMBroadbandBearerHuawei MMBroadbandBearerHuawei;
|
||||
typedef struct _MMBroadbandBearerHuaweiClass MMBroadbandBearerHuaweiClass;
|
||||
typedef struct _MMBroadbandBearerHuaweiPrivate MMBroadbandBearerHuaweiPrivate;
|
||||
|
||||
struct _MMBroadbandBearerHuawei {
|
||||
MMBroadbandBearer parent;
|
||||
MMBroadbandBearerHuaweiPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMBroadbandBearerHuaweiClass {
|
||||
MMBroadbandBearerClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_bearer_huawei_get_type (void);
|
||||
|
||||
void mm_broadband_bearer_huawei_new (MMBroadbandModemHuawei *modem,
|
||||
MMBearerProperties *config,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
MMBaseBearer *mm_broadband_bearer_huawei_new_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_BROADBAND_BEARER_HUAWEI_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_HUAWEI_H
|
||||
#define MM_BROADBAND_MODEM_HUAWEI_H
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_HUAWEI (mm_broadband_modem_huawei_get_type ())
|
||||
#define MM_BROADBAND_MODEM_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_HUAWEI, MMBroadbandModemHuawei))
|
||||
#define MM_BROADBAND_MODEM_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_HUAWEI, MMBroadbandModemHuaweiClass))
|
||||
#define MM_IS_BROADBAND_MODEM_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_HUAWEI))
|
||||
#define MM_IS_BROADBAND_MODEM_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_HUAWEI))
|
||||
#define MM_BROADBAND_MODEM_HUAWEI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_HUAWEI, MMBroadbandModemHuaweiClass))
|
||||
|
||||
typedef struct _MMBroadbandModemHuawei MMBroadbandModemHuawei;
|
||||
typedef struct _MMBroadbandModemHuaweiClass MMBroadbandModemHuaweiClass;
|
||||
typedef struct _MMBroadbandModemHuaweiPrivate MMBroadbandModemHuaweiPrivate;
|
||||
|
||||
struct _MMBroadbandModemHuawei {
|
||||
MMBroadbandModem parent;
|
||||
MMBroadbandModemHuaweiPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemHuaweiClass{
|
||||
MMBroadbandModemClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_huawei_get_type (void);
|
||||
|
||||
MMBroadbandModemHuawei *mm_broadband_modem_huawei_new (const gchar *device,
|
||||
const gchar **driver,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
MMPortSerialAt *mm_broadband_modem_huawei_peek_port_at_for_data (MMBroadbandModemHuawei *self,
|
||||
MMPort *port);
|
||||
GList *mm_broadband_modem_huawei_get_at_port_list (MMBroadbandModemHuawei *self);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_HUAWEI_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,193 @@
|
||||
/* -*- 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 Huawei Technologies Co., Ltd
|
||||
* Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#ifndef MM_MODEM_HELPERS_HUAWEI_H
|
||||
#define MM_MODEM_HELPERS_HUAWEI_H
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^NDISSTAT / ^NDISSTATQRY response parser */
|
||||
gboolean mm_huawei_parse_ndisstatqry_response (const gchar *response,
|
||||
gboolean *ipv4_available,
|
||||
gboolean *ipv4_connected,
|
||||
gboolean *ipv6_available,
|
||||
gboolean *ipv6_connected,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^DHCP response parser */
|
||||
gboolean mm_huawei_parse_dhcp_response (const char *reply,
|
||||
guint *out_address,
|
||||
guint *out_prefix,
|
||||
guint *out_gateway,
|
||||
guint *out_dns1,
|
||||
guint *out_dns2,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SYSINFO response parser */
|
||||
gboolean mm_huawei_parse_sysinfo_response (const char *reply,
|
||||
guint *out_srv_status,
|
||||
guint *out_srv_domain,
|
||||
guint *out_roam_status,
|
||||
guint *out_sys_mode,
|
||||
guint *out_sim_state,
|
||||
gboolean *out_sys_submode_valid,
|
||||
guint *out_sys_submode,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SYSINFOEX response parser */
|
||||
gboolean mm_huawei_parse_sysinfoex_response (const char *reply,
|
||||
guint *out_srv_status,
|
||||
guint *out_srv_domain,
|
||||
guint *out_roam_status,
|
||||
guint *out_sim_state,
|
||||
guint *out_sys_mode,
|
||||
guint *out_sys_submode,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^PREFMODE test parser */
|
||||
|
||||
typedef struct {
|
||||
guint prefmode;
|
||||
MMModemMode allowed;
|
||||
MMModemMode preferred;
|
||||
} MMHuaweiPrefmodeCombination;
|
||||
|
||||
GArray *mm_huawei_parse_prefmode_test (const gchar *response,
|
||||
gpointer log_object,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^PREFMODE response parser */
|
||||
|
||||
const MMHuaweiPrefmodeCombination *mm_huawei_parse_prefmode_response (const gchar *response,
|
||||
const GArray *supported_mode_combinations,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SYSCFG test parser */
|
||||
|
||||
/* This is the default string we use as fallback when the modem gives
|
||||
* an empty response to AT^SYSCFG=? */
|
||||
#define MM_HUAWEI_DEFAULT_SYSCFG_FMT "^SYSCFG:(2,13,14,16),(0-3),,,"
|
||||
|
||||
typedef struct {
|
||||
guint mode;
|
||||
guint acqorder;
|
||||
MMModemMode allowed;
|
||||
MMModemMode preferred;
|
||||
} MMHuaweiSyscfgCombination;
|
||||
|
||||
GArray *mm_huawei_parse_syscfg_test (const gchar *response,
|
||||
gpointer log_object,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SYSCFG response parser */
|
||||
|
||||
const MMHuaweiSyscfgCombination *mm_huawei_parse_syscfg_response (const gchar *response,
|
||||
const GArray *supported_mode_combinations,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SYSCFGEX test parser */
|
||||
|
||||
typedef struct {
|
||||
gchar *mode_str;
|
||||
MMModemMode allowed;
|
||||
MMModemMode preferred;
|
||||
} MMHuaweiSyscfgexCombination;
|
||||
|
||||
GArray *mm_huawei_parse_syscfgex_test (const gchar *response,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^SYSCFGEX response parser */
|
||||
|
||||
const MMHuaweiSyscfgexCombination *mm_huawei_parse_syscfgex_response (const gchar *response,
|
||||
const GArray *supported_mode_combinations,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^NWTIME response parser */
|
||||
|
||||
gboolean mm_huawei_parse_nwtime_response (const gchar *response,
|
||||
gchar **iso8601p,
|
||||
MMNetworkTimezone **tzp,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^TIME response parser */
|
||||
|
||||
gboolean mm_huawei_parse_time_response (const gchar *response,
|
||||
gchar **iso8601p,
|
||||
MMNetworkTimezone **tzp,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^HCSQ response parser */
|
||||
|
||||
gboolean mm_huawei_parse_hcsq_response (const gchar *response,
|
||||
MMModemAccessTechnology *out_act,
|
||||
guint *out_value1,
|
||||
guint *out_value2,
|
||||
guint *out_value3,
|
||||
guint *out_value4,
|
||||
guint *out_value5,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^CVOICE response parser */
|
||||
|
||||
gboolean mm_huawei_parse_cvoice_response (const gchar *response,
|
||||
guint *hz,
|
||||
guint *bits,
|
||||
GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ^GETPORTMODE response parser */
|
||||
|
||||
typedef enum { /*< underscore_name=mm_huawei_port_mode >*/
|
||||
MM_HUAWEI_PORT_MODE_NONE,
|
||||
MM_HUAWEI_PORT_MODE_PCUI,
|
||||
MM_HUAWEI_PORT_MODE_MODEM,
|
||||
MM_HUAWEI_PORT_MODE_DIAG,
|
||||
MM_HUAWEI_PORT_MODE_GPS,
|
||||
MM_HUAWEI_PORT_MODE_NET,
|
||||
MM_HUAWEI_PORT_MODE_CDROM,
|
||||
MM_HUAWEI_PORT_MODE_SD,
|
||||
MM_HUAWEI_PORT_MODE_BT,
|
||||
MM_HUAWEI_PORT_MODE_SHELL,
|
||||
} MMHuaweiPortMode;
|
||||
|
||||
#define MM_HUAWEI_PORT_MODE_IS_SERIAL(mode) \
|
||||
(mode == MM_HUAWEI_PORT_MODE_PCUI || \
|
||||
mode == MM_HUAWEI_PORT_MODE_MODEM || \
|
||||
mode == MM_HUAWEI_PORT_MODE_DIAG || \
|
||||
mode == MM_HUAWEI_PORT_MODE_GPS || \
|
||||
mode == MM_HUAWEI_PORT_MODE_SHELL)
|
||||
|
||||
GArray *mm_huawei_parse_getportmode_response (const gchar *response,
|
||||
gpointer log_object,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_MODEM_HELPERS_HUAWEI_H */
|
||||
@@ -0,0 +1,735 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#include <gmodule.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include <ModemManager-tags.h>
|
||||
#include "mm-port-enums-types.h"
|
||||
#include "mm-log.h"
|
||||
#include "mm-plugin-huawei.h"
|
||||
#include "mm-broadband-modem-huawei.h"
|
||||
#include "mm-modem-helpers-huawei.h"
|
||||
#include "mm-huawei-enums-types.h"
|
||||
|
||||
#if defined WITH_QMI
|
||||
#include "mm-broadband-modem-qmi.h"
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginHuawei, mm_plugin_huawei, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Custom init */
|
||||
|
||||
#define TAG_FIRST_INTERFACE_CONTEXT "first-interface-context"
|
||||
|
||||
/* Maximum time to wait for the first interface 0 to appear and get probed.
|
||||
* If it doesn't appear in this time, we'll decide which will be considered the
|
||||
* first interface. */
|
||||
#define MAX_WAIT_TIME 5
|
||||
|
||||
typedef struct {
|
||||
MMPortProbe *probe;
|
||||
gint first_usbif;
|
||||
guint timeout_id;
|
||||
gboolean custom_init_run;
|
||||
} FirstInterfaceContext;
|
||||
|
||||
static void
|
||||
first_interface_context_free (FirstInterfaceContext *ctx)
|
||||
{
|
||||
if (ctx->timeout_id)
|
||||
g_source_remove (ctx->timeout_id);
|
||||
g_object_unref (ctx->probe);
|
||||
g_slice_free (FirstInterfaceContext, ctx);
|
||||
}
|
||||
|
||||
#define TAG_GETPORTMODE_RESULT "getportmode-result"
|
||||
#define TAG_AT_PORT_FLAGS "at-port-flags"
|
||||
|
||||
typedef struct {
|
||||
MMPortSerialAt *port;
|
||||
gboolean curc_done;
|
||||
guint curc_retries;
|
||||
gboolean getportmode_done;
|
||||
guint getportmode_retries;
|
||||
} HuaweiCustomInitContext;
|
||||
|
||||
static void
|
||||
huawei_custom_init_context_free (HuaweiCustomInitContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->port);
|
||||
g_slice_free (HuaweiCustomInitContext, ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
huawei_custom_init_finish (MMPortProbe *probe,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void huawei_custom_init_step (GTask *task);
|
||||
|
||||
static void
|
||||
getportmode_ready (MMPortSerialAt *port,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMDevice *device;
|
||||
MMPortProbe *probe;
|
||||
HuaweiCustomInitContext *ctx;
|
||||
const gchar *response;
|
||||
GArray *modes;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
probe = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
device = mm_port_probe_peek_device (probe);
|
||||
|
||||
response = mm_port_serial_at_command_finish (port, res, &error);
|
||||
if (error) {
|
||||
mm_obj_dbg (probe, "couldn't get port mode: '%s'", error->message);
|
||||
|
||||
/* If any error occurred that was not ERROR or COMMAND NOT SUPPORT then
|
||||
* retry the command.
|
||||
*/
|
||||
if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN))
|
||||
ctx->getportmode_done = TRUE;
|
||||
huawei_custom_init_step (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mark port as being AT already */
|
||||
mm_port_probe_set_result_at (probe, TRUE);
|
||||
|
||||
/* Flag as GETPORTMODE already done */
|
||||
ctx->getportmode_done = TRUE;
|
||||
|
||||
modes = mm_huawei_parse_getportmode_response (response, probe, &error);
|
||||
if (!modes)
|
||||
mm_obj_warn (probe, "failed to parse ^GETPORTMODE response: %s", error->message);
|
||||
else
|
||||
g_object_set_data_full (G_OBJECT (device), TAG_GETPORTMODE_RESULT, modes, (GDestroyNotify) g_array_unref);
|
||||
huawei_custom_init_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
curc_ready (MMPortSerialAt *port,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMPortProbe *probe;
|
||||
HuaweiCustomInitContext *ctx;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
probe = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
mm_port_serial_at_command_finish (port, res, &error);
|
||||
if (error) {
|
||||
/* Retry if we get a timeout error */
|
||||
if (g_error_matches (error,
|
||||
MM_SERIAL_ERROR,
|
||||
MM_SERIAL_ERROR_RESPONSE_TIMEOUT))
|
||||
goto out;
|
||||
|
||||
mm_obj_dbg (probe, "couldn't turn off unsolicited messages in secondary ports: %s", error->message);
|
||||
}
|
||||
|
||||
mm_obj_dbg (probe, "unsolicited messages in secondary ports turned off");
|
||||
|
||||
ctx->curc_done = TRUE;
|
||||
|
||||
out:
|
||||
huawei_custom_init_step (task);
|
||||
}
|
||||
|
||||
static void
|
||||
try_next_usbif (MMPortProbe *probe,
|
||||
MMDevice *device)
|
||||
{
|
||||
FirstInterfaceContext *fi_ctx;
|
||||
GList *l;
|
||||
gint closest;
|
||||
|
||||
fi_ctx = g_object_get_data (G_OBJECT (device), TAG_FIRST_INTERFACE_CONTEXT);
|
||||
g_assert (fi_ctx != NULL);
|
||||
|
||||
/* Look for the next closest one among the list of interfaces in the device,
|
||||
* and enable that one as being first */
|
||||
closest = G_MAXINT;
|
||||
for (l = mm_device_peek_port_probe_list (device); l; l = g_list_next (l)) {
|
||||
MMPortProbe *iter = MM_PORT_PROBE (l->data);
|
||||
|
||||
/* Only expect ttys for next probing attempt */
|
||||
if (g_str_equal (mm_port_probe_get_port_subsys (iter), "tty")) {
|
||||
gint usbif;
|
||||
|
||||
usbif = mm_kernel_device_get_interface_number (mm_port_probe_peek_port (iter));
|
||||
if (usbif == fi_ctx->first_usbif) {
|
||||
/* This is the one we just probed, which wasn't yet removed, so just skip it */
|
||||
} else if (usbif > fi_ctx->first_usbif &&
|
||||
usbif < closest) {
|
||||
closest = usbif;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closest == G_MAXINT) {
|
||||
/* No more ttys to try! Just return something */
|
||||
closest = 0;
|
||||
mm_obj_dbg (probe, "no more ports to run initial probing");
|
||||
} else
|
||||
mm_obj_dbg (probe, "will try initial probing with interface '%d' instead", closest);
|
||||
|
||||
fi_ctx->first_usbif = closest;
|
||||
}
|
||||
|
||||
static void
|
||||
huawei_custom_init_step (GTask *task)
|
||||
{
|
||||
MMPortProbe *probe;
|
||||
HuaweiCustomInitContext *ctx;
|
||||
FirstInterfaceContext *fi_ctx;
|
||||
MMKernelDevice *port;
|
||||
|
||||
probe = g_task_get_source_object (task);
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* If cancelled, end */
|
||||
if (g_task_return_error_if_cancelled (task)) {
|
||||
mm_obj_dbg (probe, "no need to keep on running custom init");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx->curc_done) {
|
||||
if (ctx->curc_retries == 0) {
|
||||
/* All retries consumed, probably not an AT port */
|
||||
mm_port_probe_set_result_at (probe, FALSE);
|
||||
/* Try with next */
|
||||
try_next_usbif (probe, mm_port_probe_peek_device (probe));
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->curc_retries--;
|
||||
/* Turn off unsolicited messages on secondary ports until needed */
|
||||
mm_port_serial_at_command (
|
||||
ctx->port,
|
||||
"AT^CURC=0",
|
||||
3,
|
||||
FALSE, /* raw */
|
||||
FALSE, /* allow_cached */
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback)curc_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to get a port map from the modem */
|
||||
port = mm_port_probe_peek_port (probe);
|
||||
if (!ctx->getportmode_done && !mm_kernel_device_get_global_property_as_boolean (port, "ID_MM_HUAWEI_DISABLE_GETPORTMODE")) {
|
||||
if (ctx->getportmode_retries == 0) {
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->getportmode_retries--;
|
||||
mm_port_serial_at_command (
|
||||
ctx->port,
|
||||
"AT^GETPORTMODE",
|
||||
3,
|
||||
FALSE, /* raw */
|
||||
FALSE, /* allow_cached */
|
||||
g_task_get_cancellable (task),
|
||||
(GAsyncReadyCallback)getportmode_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* All done it seems */
|
||||
fi_ctx = g_object_get_data (G_OBJECT (mm_port_probe_peek_device (probe)), TAG_FIRST_INTERFACE_CONTEXT);
|
||||
g_assert (fi_ctx != NULL);
|
||||
fi_ctx->custom_init_run = TRUE;
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
first_interface_missing_timeout_cb (MMDevice *device)
|
||||
{
|
||||
FirstInterfaceContext *fi_ctx;
|
||||
|
||||
fi_ctx = g_object_get_data (G_OBJECT (device), TAG_FIRST_INTERFACE_CONTEXT);
|
||||
g_assert (fi_ctx != NULL);
|
||||
try_next_usbif (fi_ctx->probe, device);
|
||||
|
||||
/* Reload the timeout, just in case we end up not having the next interface to probe...
|
||||
* which is anyway very unlikely as we got it by looking at the real probe list, but anyway... */
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
huawei_custom_init (MMPortProbe *probe,
|
||||
MMPortSerialAt *port,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMDevice *device;
|
||||
FirstInterfaceContext *fi_ctx;
|
||||
HuaweiCustomInitContext *ctx;
|
||||
GTask *task;
|
||||
|
||||
device = mm_port_probe_peek_device (probe);
|
||||
|
||||
/* The primary port (called the "modem" port in the Windows drivers) is
|
||||
* always USB interface 0, and we need to detect that interface first for
|
||||
* two reasons: (1) to disable unsolicited messages on other ports that
|
||||
* may fill up the buffer and crash the device, and (2) to attempt to get
|
||||
* the port layout for hints about what the secondary port is (called the
|
||||
* "pcui" port in Windows). Thus we probe USB interface 0 first and defer
|
||||
* probing other interfaces until we've got if0, at which point we allow
|
||||
* the other ports to be probed too.
|
||||
*/
|
||||
fi_ctx = g_object_get_data (G_OBJECT (device), TAG_FIRST_INTERFACE_CONTEXT);
|
||||
if (!fi_ctx) {
|
||||
/* This is the first time we ask for the context. Set it up. */
|
||||
fi_ctx = g_slice_new0 (FirstInterfaceContext);
|
||||
fi_ctx->probe = g_object_ref (probe);
|
||||
g_object_set_data_full (G_OBJECT (device),
|
||||
TAG_FIRST_INTERFACE_CONTEXT,
|
||||
fi_ctx,
|
||||
(GDestroyNotify)first_interface_context_free);
|
||||
/* The timeout is controlled in the data set in 'device', and therefore
|
||||
* it should be safe to assume that the timeout will not get fired after
|
||||
* having disposed 'device' */
|
||||
fi_ctx->timeout_id = g_timeout_add_seconds (MAX_WAIT_TIME,
|
||||
(GSourceFunc)first_interface_missing_timeout_cb,
|
||||
device);
|
||||
|
||||
/* By default, we'll ask the Huawei plugin to start probing usbif 0 */
|
||||
fi_ctx->first_usbif = 0;
|
||||
|
||||
/* Custom init of the Huawei plugin is to be run only in the first
|
||||
* interface. We'll control here whether we did run it already or not. */
|
||||
fi_ctx->custom_init_run = FALSE;
|
||||
}
|
||||
|
||||
ctx = g_slice_new (HuaweiCustomInitContext);
|
||||
ctx->port = g_object_ref (port);
|
||||
ctx->curc_done = FALSE;
|
||||
ctx->curc_retries = 3;
|
||||
ctx->getportmode_done = FALSE;
|
||||
ctx->getportmode_retries = 3;
|
||||
|
||||
task = g_task_new (probe, cancellable, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)huawei_custom_init_context_free);
|
||||
|
||||
/* Custom init only to be run in the first interface */
|
||||
if (mm_kernel_device_get_interface_number (mm_port_probe_peek_port (probe)) != fi_ctx->first_usbif) {
|
||||
if (fi_ctx->custom_init_run)
|
||||
/* If custom init was run already, we can consider this as successfully run */
|
||||
g_task_return_boolean (task, TRUE);
|
||||
else
|
||||
/* Otherwise, we'll need to defer the probing a bit more */
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_RETRY,
|
||||
"Defer needed");
|
||||
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We can run custom init in the first interface! clear the timeout as it is no longer needed */
|
||||
if (fi_ctx->timeout_id) {
|
||||
g_source_remove (fi_ctx->timeout_id);
|
||||
fi_ctx->timeout_id = 0;
|
||||
}
|
||||
|
||||
huawei_custom_init_step (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gint
|
||||
probe_cmp_by_usbif (MMPortProbe *a,
|
||||
MMPortProbe *b)
|
||||
{
|
||||
return (mm_kernel_device_get_interface_number (mm_port_probe_peek_port (a)) -
|
||||
mm_kernel_device_get_interface_number (mm_port_probe_peek_port (b)));
|
||||
}
|
||||
|
||||
static guint
|
||||
propagate_getportmode_hints (MMPlugin *self,
|
||||
GList *probes,
|
||||
gboolean *primary_flagged)
|
||||
{
|
||||
MMDevice *device;
|
||||
GArray *modes;
|
||||
GList *l;
|
||||
GList *tty_probes = NULL;
|
||||
guint n_ports_with_hints = 0;
|
||||
guint mode_i = 0;
|
||||
|
||||
g_assert (probes != NULL);
|
||||
device = mm_port_probe_peek_device (MM_PORT_PROBE (probes->data));
|
||||
modes = g_object_get_data (G_OBJECT (device), TAG_GETPORTMODE_RESULT);
|
||||
|
||||
/* Nothing to do if GETPORTMODE is flagged as not supported */
|
||||
if (!modes)
|
||||
return 0;
|
||||
|
||||
/* Build a list of TTY port probes (AT and not-AT) sorted by interface number */
|
||||
for (l = probes; l; l = g_list_next (l)) {
|
||||
MMPortProbe *probe;
|
||||
|
||||
probe = MM_PORT_PROBE (l->data);
|
||||
if (g_str_equal (mm_port_probe_get_port_subsys (probe), "tty"))
|
||||
tty_probes = g_list_insert_sorted (tty_probes, probe, (GCompareFunc) probe_cmp_by_usbif);
|
||||
}
|
||||
|
||||
/* Propagate the getportmode tags to the specific port probes */
|
||||
for (l = tty_probes, mode_i = 0; l; l = g_list_next (l)) {
|
||||
MMPortProbe *probe;
|
||||
MMPortSerialAtFlag at_port_flags = MM_PORT_SERIAL_AT_FLAG_NONE;
|
||||
MMHuaweiPortMode port_mode;
|
||||
|
||||
probe = MM_PORT_PROBE (l->data);
|
||||
|
||||
/* Look for the next serial port mode applicable */
|
||||
while (!MM_HUAWEI_PORT_MODE_IS_SERIAL (g_array_index (modes, MMHuaweiPortMode, mode_i)) && (mode_i < modes->len))
|
||||
mode_i++;
|
||||
if (mode_i == modes->len) {
|
||||
mm_obj_dbg (probe, "missing port mode hint");
|
||||
continue;
|
||||
}
|
||||
|
||||
port_mode = g_array_index (modes, MMHuaweiPortMode, mode_i);
|
||||
if (!mm_port_probe_is_at (probe)) {
|
||||
mm_obj_dbg (probe, "port mode hint for non-AT port: %s", mm_huawei_port_mode_get_string (port_mode));
|
||||
mode_i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
mm_obj_dbg (probe, "port mode hint for AT port: %s", mm_huawei_port_mode_get_string (port_mode));
|
||||
if (port_mode == MM_HUAWEI_PORT_MODE_PCUI)
|
||||
at_port_flags = MM_PORT_SERIAL_AT_FLAG_PRIMARY;
|
||||
else if (port_mode == MM_HUAWEI_PORT_MODE_MODEM)
|
||||
at_port_flags = MM_PORT_SERIAL_AT_FLAG_PPP;
|
||||
|
||||
if (at_port_flags != MM_PORT_SERIAL_AT_FLAG_NONE) {
|
||||
n_ports_with_hints++;
|
||||
g_object_set_data (G_OBJECT (probe), TAG_AT_PORT_FLAGS, GUINT_TO_POINTER (at_port_flags));
|
||||
}
|
||||
mode_i++;
|
||||
}
|
||||
|
||||
g_list_free (tty_probes);
|
||||
|
||||
return n_ports_with_hints;
|
||||
}
|
||||
|
||||
static guint
|
||||
propagate_description_hints (MMPlugin *self,
|
||||
GList *probes,
|
||||
gboolean *primary_flagged)
|
||||
{
|
||||
GList *l;
|
||||
guint n_ports_with_hints = 0;
|
||||
|
||||
for (l = probes; l; l = g_list_next (l)) {
|
||||
MMPortProbe *probe;
|
||||
MMPortSerialAtFlag at_port_flags = MM_PORT_SERIAL_AT_FLAG_NONE;
|
||||
const gchar *description;
|
||||
g_autofree gchar *lower_description = NULL;
|
||||
|
||||
probe = MM_PORT_PROBE (l->data);
|
||||
|
||||
if (!mm_port_probe_is_at (probe))
|
||||
continue;
|
||||
|
||||
description = mm_kernel_device_get_interface_description (mm_port_probe_peek_port (probe));
|
||||
if (!description)
|
||||
continue;
|
||||
|
||||
mm_obj_dbg (probe, "%s interface description: %s", mm_port_probe_get_port_name (probe), description);
|
||||
|
||||
lower_description = g_ascii_strdown (description, -1);
|
||||
if (strstr (lower_description, "modem"))
|
||||
at_port_flags = MM_PORT_SERIAL_AT_FLAG_PPP;
|
||||
else if (strstr (lower_description, "pcui")) {
|
||||
at_port_flags = MM_PORT_SERIAL_AT_FLAG_PRIMARY;
|
||||
*primary_flagged = TRUE;
|
||||
}
|
||||
|
||||
if (at_port_flags != MM_PORT_SERIAL_AT_FLAG_NONE) {
|
||||
n_ports_with_hints++;
|
||||
g_object_set_data (G_OBJECT (probe), TAG_AT_PORT_FLAGS, GUINT_TO_POINTER (at_port_flags));
|
||||
}
|
||||
}
|
||||
|
||||
return n_ports_with_hints;
|
||||
}
|
||||
|
||||
static guint
|
||||
propagate_generic_hints (MMPlugin *self,
|
||||
GList *probes,
|
||||
gboolean *primary_flagged)
|
||||
{
|
||||
GList *l;
|
||||
guint n_ports_with_hints = 0;
|
||||
|
||||
for (l = probes; l; l = g_list_next (l)) {
|
||||
MMPortProbe *probe;
|
||||
MMKernelDevice *kernel_device;
|
||||
MMPortSerialAtFlag at_port_flags = MM_PORT_SERIAL_AT_FLAG_NONE;
|
||||
|
||||
probe = MM_PORT_PROBE (l->data);
|
||||
|
||||
if (!mm_port_probe_is_at (probe))
|
||||
continue;
|
||||
|
||||
kernel_device = mm_port_probe_peek_port (probe);
|
||||
if (mm_kernel_device_get_property_as_boolean (kernel_device, ID_MM_PORT_TYPE_AT_PRIMARY)) {
|
||||
at_port_flags = MM_PORT_SERIAL_AT_FLAG_PRIMARY;
|
||||
*primary_flagged = TRUE;
|
||||
}
|
||||
else if (mm_kernel_device_get_property_as_boolean (kernel_device, ID_MM_PORT_TYPE_AT_SECONDARY))
|
||||
at_port_flags = MM_PORT_SERIAL_AT_FLAG_SECONDARY;
|
||||
else if (mm_kernel_device_get_property_as_boolean (kernel_device, ID_MM_PORT_TYPE_AT_PPP))
|
||||
at_port_flags = MM_PORT_SERIAL_AT_FLAG_PPP;
|
||||
|
||||
if (at_port_flags != MM_PORT_SERIAL_AT_FLAG_NONE) {
|
||||
n_ports_with_hints++;
|
||||
g_object_set_data (G_OBJECT (probe), TAG_AT_PORT_FLAGS, GUINT_TO_POINTER (at_port_flags));
|
||||
}
|
||||
}
|
||||
|
||||
return n_ports_with_hints;
|
||||
}
|
||||
|
||||
static guint
|
||||
fallback_primary_cdcwdm (MMPlugin *self,
|
||||
GList *probes)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = probes; l; l = g_list_next (l)) {
|
||||
MMPortProbe *probe;
|
||||
|
||||
probe = MM_PORT_PROBE (l->data);
|
||||
|
||||
if (!mm_port_probe_is_at (probe))
|
||||
continue;
|
||||
|
||||
if (g_str_equal (mm_port_probe_get_port_subsys (probe), "usbmisc")) {
|
||||
mm_obj_dbg (self, "fallback port type hint applied to first cdc-wmd port found");
|
||||
g_object_set_data (G_OBJECT (probe), TAG_AT_PORT_FLAGS, GUINT_TO_POINTER (MM_PORT_SERIAL_AT_FLAG_PRIMARY));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static guint
|
||||
fallback_usbif0 (MMPlugin *self,
|
||||
GList *probes)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = probes; l; l = g_list_next (l)) {
|
||||
MMPortProbe *probe;
|
||||
guint usbif;
|
||||
|
||||
probe = MM_PORT_PROBE (l->data);
|
||||
|
||||
if (!mm_port_probe_is_at (probe))
|
||||
continue;
|
||||
|
||||
usbif = mm_kernel_device_get_property_as_int_hex (mm_port_probe_peek_port (probe), "ID_USB_INTERFACE_NUM");
|
||||
if (usbif == 0) {
|
||||
mm_obj_dbg (self, "fallback port type hint applied to interface 0");
|
||||
g_object_set_data (G_OBJECT (probe), TAG_AT_PORT_FLAGS, GUINT_TO_POINTER (MM_PORT_SERIAL_AT_FLAG_PPP));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
propagate_port_type_hints (MMPlugin *self,
|
||||
GList *probes)
|
||||
{
|
||||
gboolean primary_flagged = FALSE;
|
||||
guint n_ports_with_hints;
|
||||
|
||||
g_assert (probes != NULL);
|
||||
|
||||
if ((n_ports_with_hints = propagate_getportmode_hints (self, probes, &primary_flagged)) > 0)
|
||||
mm_obj_dbg (self, "port type hints set by GETPORTMODE");
|
||||
else if ((n_ports_with_hints = propagate_description_hints (self, probes, &primary_flagged)) > 0)
|
||||
mm_obj_dbg (self, "port type hints set by interface descriptions");
|
||||
else if ((n_ports_with_hints = propagate_generic_hints (self, probes, &primary_flagged)) > 0)
|
||||
mm_obj_dbg (self, "port type hints set by generic udev tags");
|
||||
|
||||
/* Fallback hint for the first cdc-wdm port if no other port has been flagged as primary */
|
||||
if (!primary_flagged)
|
||||
n_ports_with_hints += fallback_primary_cdcwdm (self, probes);
|
||||
|
||||
/* If not a single port type hint available (not plugin-provided and not generic)
|
||||
* then we'll assume usbif 0 is the modem port */
|
||||
if (!n_ports_with_hints)
|
||||
n_ports_with_hints = fallback_usbif0 (self, probes);
|
||||
|
||||
mm_obj_dbg (self, "%u port hints have been set", n_ports_with_hints);
|
||||
}
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
propagate_port_type_hints (self, probes);
|
||||
|
||||
#if defined WITH_QMI
|
||||
if (mm_port_probe_list_has_qmi_port (probes)) {
|
||||
mm_obj_dbg (self, "QMI-powered Huawei modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_qmi_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined WITH_MBIM
|
||||
if (mm_port_probe_list_has_mbim_port (probes)) {
|
||||
mm_obj_dbg (self, "MBIM-powered Huawei modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
return MM_BASE_MODEM (mm_broadband_modem_huawei_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
grab_port (MMPlugin *self,
|
||||
MMBaseModem *modem,
|
||||
MMPortProbe *probe,
|
||||
GError **error)
|
||||
{
|
||||
MMPortSerialAtFlag pflags;
|
||||
MMKernelDevice *port;
|
||||
MMPortType port_type;
|
||||
|
||||
port_type = mm_port_probe_get_port_type (probe);
|
||||
port = mm_port_probe_peek_port (probe);
|
||||
|
||||
pflags = (MMPortSerialAtFlag) GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (probe), TAG_AT_PORT_FLAGS));
|
||||
if (pflags != MM_PORT_SERIAL_AT_FLAG_NONE) {
|
||||
gchar *str;
|
||||
|
||||
str = mm_port_serial_at_flag_build_string_from_mask (pflags);
|
||||
mm_obj_dbg (self, "(%s/%s) port will have AT flags '%s'",
|
||||
mm_port_probe_get_port_subsys (probe),
|
||||
mm_port_probe_get_port_name (probe),
|
||||
str);
|
||||
g_free (str);
|
||||
} else {
|
||||
/* The huawei plugin handles the generic udev tags itself, so explicitly request
|
||||
* to avoid processing them by the generic modem. */
|
||||
pflags = MM_PORT_SERIAL_AT_FLAG_NONE_NO_GENERIC;
|
||||
}
|
||||
|
||||
return mm_base_modem_grab_port (modem,
|
||||
port,
|
||||
port_type,
|
||||
pflags,
|
||||
error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", "net", "usbmisc", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x12d1, 0 };
|
||||
static const MMAsyncMethod custom_init = {
|
||||
.async = G_CALLBACK (huawei_custom_init),
|
||||
.finish = G_CALLBACK (huawei_custom_init_finish),
|
||||
};
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_HUAWEI,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_REQUIRED_QCDM, TRUE,
|
||||
MM_PLUGIN_ALLOWED_QMI, TRUE,
|
||||
MM_PLUGIN_ALLOWED_MBIM, TRUE,
|
||||
MM_PLUGIN_CUSTOM_INIT, &custom_init,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_huawei_init (MMPluginHuawei *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_huawei_class_init (MMPluginHuaweiClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
plugin_class->grab_port = grab_port;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_HUAWEI_H
|
||||
#define MM_PLUGIN_HUAWEI_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_HUAWEI (mm_plugin_huawei_get_type ())
|
||||
#define MM_PLUGIN_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuawei))
|
||||
#define MM_PLUGIN_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuaweiClass))
|
||||
#define MM_IS_PLUGIN_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_HUAWEI))
|
||||
#define MM_IS_PLUGIN_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_HUAWEI))
|
||||
#define MM_PLUGIN_HUAWEI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_HUAWEI, MMPluginHuaweiClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginHuawei;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginHuaweiClass;
|
||||
|
||||
GType mm_plugin_huawei_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_HUAWEI_H */
|
||||
@@ -0,0 +1,167 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Lanedo GmbH
|
||||
*/
|
||||
|
||||
#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-modem-helpers.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
|
||||
#include "mm-sim-huawei.h"
|
||||
|
||||
G_DEFINE_TYPE (MMSimHuawei, mm_sim_huawei, MM_TYPE_BASE_SIM)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SIM identifier loading */
|
||||
|
||||
static gchar *
|
||||
load_sim_identifier_finish (MMBaseSim *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_load_sim_identifier_ready (MMSimHuawei *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gchar *simid;
|
||||
|
||||
simid = MM_BASE_SIM_CLASS (mm_sim_huawei_parent_class)->load_sim_identifier_finish (MM_BASE_SIM (self), res, &error);
|
||||
if (simid)
|
||||
g_task_return_pointer (task, simid, g_free);
|
||||
else
|
||||
g_task_return_error (task, error);
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
iccid_read_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseSim *self;
|
||||
const gchar *response;
|
||||
const gchar *p;
|
||||
char *parsed;
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, NULL);
|
||||
if (!response)
|
||||
goto error;
|
||||
|
||||
p = mm_strip_tag (response, "^ICCID:");
|
||||
if (!p)
|
||||
goto error;
|
||||
|
||||
parsed = mm_3gpp_parse_iccid (p, NULL);
|
||||
if (parsed) {
|
||||
g_task_return_pointer (task, parsed, g_free);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
/* Chain up to parent method; older devices don't support ^ICCID */
|
||||
self = g_task_get_source_object (task);
|
||||
MM_BASE_SIM_CLASS (mm_sim_huawei_parent_class)->load_sim_identifier (self,
|
||||
(GAsyncReadyCallback) parent_load_sim_identifier_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
load_sim_identifier (MMBaseSim *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBaseModem *modem = NULL;
|
||||
|
||||
g_object_get (self,
|
||||
MM_BASE_SIM_MODEM, &modem,
|
||||
NULL);
|
||||
|
||||
mm_base_modem_at_command (
|
||||
modem,
|
||||
"^ICCID?",
|
||||
5,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)iccid_read_ready,
|
||||
g_task_new (self, NULL, callback, user_data));
|
||||
g_object_unref (modem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseSim *
|
||||
mm_sim_huawei_new_finish (GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
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_base_sim_export (MM_BASE_SIM (sim));
|
||||
|
||||
return MM_BASE_SIM (sim);
|
||||
}
|
||||
|
||||
void
|
||||
mm_sim_huawei_new (MMBaseModem *modem,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (MM_TYPE_SIM_HUAWEI,
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data,
|
||||
MM_BASE_SIM_MODEM, modem,
|
||||
"active", TRUE, /* by default always active */
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sim_huawei_init (MMSimHuawei *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sim_huawei_class_init (MMSimHuaweiClass *klass)
|
||||
{
|
||||
MMBaseSimClass *base_sim_class = MM_BASE_SIM_CLASS (klass);
|
||||
|
||||
base_sim_class->load_sim_identifier = load_sim_identifier;
|
||||
base_sim_class->load_sim_identifier_finish = load_sim_identifier_finish;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Lanedo GmbH
|
||||
*/
|
||||
|
||||
#ifndef MM_SIM_HUAWEI_H
|
||||
#define MM_SIM_HUAWEI_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "mm-base-sim.h"
|
||||
|
||||
#define MM_TYPE_SIM_HUAWEI (mm_sim_huawei_get_type ())
|
||||
#define MM_SIM_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SIM_HUAWEI, MMSimHuawei))
|
||||
#define MM_SIM_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SIM_HUAWEI, MMSimHuaweiClass))
|
||||
#define MM_IS_SIM_HUAWEI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SIM_HUAWEI))
|
||||
#define MM_IS_SIM_HUAWEI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SIM_HUAWEI))
|
||||
#define MM_SIM_HUAWEI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SIM_HUAWEI, MMSimHuaweiClass))
|
||||
|
||||
typedef struct _MMSimHuawei MMSimHuawei;
|
||||
typedef struct _MMSimHuaweiClass MMSimHuaweiClass;
|
||||
|
||||
struct _MMSimHuawei {
|
||||
MMBaseSim parent;
|
||||
};
|
||||
|
||||
struct _MMSimHuaweiClass {
|
||||
MMBaseSimClass parent;
|
||||
};
|
||||
|
||||
GType mm_sim_huawei_get_type (void);
|
||||
|
||||
void mm_sim_huawei_new (MMBaseModem *modem,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
MMBaseSim *mm_sim_huawei_new_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_SIM_HUAWEI_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,882 @@
|
||||
/* -*- 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) 2012 Google, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#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-broadband-bearer-icera.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-error-helpers.h"
|
||||
#include "mm-daemon-enums-types.h"
|
||||
#include "mm-modem-helpers-icera.h"
|
||||
|
||||
G_DEFINE_TYPE (MMBroadbandBearerIcera, mm_broadband_bearer_icera, MM_TYPE_BROADBAND_BEARER);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DEFAULT_IP_METHOD,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *properties[PROP_LAST];
|
||||
|
||||
struct _MMBroadbandBearerIceraPrivate {
|
||||
MMBearerIpMethod default_ip_method;
|
||||
|
||||
/* Connection related */
|
||||
gpointer connect_pending;
|
||||
guint connect_pending_id;
|
||||
gulong connect_cancellable_id;
|
||||
gulong connect_port_closed_id;
|
||||
|
||||
/* Disconnection related */
|
||||
gpointer disconnect_pending;
|
||||
guint disconnect_pending_id;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP IP config retrieval (sub-step of the 3GPP Connection sequence) */
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
guint cid;
|
||||
} GetIpConfig3gppContext;
|
||||
|
||||
static void
|
||||
get_ip_config_context_free (GetIpConfig3gppContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->primary);
|
||||
g_object_unref (ctx->modem);
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_ip_config_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
MMBearerIpConfig **ipv4_config,
|
||||
MMBearerIpConfig **ipv6_config,
|
||||
GError **error)
|
||||
{
|
||||
MMBearerConnectResult *configs;
|
||||
MMBearerIpConfig *ipv4, *ipv6;
|
||||
|
||||
configs = g_task_propagate_pointer (G_TASK (res), error);
|
||||
if (!configs)
|
||||
return FALSE;
|
||||
|
||||
ipv4 = mm_bearer_connect_result_peek_ipv4_config (configs);
|
||||
ipv6 = mm_bearer_connect_result_peek_ipv6_config (configs);
|
||||
g_assert (ipv4 || ipv6);
|
||||
if (ipv4_config && ipv4)
|
||||
*ipv4_config = g_object_ref (ipv4);
|
||||
if (ipv6_config && ipv6)
|
||||
*ipv6_config = g_object_ref (ipv6);
|
||||
|
||||
mm_bearer_connect_result_unref (configs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ip_config_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GetIpConfig3gppContext *ctx;
|
||||
MMBearerIpConfig *ipv4_config = NULL;
|
||||
MMBearerIpConfig *ipv6_config = NULL;
|
||||
const gchar *response;
|
||||
GError *error = NULL;
|
||||
MMBearerConnectResult *connect_result;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
response = mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (error) {
|
||||
g_task_return_error (task, error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!mm_icera_parse_ipdpaddr_response (response,
|
||||
ctx->cid,
|
||||
&ipv4_config,
|
||||
&ipv6_config,
|
||||
&error)) {
|
||||
g_task_return_error (task, error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ipv4_config && !ipv6_config) {
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Couldn't get IP config: couldn't parse response '%s'",
|
||||
response);
|
||||
goto out;
|
||||
}
|
||||
|
||||
connect_result = mm_bearer_connect_result_new (MM_PORT (ctx->primary),
|
||||
ipv4_config,
|
||||
ipv6_config);
|
||||
g_task_return_pointer (task,
|
||||
connect_result,
|
||||
(GDestroyNotify)mm_bearer_connect_result_unref);
|
||||
|
||||
out:
|
||||
g_object_unref (task);
|
||||
g_clear_object (&ipv4_config);
|
||||
g_clear_object (&ipv6_config);
|
||||
}
|
||||
|
||||
static void
|
||||
get_ip_config_3gpp (MMBroadbandBearer *_self,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
MMPort *data,
|
||||
guint cid,
|
||||
MMBearerIpFamily ip_family,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandBearerIcera *self = MM_BROADBAND_BEARER_ICERA (_self);
|
||||
GetIpConfig3gppContext *ctx;
|
||||
GTask *task;
|
||||
|
||||
ctx = g_new0 (GetIpConfig3gppContext, 1);
|
||||
ctx->modem = g_object_ref (MM_BASE_MODEM (modem));
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->cid = cid;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)get_ip_config_context_free);
|
||||
|
||||
if (self->priv->default_ip_method == MM_BEARER_IP_METHOD_STATIC) {
|
||||
gchar *command;
|
||||
|
||||
command = g_strdup_printf ("%%IPDPADDR=%u", cid);
|
||||
mm_base_modem_at_command_full (MM_BASE_MODEM (modem),
|
||||
primary,
|
||||
command,
|
||||
3,
|
||||
FALSE,
|
||||
FALSE, /* raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback)ip_config_ready,
|
||||
task);
|
||||
g_free (command);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, DHCP */
|
||||
if (self->priv->default_ip_method == MM_BEARER_IP_METHOD_DHCP) {
|
||||
MMBearerConnectResult *connect_result;
|
||||
MMBearerIpConfig *ipv4_config = NULL, *ipv6_config = NULL;
|
||||
|
||||
if (ip_family & MM_BEARER_IP_FAMILY_IPV4 || ip_family & MM_BEARER_IP_FAMILY_IPV4V6) {
|
||||
ipv4_config = mm_bearer_ip_config_new ();
|
||||
mm_bearer_ip_config_set_method (ipv4_config, MM_BEARER_IP_METHOD_DHCP);
|
||||
}
|
||||
if (ip_family & MM_BEARER_IP_FAMILY_IPV6 || ip_family & MM_BEARER_IP_FAMILY_IPV4V6) {
|
||||
ipv6_config = mm_bearer_ip_config_new ();
|
||||
mm_bearer_ip_config_set_method (ipv6_config, MM_BEARER_IP_METHOD_DHCP);
|
||||
}
|
||||
g_assert (ipv4_config || ipv6_config);
|
||||
|
||||
connect_result = mm_bearer_connect_result_new (MM_PORT (ctx->primary),
|
||||
ipv4_config,
|
||||
ipv6_config);
|
||||
g_clear_object (&ipv4_config);
|
||||
g_clear_object (&ipv6_config);
|
||||
|
||||
g_task_return_pointer (task,
|
||||
connect_result,
|
||||
(GDestroyNotify)mm_bearer_connect_result_unref);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP disconnection */
|
||||
|
||||
static gboolean
|
||||
disconnect_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
disconnect_3gpp_timed_out_cb (MMBroadbandBearerIcera *self)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
/* Recover disconnection task */
|
||||
task = self->priv->disconnect_pending;
|
||||
|
||||
self->priv->disconnect_pending = NULL;
|
||||
self->priv->disconnect_pending_id = 0;
|
||||
|
||||
g_task_return_new_error (task,
|
||||
MM_SERIAL_ERROR,
|
||||
MM_SERIAL_ERROR_RESPONSE_TIMEOUT,
|
||||
"Disconnection attempt timed out");
|
||||
g_object_unref (task);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
process_pending_disconnect_attempt (MMBroadbandBearerIcera *self,
|
||||
MMBearerConnectionStatus status)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
/* Recover disconnection task */
|
||||
task = self->priv->disconnect_pending;
|
||||
self->priv->disconnect_pending = NULL;
|
||||
g_assert (task != NULL);
|
||||
|
||||
/* Cleanup timeout, if any */
|
||||
if (self->priv->disconnect_pending_id) {
|
||||
g_source_remove (self->priv->disconnect_pending_id);
|
||||
self->priv->disconnect_pending_id = 0;
|
||||
}
|
||||
|
||||
/* Received 'CONNECTED' during a disconnection attempt? */
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_CONNECTED) {
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Disconnection failed");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Received 'DISCONNECTED' during a disconnection attempt? */
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED ||
|
||||
status == MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED) {
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* No other status is expected by this implementation */
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_ipdpact_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
MMBroadbandBearerIcera *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GTask *task;
|
||||
|
||||
/* Try to recover the disconnection task. If none found, it means the
|
||||
* task was already completed and we have nothing else to do. */
|
||||
task = g_steal_pointer (&self->priv->disconnect_pending);
|
||||
|
||||
if (!task) {
|
||||
mm_obj_dbg (self, "disconnection context was finished already by an unsolicited message");
|
||||
/* Run _finish() to finalize the async call, even if we don't care
|
||||
* about the result */
|
||||
mm_base_modem_at_command_full_finish (modem, res, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (error) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Track again */
|
||||
self->priv->disconnect_pending = task;
|
||||
|
||||
/* Set a 60-second disconnection-failure timeout */
|
||||
self->priv->disconnect_pending_id = g_timeout_add_seconds (60,
|
||||
(GSourceFunc)disconnect_3gpp_timed_out_cb,
|
||||
self);
|
||||
|
||||
out:
|
||||
/* Balance refcount with the extra ref we passed to command_full() */
|
||||
g_object_unref (self);
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_3gpp (MMBroadbandBearer *bearer,
|
||||
MMBroadbandModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
MMPortSerialAt *secondary,
|
||||
MMPort *data,
|
||||
guint cid,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandBearerIcera *self = MM_BROADBAND_BEARER_ICERA (bearer);
|
||||
gchar *command;
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
/* The unsolicited response to %IPDPACT may come before the OK does.
|
||||
* We will keep the disconnection task in the bearer private data so
|
||||
* that it is accessible from the unsolicited message handler. Note
|
||||
* also that we do NOT pass the task to the GAsyncReadyCallback, as it
|
||||
* may not be valid any more when the callback is called (it may be
|
||||
* already completed in the unsolicited handling) */
|
||||
g_assert (self->priv->disconnect_pending == NULL);
|
||||
self->priv->disconnect_pending = task;
|
||||
|
||||
command = g_strdup_printf ("%%IPDPACT=%d,0", cid);
|
||||
mm_base_modem_at_command_full (
|
||||
MM_BASE_MODEM (modem),
|
||||
primary,
|
||||
command,
|
||||
MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT,
|
||||
FALSE,
|
||||
FALSE, /* raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback)disconnect_ipdpact_ready,
|
||||
g_object_ref (self)); /* we pass the bearer object! */
|
||||
g_free (command);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 3GPP Dialing (sub-step of the 3GPP Connection sequence) */
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
MMPortSerialAt *primary;
|
||||
guint cid;
|
||||
MMPort *data;
|
||||
guint authentication_retries;
|
||||
GError *saved_error;
|
||||
} Dial3gppContext;
|
||||
|
||||
static void
|
||||
dial_3gpp_context_free (Dial3gppContext *ctx)
|
||||
{
|
||||
g_assert (!ctx->saved_error);
|
||||
g_clear_object (&ctx->data);
|
||||
g_clear_object (&ctx->primary);
|
||||
g_clear_object (&ctx->modem);
|
||||
g_slice_free (Dial3gppContext, ctx);
|
||||
}
|
||||
|
||||
static guint
|
||||
dial_3gpp_get_connecting_cid (GTask *task)
|
||||
{
|
||||
Dial3gppContext *ctx;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
return ctx->cid;
|
||||
}
|
||||
|
||||
static MMPort *
|
||||
dial_3gpp_finish (MMBroadbandBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return MM_PORT (g_task_propagate_pointer (G_TASK (res), error));
|
||||
}
|
||||
|
||||
static void
|
||||
connect_reset_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
Dial3gppContext *ctx;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
mm_base_modem_at_command_full_finish (modem, res, NULL);
|
||||
|
||||
/* When reset is requested, it was either cancelled or an error was stored */
|
||||
if (!g_task_return_error_if_cancelled (task)) {
|
||||
g_assert (ctx->saved_error);
|
||||
g_task_return_error (task, ctx->saved_error);
|
||||
ctx->saved_error = NULL;
|
||||
}
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_reset (GTask *task)
|
||||
{
|
||||
Dial3gppContext *ctx;
|
||||
gchar *command;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Need to reset the connection attempt */
|
||||
command = g_strdup_printf ("%%IPDPACT=%d,0", ctx->cid);
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
command,
|
||||
MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT,
|
||||
FALSE,
|
||||
FALSE, /* raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback)connect_reset_ready,
|
||||
task);
|
||||
g_free (command);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
connect_timed_out_cb (MMBroadbandBearerIcera *self)
|
||||
{
|
||||
GTask *task;
|
||||
Dial3gppContext *ctx;
|
||||
|
||||
/* Cleanup timeout ID */
|
||||
self->priv->connect_pending_id = 0;
|
||||
|
||||
/* Recover task and own it */
|
||||
task = self->priv->connect_pending;
|
||||
self->priv->connect_pending = NULL;
|
||||
g_assert (task);
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Remove closed port watch, if found */
|
||||
if (self->priv->connect_port_closed_id) {
|
||||
g_signal_handler_disconnect (ctx->primary, self->priv->connect_port_closed_id);
|
||||
self->priv->connect_port_closed_id = 0;
|
||||
}
|
||||
|
||||
/* Setup error to return after the reset */
|
||||
g_assert (!ctx->saved_error);
|
||||
ctx->saved_error = g_error_new (MM_MOBILE_EQUIPMENT_ERROR,
|
||||
MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT,
|
||||
"Connection attempt timed out");
|
||||
|
||||
/* It's probably pointless to try to reset this here, but anyway... */
|
||||
connect_reset (task);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
ier_query_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBroadbandBearerIcera *self;
|
||||
const gchar *response;
|
||||
GError *activation_error = NULL;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
response = mm_base_modem_at_command_full_finish (modem, res, NULL);
|
||||
if (response) {
|
||||
gint nw_activation_err;
|
||||
|
||||
response = mm_strip_tag (response, "%IER:");
|
||||
if (sscanf (response, "%*d,%*d,%d", &nw_activation_err)) {
|
||||
/* 3GPP TS 24.008 Annex G error codes:
|
||||
* 27 - Unknown or missing access point name
|
||||
* 33 - Requested service option not subscribed
|
||||
*/
|
||||
if (nw_activation_err == 27 || nw_activation_err == 33)
|
||||
activation_error = mm_mobile_equipment_error_for_code (MM_MOBILE_EQUIPMENT_ERROR_SERVICE_OPTION_NOT_SUBSCRIBED, self);
|
||||
}
|
||||
}
|
||||
|
||||
if (activation_error)
|
||||
g_task_return_error (task, activation_error);
|
||||
else
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Call setup failed");
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
process_pending_connect_attempt (MMBroadbandBearerIcera *self,
|
||||
MMBearerConnectionStatus status)
|
||||
{
|
||||
GTask *task;
|
||||
Dial3gppContext *ctx;
|
||||
|
||||
/* Recover task and remove both cancellation and timeout (if any)*/
|
||||
g_assert (self->priv->connect_pending);
|
||||
task = self->priv->connect_pending;
|
||||
self->priv->connect_pending = NULL;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
if (self->priv->connect_pending_id) {
|
||||
g_source_remove (self->priv->connect_pending_id);
|
||||
self->priv->connect_pending_id = 0;
|
||||
}
|
||||
|
||||
if (self->priv->connect_port_closed_id) {
|
||||
g_signal_handler_disconnect (ctx->primary, self->priv->connect_port_closed_id);
|
||||
self->priv->connect_port_closed_id = 0;
|
||||
}
|
||||
|
||||
/* Received 'CONNECTED' during a connection attempt? */
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_CONNECTED) {
|
||||
/* If we wanted to get cancelled before, do it now. */
|
||||
if (g_cancellable_is_cancelled (g_task_get_cancellable (task))) {
|
||||
connect_reset (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we wanted to get cancelled before and now we couldn't connect,
|
||||
* use the cancelled error and return */
|
||||
if (g_task_return_error_if_cancelled (task)) {
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Received CONNECTION_FAILED during a connection attempt? */
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED) {
|
||||
/* Try to gather additional info about the connection failure */
|
||||
mm_base_modem_at_command_full (
|
||||
ctx->modem,
|
||||
ctx->primary,
|
||||
"%IER?",
|
||||
60,
|
||||
FALSE,
|
||||
FALSE, /* raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback) ier_query_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, received 'DISCONNECTED' during a connection attempt? */
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Call setup failed");
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
forced_close_cb (MMBroadbandBearerIcera *self)
|
||||
{
|
||||
/* Just treat the forced close event as any other unsolicited message */
|
||||
mm_base_bearer_report_connection_status (MM_BASE_BEARER (self),
|
||||
MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED);
|
||||
}
|
||||
|
||||
static void
|
||||
activate_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
MMBroadbandBearerIcera *self)
|
||||
{
|
||||
GTask *task;
|
||||
Dial3gppContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
task = g_steal_pointer (&self->priv->connect_pending);
|
||||
|
||||
/* Try to recover the connection context. If none found, it means the
|
||||
* context was already completed and we have nothing else to do. */
|
||||
if (!task) {
|
||||
mm_obj_dbg (self, "connection context was finished already by an unsolicited message");
|
||||
/* Run _finish() to finalize the async call, even if we don't care
|
||||
* the result */
|
||||
mm_base_modem_at_command_full_finish (modem, res, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Errors on the dial command are fatal */
|
||||
if (!mm_base_modem_at_command_full_finish (modem, res, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Track again */
|
||||
self->priv->connect_pending = task;
|
||||
|
||||
/* We will now setup a timeout and keep the context in the bearer's private.
|
||||
* Reports of modem being connected will arrive via unsolicited messages.
|
||||
* This timeout should be long enough. Actually... ideally should never get
|
||||
* reached. */
|
||||
self->priv->connect_pending_id = g_timeout_add_seconds (MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT,
|
||||
(GSourceFunc)connect_timed_out_cb,
|
||||
self);
|
||||
|
||||
/* If we get the port closed, we treat as a connect error */
|
||||
ctx = g_task_get_task_data (task);
|
||||
self->priv->connect_port_closed_id = g_signal_connect_swapped (ctx->primary,
|
||||
"forced-close",
|
||||
G_CALLBACK (forced_close_cb),
|
||||
self);
|
||||
|
||||
out:
|
||||
/* Balance refcount with the extra ref we passed to command_full() */
|
||||
g_object_unref (self);
|
||||
}
|
||||
|
||||
static void
|
||||
dial_3gpp (MMBroadbandBearer *_self,
|
||||
MMBaseModem *modem,
|
||||
MMPortSerialAt *primary,
|
||||
guint cid,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandBearerIcera *self = MM_BROADBAND_BEARER_ICERA (_self);
|
||||
GTask *task;
|
||||
Dial3gppContext *ctx;
|
||||
g_autofree gchar *cmd = NULL;
|
||||
|
||||
g_assert (primary != NULL);
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
|
||||
ctx = g_slice_new0 (Dial3gppContext);
|
||||
ctx->modem = g_object_ref (modem);
|
||||
ctx->primary = g_object_ref (primary);
|
||||
ctx->cid = cid;
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)dial_3gpp_context_free);
|
||||
|
||||
/* We need a net data port */
|
||||
ctx->data = mm_base_modem_get_best_data_port (modem, MM_PORT_TYPE_NET);
|
||||
if (!ctx->data) {
|
||||
g_task_return_new_error (task,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_NOT_FOUND,
|
||||
"No valid data port found to launch connection");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The unsolicited response to %IPDPACT may come before the OK does.
|
||||
* We will keep the connection context in the bearer private data so
|
||||
* that it is accessible from the unsolicited message handler. Note
|
||||
* also that we do NOT pass the ctx to the GAsyncReadyCallback, as it
|
||||
* may not be valid any more when the callback is called (it may be
|
||||
* already completed in the unsolicited handling) */
|
||||
g_assert (self->priv->connect_pending == NULL);
|
||||
self->priv->connect_pending = task;
|
||||
|
||||
cmd = g_strdup_printf ("%%IPDPACT=%d,1", ctx->cid);
|
||||
mm_base_modem_at_command_full (ctx->modem,
|
||||
ctx->primary,
|
||||
cmd,
|
||||
MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT,
|
||||
FALSE,
|
||||
FALSE, /* raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback) activate_ready,
|
||||
g_object_ref (self)); /* we pass the bearer object! */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gint
|
||||
mm_broadband_bearer_icera_get_connecting_profile_id (MMBroadbandBearerIcera *self)
|
||||
{
|
||||
return (self->priv->connect_pending ?
|
||||
(gint)dial_3gpp_get_connecting_cid (self->priv->connect_pending) :
|
||||
MM_3GPP_PROFILE_ID_UNKNOWN);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
report_connection_status (MMBaseBearer *_self,
|
||||
MMBearerConnectionStatus status,
|
||||
const GError *connection_error)
|
||||
{
|
||||
MMBroadbandBearerIcera *self = MM_BROADBAND_BEARER_ICERA (_self);
|
||||
|
||||
g_assert (status == MM_BEARER_CONNECTION_STATUS_CONNECTED ||
|
||||
status == MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED ||
|
||||
status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
|
||||
|
||||
/* Process pending connection attempt */
|
||||
if (self->priv->connect_pending) {
|
||||
process_pending_connect_attempt (self, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process pending disconnection attempt */
|
||||
if (self->priv->disconnect_pending) {
|
||||
process_pending_disconnect_attempt (self, status);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "received spontaneous %%IPDPACT (%s)", mm_bearer_connection_status_get_string (status));
|
||||
|
||||
/* Received a random 'DISCONNECTED'...*/
|
||||
if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED ||
|
||||
status == MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED) {
|
||||
/* If no connection/disconnection attempt on-going, make sure we mark ourselves as
|
||||
* disconnected. Make sure we only pass 'DISCONNECTED' to the parent */
|
||||
MM_BASE_BEARER_CLASS (mm_broadband_bearer_icera_parent_class)->report_connection_status (
|
||||
_self,
|
||||
MM_BEARER_CONNECTION_STATUS_DISCONNECTED,
|
||||
connection_error);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseBearer *
|
||||
mm_broadband_bearer_icera_new_finish (GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
GObject *source;
|
||||
GObject *bearer;
|
||||
|
||||
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_base_bearer_export (MM_BASE_BEARER (bearer));
|
||||
|
||||
return MM_BASE_BEARER (bearer);
|
||||
}
|
||||
|
||||
void
|
||||
mm_broadband_bearer_icera_new (MMBroadbandModem *modem,
|
||||
MMBearerIpMethod ip_method,
|
||||
MMBearerProperties *config,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (
|
||||
MM_TYPE_BROADBAND_BEARER_ICERA,
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data,
|
||||
MM_BASE_BEARER_MODEM, modem,
|
||||
MM_BASE_BEARER_CONFIG, config,
|
||||
MM_BROADBAND_BEARER_ICERA_DEFAULT_IP_METHOD, ip_method,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MMBroadbandBearerIcera *self = MM_BROADBAND_BEARER_ICERA (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DEFAULT_IP_METHOD:
|
||||
self->priv->default_ip_method = g_value_get_enum (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MMBroadbandBearerIcera *self = MM_BROADBAND_BEARER_ICERA (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DEFAULT_IP_METHOD:
|
||||
g_value_set_enum (value, self->priv->default_ip_method);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_icera_init (MMBroadbandBearerIcera *self)
|
||||
{
|
||||
/* Initialize private data */
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
MM_TYPE_BROADBAND_BEARER_ICERA,
|
||||
MMBroadbandBearerIceraPrivate);
|
||||
|
||||
/* Defaults */
|
||||
self->priv->default_ip_method = MM_BEARER_IP_METHOD_STATIC;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_bearer_icera_class_init (MMBroadbandBearerIceraClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass);
|
||||
MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (MMBroadbandBearerIceraPrivate));
|
||||
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
|
||||
base_bearer_class->report_connection_status = report_connection_status;
|
||||
base_bearer_class->load_connection_status = NULL;
|
||||
base_bearer_class->load_connection_status_finish = NULL;
|
||||
#if defined WITH_SUSPEND_RESUME
|
||||
base_bearer_class->reload_connection_status = NULL;
|
||||
base_bearer_class->reload_connection_status_finish = NULL;
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
properties[PROP_DEFAULT_IP_METHOD] =
|
||||
g_param_spec_enum (MM_BROADBAND_BEARER_ICERA_DEFAULT_IP_METHOD,
|
||||
"Default IP method",
|
||||
"Default IP Method (static or DHCP) to use.",
|
||||
MM_TYPE_BEARER_IP_METHOD,
|
||||
MM_BEARER_IP_METHOD_STATIC,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (object_class, PROP_DEFAULT_IP_METHOD, properties[PROP_DEFAULT_IP_METHOD]);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -*- 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:
|
||||
*
|
||||
* Author: Nathan Williams <njw@google.com>
|
||||
*
|
||||
* Copyright (C) 2012 Google, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_BEARER_ICERA_H
|
||||
#define MM_BROADBAND_BEARER_ICERA_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-broadband-bearer.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_BEARER_ICERA (mm_broadband_bearer_icera_get_type ())
|
||||
#define MM_BROADBAND_BEARER_ICERA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_BEARER_ICERA, MMBroadbandBearerIcera))
|
||||
#define MM_BROADBAND_BEARER_ICERA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_BEARER_ICERA, MMBroadbandBearerIceraClass))
|
||||
#define MM_IS_BROADBAND_BEARER_ICERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_BEARER_ICERA))
|
||||
#define MM_IS_BROADBAND_BEARER_ICERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_BEARER_ICERA))
|
||||
#define MM_BROADBAND_BEARER_ICERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_BEARER_ICERA, MMBroadbandBearerIceraClass))
|
||||
|
||||
#define MM_BROADBAND_BEARER_ICERA_DEFAULT_IP_METHOD "broadband-bearer-icera-default-ip-method"
|
||||
|
||||
typedef struct _MMBroadbandBearerIcera MMBroadbandBearerIcera;
|
||||
typedef struct _MMBroadbandBearerIceraClass MMBroadbandBearerIceraClass;
|
||||
typedef struct _MMBroadbandBearerIceraPrivate MMBroadbandBearerIceraPrivate;
|
||||
|
||||
struct _MMBroadbandBearerIcera {
|
||||
MMBroadbandBearer parent;
|
||||
MMBroadbandBearerIceraPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMBroadbandBearerIceraClass {
|
||||
MMBroadbandBearerClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_bearer_icera_get_type (void);
|
||||
|
||||
/* Default bearer creation implementation */
|
||||
void mm_broadband_bearer_icera_new (MMBroadbandModem *modem,
|
||||
MMBearerIpMethod ip_method,
|
||||
MMBearerProperties *config,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
MMBaseBearer *mm_broadband_bearer_icera_new_finish (GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
gint mm_broadband_bearer_icera_get_connecting_profile_id (MMBroadbandBearerIcera *self);
|
||||
|
||||
#endif /* MM_BROADBAND_BEARER_ICERA_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org>
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_ICERA_H
|
||||
#define MM_BROADBAND_MODEM_ICERA_H
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_ICERA (mm_broadband_modem_icera_get_type ())
|
||||
#define MM_BROADBAND_MODEM_ICERA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_ICERA, MMBroadbandModemIcera))
|
||||
#define MM_BROADBAND_MODEM_ICERA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_ICERA, MMBroadbandModemIceraClass))
|
||||
#define MM_IS_BROADBAND_MODEM_ICERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_ICERA))
|
||||
#define MM_IS_BROADBAND_MODEM_ICERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_ICERA))
|
||||
#define MM_BROADBAND_MODEM_ICERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_ICERA, MMBroadbandModemIceraClass))
|
||||
|
||||
#define MM_BROADBAND_MODEM_ICERA_DEFAULT_IP_METHOD "broadband-modem-icera-default-ip-method"
|
||||
|
||||
typedef struct _MMBroadbandModemIcera MMBroadbandModemIcera;
|
||||
typedef struct _MMBroadbandModemIceraClass MMBroadbandModemIceraClass;
|
||||
typedef struct _MMBroadbandModemIceraPrivate MMBroadbandModemIceraPrivate;
|
||||
|
||||
struct _MMBroadbandModemIcera {
|
||||
MMBroadbandModem parent;
|
||||
MMBroadbandModemIceraPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemIceraClass{
|
||||
MMBroadbandModemClass parent;
|
||||
};
|
||||
|
||||
G_MODULE_EXPORT
|
||||
GType mm_broadband_modem_icera_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT
|
||||
MMBroadbandModemIcera *mm_broadband_modem_icera_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_ICERA_H */
|
||||
@@ -0,0 +1,389 @@
|
||||
/* -*- 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) 2012 Google, Inc.
|
||||
* Copyright (C) 2012 - 2013 Aleksander Morgado <aleksander@gnu.org>
|
||||
* Copyright (C) 2014 Dan Williams <dcbw@redhat.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-log.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-modem-helpers-icera.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* %IPDPADDR response parser */
|
||||
|
||||
static MMBearerIpConfig *
|
||||
parse_ipdpaddr_v4 (const gchar **items, guint num_items, GError **error)
|
||||
{
|
||||
MMBearerIpConfig *config;
|
||||
const gchar *dns[3] = { 0 };
|
||||
guint dns_i = 0, tmp;
|
||||
const gchar *netmask = NULL;
|
||||
|
||||
/* IP address and prefix */
|
||||
tmp = 0;
|
||||
if (!inet_pton (AF_INET, items[1], &tmp)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse IPv4 address '%s'", items[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!tmp) {
|
||||
/* No IPv4 config */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config = mm_bearer_ip_config_new ();
|
||||
mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_STATIC);
|
||||
mm_bearer_ip_config_set_address (config, items[1]);
|
||||
mm_bearer_ip_config_set_prefix (config, 32); /* default prefix */
|
||||
|
||||
/* Gateway */
|
||||
tmp = 0;
|
||||
if (inet_pton (AF_INET, items[2], &tmp)) {
|
||||
if (tmp)
|
||||
mm_bearer_ip_config_set_gateway (config, items[2]);
|
||||
} else {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse gateway address '%s'", items[2]);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* DNS */
|
||||
tmp = 0;
|
||||
if (inet_pton (AF_INET, items[3], &tmp) && tmp)
|
||||
dns[dns_i++] = items[3];
|
||||
else {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse DNS address '%s'", items[3]);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* DNS2 - sometimes missing and set to 0.0.0.0 */
|
||||
tmp = 0;
|
||||
if (inet_pton (AF_INET, items[4], &tmp) && tmp)
|
||||
dns[dns_i++] = items[4];
|
||||
if (dns_i > 0)
|
||||
mm_bearer_ip_config_set_dns (config, (const gchar **) dns);
|
||||
|
||||
/* Short form (eg, Sierra USB305) */
|
||||
if (num_items < 9)
|
||||
return config;
|
||||
|
||||
/* Devices return netmask and secondary gateway in one of two
|
||||
* positions. The netmask may be either at index 7 or 8, while
|
||||
* the secondary gateway may be at position 8 or 9.
|
||||
*/
|
||||
|
||||
if (items[7] && strstr (items[7], "255.") && !strstr (items[7], "255.0.0.0"))
|
||||
netmask = items[7];
|
||||
if (items[8] && strstr (items[8], "255.") && !strstr (items[8], "255.0.0.0"))
|
||||
netmask = items[8];
|
||||
if (netmask) {
|
||||
if (!inet_pton (AF_INET, netmask, &tmp)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse netmask '%s'",
|
||||
netmask);
|
||||
goto error;
|
||||
}
|
||||
mm_bearer_ip_config_set_prefix (config, mm_netmask_to_cidr (netmask));
|
||||
}
|
||||
|
||||
/* Secondary gateway */
|
||||
if (!mm_bearer_ip_config_get_gateway (config)) {
|
||||
const char *gw2 = NULL;
|
||||
|
||||
if (num_items >= 10 && items[9] && !strstr (items[9], "255.") && !strstr (items[9], "::"))
|
||||
gw2 = items[9];
|
||||
/* Prefer position 8 */
|
||||
if (items[8] && !strstr (items[8], "255."))
|
||||
gw2 = items[8];
|
||||
|
||||
if (gw2 && inet_pton (AF_INET, gw2, &tmp) && tmp)
|
||||
mm_bearer_ip_config_set_gateway (config, gw2);
|
||||
else {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse secondary gateway address '%s'",
|
||||
gw2 ? gw2 : "(unknown)");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
|
||||
error:
|
||||
g_object_unref (config);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static MMBearerIpConfig *
|
||||
parse_ipdpaddr_v6 (const gchar **items, guint num_items, GError **error)
|
||||
{
|
||||
MMBearerIpConfig *config;
|
||||
const gchar *dns[2] = { 0 };
|
||||
struct in6_addr tmp6 = IN6ADDR_ANY_INIT;
|
||||
|
||||
if (num_items < 12)
|
||||
return NULL;
|
||||
|
||||
/* No IPv6 IP and no IPv6 DNS, return NULL without error. */
|
||||
if (g_strcmp0 (items[9], "::") == 0 && g_strcmp0 (items[11], "::") == 0)
|
||||
return NULL;
|
||||
|
||||
config = mm_bearer_ip_config_new ();
|
||||
|
||||
/* It appears that for IPv6 %IPDPADDR returns only the expected
|
||||
* link-local address and a DNS address, and that to retrieve the
|
||||
* default router, extra DNS, and search domains, the host must listen
|
||||
* for IPv6 Router Advertisements on the net port.
|
||||
*/
|
||||
if (g_strcmp0 (items[9], "::") != 0) {
|
||||
mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_STATIC);
|
||||
/* IP address and prefix */
|
||||
if (inet_pton (AF_INET6, items[9], &tmp6) != 1 ||
|
||||
IN6_IS_ADDR_UNSPECIFIED (&tmp6)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse IPv6 address '%s'", items[9]);
|
||||
goto error;
|
||||
}
|
||||
mm_bearer_ip_config_set_address (config, items[9]);
|
||||
mm_bearer_ip_config_set_prefix (config, 64);
|
||||
|
||||
/* If the address is a link-local one, then SLAAC or DHCP must be used
|
||||
* to get the real prefix and address. Change the method to DHCP to
|
||||
* indicate this to clients.
|
||||
*/
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&tmp6))
|
||||
mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP);
|
||||
} else {
|
||||
/* No IPv6 given, but DNS will be available, try with DHCP */
|
||||
mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_DHCP);
|
||||
}
|
||||
|
||||
/* DNS server */
|
||||
if (g_strcmp0 (items[11], "::") != 0) {
|
||||
memset (&tmp6, 0, sizeof (tmp6));
|
||||
if (inet_pton (AF_INET6, items[11], &tmp6) == 1 &&
|
||||
!IN6_IS_ADDR_UNSPECIFIED (&tmp6)) {
|
||||
dns[0] = items[11];
|
||||
dns[1] = NULL;
|
||||
mm_bearer_ip_config_set_dns (config, (const gchar **) dns);
|
||||
} else {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't parse DNS address '%s'", items[11]);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
|
||||
error:
|
||||
g_object_unref (config);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define IPDPADDR_TAG "%IPDPADDR: "
|
||||
|
||||
gboolean
|
||||
mm_icera_parse_ipdpaddr_response (const gchar *response,
|
||||
guint expected_cid,
|
||||
MMBearerIpConfig **out_ip4_config,
|
||||
MMBearerIpConfig **out_ip6_config,
|
||||
GError **error)
|
||||
{
|
||||
MMBearerIpConfig *ip4_config = NULL;
|
||||
MMBearerIpConfig *ip6_config = NULL;
|
||||
GError *local = NULL;
|
||||
gboolean success = FALSE;
|
||||
char **items;
|
||||
guint num_items, i;
|
||||
guint num;
|
||||
|
||||
g_return_val_if_fail (out_ip4_config, FALSE);
|
||||
g_return_val_if_fail (out_ip6_config, FALSE);
|
||||
|
||||
if (!response || !g_str_has_prefix (response, IPDPADDR_TAG)) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing %%IPDPADDR prefix");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>[,<nbns1>,<nbns2>[,<??>,<netmask>,<gw>]]
|
||||
* %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>,<nbns1>,<nbns2>,<netmask>,<gw>
|
||||
* %IPDPADDR: <cid>,<ip>,<gw>,<dns1>,<dns2>,<nbns1>,<nbns2>,<??>,<gw>,<ip6>,::,<ip6_dns1>,::,::,::,::,::
|
||||
*
|
||||
* Sierra USB305: %IPDPADDR: 2, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0
|
||||
* K3805-Z: %IPDPADDR: 2, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 255.255.255.0, 21.93.217.10,
|
||||
* Nokia 21M: %IPDPADDR: 2, 33.196.7.127, 33.196.7.128, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 33.196.7.128, fe80::f:9135:5901, ::, fd00:976a::9, ::, ::, ::, ::, ::
|
||||
* Nokia 21M: %IPDPADDR: 3, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, fe80::2e:437b:7901, ::, fd00:976a::9, ::, ::, ::, ::, ::
|
||||
*/
|
||||
response = mm_strip_tag (response, IPDPADDR_TAG);
|
||||
items = g_strsplit_set (response, ",", 0);
|
||||
|
||||
/* Strip any spaces on elements; inet_pton() doesn't like them */
|
||||
num_items = g_strv_length (items);
|
||||
for (i = 0; i < num_items; i++)
|
||||
items[i] = g_strstrip (items[i]);
|
||||
|
||||
if (num_items < 7) {
|
||||
g_set_error_literal (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Malformed IPDPADDR response (not enough items)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Validate context ID */
|
||||
if (!mm_get_uint_from_str (items[0], &num) ||
|
||||
num != expected_cid) {
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Unknown CID in IPDPADDR response (got %d, expected %d)",
|
||||
(guint) num,
|
||||
expected_cid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ip4_config = parse_ipdpaddr_v4 ((const gchar **) items, num_items, &local);
|
||||
if (local) {
|
||||
g_propagate_error (error, local);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ip6_config = parse_ipdpaddr_v6 ((const gchar **) items, num_items, &local);
|
||||
if (local) {
|
||||
g_propagate_error (error, local);
|
||||
goto out;
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
|
||||
out:
|
||||
g_strfreev (items);
|
||||
|
||||
*out_ip4_config = ip4_config;
|
||||
*out_ip6_config = ip6_config;
|
||||
return success;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* %IPDPCFG? response parser.
|
||||
* Modifies the input list of profiles in place
|
||||
*
|
||||
* AT%IPDPCFG?
|
||||
* %IPDPCFG: 1,0,0,,,0
|
||||
* %IPDPCFG: 2,0,0,,,0
|
||||
* %IPDPCFG: 3,0,2,"user","pass",0
|
||||
* %IPDPCFG: 4,0,0,,,0
|
||||
* OK
|
||||
*/
|
||||
|
||||
gboolean
|
||||
mm_icera_parse_ipdpcfg_query_response (const gchar *str,
|
||||
GList *profiles,
|
||||
gpointer log_object,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GRegex) r = NULL;
|
||||
g_autoptr(GError) inner_error = NULL;
|
||||
g_autoptr(GMatchInfo) match_info = NULL;
|
||||
guint n_updates = 0;
|
||||
guint n_profiles;
|
||||
|
||||
n_profiles = g_list_length (profiles);
|
||||
|
||||
r = g_regex_new ("%IPDPCFG:\\s*(\\d+),(\\d+),(\\d+),([^,]*),([^,]*),(\\d+)",
|
||||
G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
|
||||
0, NULL);
|
||||
g_assert (r != NULL);
|
||||
|
||||
g_regex_match_full (r, str, strlen (str), 0, 0, &match_info, &inner_error);
|
||||
if (inner_error) {
|
||||
g_propagate_error (error, inner_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Parse the results */
|
||||
while (g_match_info_matches (match_info)) {
|
||||
guint cid;
|
||||
guint auth;
|
||||
MMBearerAllowedAuth allowed_auth;
|
||||
g_autofree gchar *user = NULL;
|
||||
g_autofree gchar *password = NULL;
|
||||
GList *l;
|
||||
|
||||
if (!mm_get_uint_from_match_info (match_info, 1, &cid)) {
|
||||
mm_obj_warn (log_object, "couldn't parse cid from %%IPDPCFG line");
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (!mm_get_uint_from_match_info (match_info, 3, &auth)) {
|
||||
mm_obj_warn (log_object, "couldn't parse auth from %%IPDPCFG line");
|
||||
goto next;
|
||||
}
|
||||
|
||||
switch (auth) {
|
||||
case 0:
|
||||
allowed_auth = MM_BEARER_ALLOWED_AUTH_NONE;
|
||||
break;
|
||||
case 1:
|
||||
allowed_auth = MM_BEARER_ALLOWED_AUTH_PAP;
|
||||
break;
|
||||
case 2:
|
||||
allowed_auth = MM_BEARER_ALLOWED_AUTH_CHAP;
|
||||
break;
|
||||
default:
|
||||
mm_obj_warn (log_object, "unexpected icera auth setting: %u", auth);
|
||||
goto next;
|
||||
}
|
||||
|
||||
user = mm_get_string_unquoted_from_match_info (match_info, 4);
|
||||
password = mm_get_string_unquoted_from_match_info (match_info, 5);
|
||||
|
||||
mm_obj_dbg (log_object, "found icera auth settings for profile with id '%u'", cid);
|
||||
|
||||
/* Find profile and update in place */
|
||||
for (l = profiles; l; l = g_list_next (l)) {
|
||||
MM3gppProfile *iter = l->data;
|
||||
|
||||
if (mm_3gpp_profile_get_profile_id (iter) == (gint) cid) {
|
||||
n_updates++;
|
||||
mm_3gpp_profile_set_allowed_auth (iter, allowed_auth);
|
||||
mm_3gpp_profile_set_user (iter, user);
|
||||
mm_3gpp_profile_set_password (iter, password);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!l)
|
||||
mm_obj_warn (log_object, "couldn't update auth settings in profile with id '%d': not found", cid);
|
||||
|
||||
next:
|
||||
g_match_info_next (match_info, NULL);
|
||||
}
|
||||
|
||||
if (n_updates != n_profiles)
|
||||
mm_obj_warn (log_object, "couldn't update auth settings in all profiles: %u/%u updated",
|
||||
n_updates, n_profiles);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* -*- 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) 2014 Dan Williams <dcbw@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_MODEM_HELPERS_ICERA_H
|
||||
#define MM_MODEM_HELPERS_ICERA_H
|
||||
|
||||
#include "glib.h"
|
||||
|
||||
/* %IPDPADDR response parser */
|
||||
gboolean mm_icera_parse_ipdpaddr_response (const gchar *response,
|
||||
guint expected_cid,
|
||||
MMBearerIpConfig **out_ip4_config,
|
||||
MMBearerIpConfig **out_ip6_config,
|
||||
GError **error);
|
||||
|
||||
/* %IPDPCFG? response parser */
|
||||
gboolean mm_icera_parse_ipdpcfg_query_response (const gchar *response,
|
||||
GList *profiles,
|
||||
gpointer log_object,
|
||||
GError **error);
|
||||
|
||||
#endif /* MM_MODEM_HELPERS_HUAWEI_H */
|
||||
@@ -0,0 +1,20 @@
|
||||
/* -*- 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) 2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
*/
|
||||
|
||||
#include "mm-shared.h"
|
||||
|
||||
MM_SHARED_DEFINE_MAJOR_VERSION
|
||||
MM_SHARED_DEFINE_MINOR_VERSION
|
||||
MM_SHARED_DEFINE_NAME(Icera)
|
||||
@@ -0,0 +1,262 @@
|
||||
/* -*- 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 Aleksander Morgado <aleksander@gnu.org>
|
||||
* Copyright (C) 2014 Dan Williams <dcbw@redhat.com>
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <locale.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-log-test.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-modem-helpers-icera.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test %IPDPADDR responses */
|
||||
|
||||
typedef struct {
|
||||
const gchar *str;
|
||||
const guint expected_cid;
|
||||
|
||||
/* IPv4 */
|
||||
const gchar *ipv4_addr;
|
||||
const guint ipv4_prefix;
|
||||
const gchar *ipv4_gw;
|
||||
const gchar *ipv4_dns1;
|
||||
const gchar *ipv4_dns2;
|
||||
|
||||
/* IPv6 */
|
||||
const gchar *ipv6_addr;
|
||||
const gchar *ipv6_dns1;
|
||||
} IpdpaddrTest;
|
||||
|
||||
static const IpdpaddrTest ipdpaddr_tests[] = {
|
||||
/* Sierra USB305 */
|
||||
{ "%IPDPADDR: 2, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0\r\n",
|
||||
2, "21.93.217.11", 32, "21.93.217.10", "10.177.0.34", "10.161.171.220",
|
||||
NULL, NULL },
|
||||
|
||||
/* ZTE/Vodafone K3805-Z */
|
||||
{ "%IPDPADDR: 5, 21.93.217.11, 21.93.217.10, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 255.255.255.0, 21.93.217.10,\r\n",
|
||||
5, "21.93.217.11", 24, "21.93.217.10", "10.177.0.34", "10.161.171.220",
|
||||
NULL, NULL },
|
||||
|
||||
/* Secondary gateway check */
|
||||
{ "%IPDPADDR: 5, 21.93.217.11, 0.0.0.0, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 255.255.255.0, 21.93.217.10,\r\n",
|
||||
5, "21.93.217.11", 24, "21.93.217.10", "10.177.0.34", "10.161.171.220",
|
||||
NULL, NULL },
|
||||
|
||||
/* Secondary gateway check #2 */
|
||||
{ "%IPDPADDR: 5, 27.107.96.189, 0.0.0.0, 121.242.190.210, 121.242.190.181, 0.0.0.0, 0.0.0.0, 255.255.255.254, 27.107.96.188\r\n",
|
||||
5, "27.107.96.189", 31, "27.107.96.188", "121.242.190.210", "121.242.190.181",
|
||||
NULL, NULL },
|
||||
|
||||
/* Nokia 21M */
|
||||
{ "%IPDPADDR: 1, 33.196.7.127, 33.196.7.128, 10.177.0.34, 10.161.171.220, 0.0.0.0, 0.0.0.0, 255.0.0.0, 33.196.7.128, fe80::f:9135:5901, ::, fd00:976a::9, ::, ::, ::, ::, ::\r\n",
|
||||
1, "33.196.7.127", 32, "33.196.7.128", "10.177.0.34", "10.161.171.220",
|
||||
"fe80::f:9135:5901", "fd00:976a::9" },
|
||||
|
||||
{ "%IPDPADDR: 3, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, fe80::2e:437b:7901, ::, fd00:976a::9, ::, ::, ::, ::, ::\r\n",
|
||||
3, NULL, 0, NULL, NULL, NULL,
|
||||
"fe80::2e:437b:7901", "fd00:976a::9" },
|
||||
|
||||
/* Some development chip (cnsbg.p1001.rev2, CL477342) */
|
||||
{ "%IPDPADDR: 5, 27.107.96.189, 27.107.96.188, 121.242.190.210, 121.242.190.181, 0.0.0.0, 0.0.0.0, 255.255.255.254, 27.107.96.188\r\n",
|
||||
5, "27.107.96.189", 31, "27.107.96.188", "121.242.190.210", "121.242.190.181",
|
||||
NULL, NULL },
|
||||
|
||||
/* 21M with newer firmware */
|
||||
{ "%IPDPADDR: 2, 188.150.116.13, 188.150.116.14, 188.149.250.16, 0.0.0.0, 0.0.0.0, 0.0.0.0, 255.255.0.0, 188.150.116.14, fe80::1:e414:eb01, ::, 2a00:e18:0:3::6, ::, ::, ::, ::, ::\r\n",
|
||||
2, "188.150.116.13", 16, "188.150.116.14", "188.149.250.16", NULL,
|
||||
"fe80::1:e414:eb01", "2a00:e18:0:3::6" },
|
||||
|
||||
{ "%IPDPADDR: 1, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, fe80::1f:fad1:4c01, ::, 2001:4600:4:fff::54, 2001:4600:4:1fff::54, ::, ::, ::, ::\r\n",
|
||||
1, NULL, 0, NULL, NULL, NULL,
|
||||
"fe80::1f:fad1:4c01", "2001:4600:4:fff::54" },
|
||||
|
||||
{ "%IPDPADDR: 1, 46.157.76.179, 46.157.76.180, 193.213.112.4, 130.67.15.198, 0.0.0.0, 0.0.0.0, 255.0.0.0, 46.157.76.180, ::, ::, ::, ::, ::, ::, ::, ::\r\n",
|
||||
1, "46.157.76.179", 32, "46.157.76.180", "193.213.112.4", "130.67.15.198",
|
||||
NULL, NULL },
|
||||
|
||||
{ "%IPDPADDR: 1, 0.0.0.0, 0.0.0.0, 193.213.112.4, 130.67.15.198, 0.0.0.0, 0.0.0.0, 0.0.0.0, 0.0.0.0, ::, ::, 2001:4600:4:fff::52, 2001:4600:4:1fff::52, ::, ::, ::, ::",
|
||||
1, NULL, 0, NULL, NULL, NULL,
|
||||
NULL, "2001:4600:4:fff::52" },
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
test_ipdpaddr (void)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; ipdpaddr_tests[i].str; i++) {
|
||||
gboolean success;
|
||||
GError *error = NULL;
|
||||
MMBearerIpConfig *ipv4 = NULL;
|
||||
MMBearerIpConfig *ipv6 = NULL;
|
||||
const gchar **dns;
|
||||
guint dnslen;
|
||||
|
||||
success = mm_icera_parse_ipdpaddr_response (
|
||||
ipdpaddr_tests[i].str,
|
||||
ipdpaddr_tests[i].expected_cid,
|
||||
&ipv4,
|
||||
&ipv6,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (success);
|
||||
|
||||
/* IPv4 */
|
||||
if (ipdpaddr_tests[i].ipv4_addr) {
|
||||
g_assert (ipv4);
|
||||
g_assert_cmpint (mm_bearer_ip_config_get_method (ipv4), ==, MM_BEARER_IP_METHOD_STATIC);
|
||||
g_assert_cmpstr (mm_bearer_ip_config_get_address (ipv4), ==, ipdpaddr_tests[i].ipv4_addr);
|
||||
g_assert_cmpint (mm_bearer_ip_config_get_prefix (ipv4), ==, ipdpaddr_tests[i].ipv4_prefix);
|
||||
g_assert_cmpstr (mm_bearer_ip_config_get_gateway (ipv4), ==, ipdpaddr_tests[i].ipv4_gw);
|
||||
|
||||
dns = mm_bearer_ip_config_get_dns (ipv4);
|
||||
g_assert (dns);
|
||||
dnslen = g_strv_length ((gchar **) dns);
|
||||
if (ipdpaddr_tests[i].ipv4_dns2 != NULL)
|
||||
g_assert_cmpint (dnslen, ==, 2);
|
||||
else
|
||||
g_assert_cmpint (dnslen, ==, 1);
|
||||
g_assert_cmpstr (dns[0], ==, ipdpaddr_tests[i].ipv4_dns1);
|
||||
g_assert_cmpstr (dns[1], ==, ipdpaddr_tests[i].ipv4_dns2);
|
||||
g_object_unref (ipv4);
|
||||
} else
|
||||
g_assert (ipv4 == NULL);
|
||||
|
||||
/* IPv6 */
|
||||
if (ipdpaddr_tests[i].ipv6_addr || ipdpaddr_tests[i].ipv6_dns1) {
|
||||
struct in6_addr a6;
|
||||
g_assert (ipv6);
|
||||
|
||||
if (ipdpaddr_tests[i].ipv6_addr) {
|
||||
g_assert_cmpstr (mm_bearer_ip_config_get_address (ipv6), ==, ipdpaddr_tests[i].ipv6_addr);
|
||||
g_assert_cmpint (mm_bearer_ip_config_get_prefix (ipv6), ==, 64);
|
||||
|
||||
g_assert (inet_pton (AF_INET6, mm_bearer_ip_config_get_address (ipv6), &a6));
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&a6))
|
||||
g_assert_cmpint (mm_bearer_ip_config_get_method (ipv6), ==, MM_BEARER_IP_METHOD_DHCP);
|
||||
else
|
||||
g_assert_cmpint (mm_bearer_ip_config_get_method (ipv6), ==, MM_BEARER_IP_METHOD_STATIC);
|
||||
} else
|
||||
g_assert_cmpint (mm_bearer_ip_config_get_method (ipv6), ==, MM_BEARER_IP_METHOD_DHCP);
|
||||
|
||||
dns = mm_bearer_ip_config_get_dns (ipv6);
|
||||
g_assert (dns);
|
||||
dnslen = g_strv_length ((gchar **) dns);
|
||||
g_assert_cmpint (dnslen, ==, 1);
|
||||
g_assert_cmpstr (dns[0], ==, ipdpaddr_tests[i].ipv6_dns1);
|
||||
g_object_unref (ipv6);
|
||||
} else
|
||||
g_assert (ipv6 == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test %IPDPCFG responses */
|
||||
|
||||
static void
|
||||
test_ipdpcfg (void)
|
||||
{
|
||||
MM3gppProfile *profile;
|
||||
GList *profiles = NULL;
|
||||
GList *l;
|
||||
GError *error = NULL;
|
||||
gboolean result;
|
||||
gboolean cid_1_validated = FALSE;
|
||||
gboolean cid_2_validated = FALSE;
|
||||
gboolean cid_5_validated = FALSE;
|
||||
const gchar *response =
|
||||
"%IPDPCFG: 1,0,0,,,0\r\n"
|
||||
"%IPDPCFG: 2,0,1,\"aaaa\",\"bbbbb\",0\r\n"
|
||||
"%IPDPCFG: 5,0,2,\"user\",\"pass\",0"; /* last line without CRLF */
|
||||
|
||||
profile = mm_3gpp_profile_new ();
|
||||
mm_3gpp_profile_set_profile_id (profile, 1);
|
||||
mm_3gpp_profile_set_apn (profile, "internet");
|
||||
mm_3gpp_profile_set_ip_type (profile, MM_BEARER_IP_FAMILY_IPV4);
|
||||
profiles = g_list_append (profiles, profile);
|
||||
|
||||
profile = mm_3gpp_profile_new ();
|
||||
mm_3gpp_profile_set_profile_id (profile, 2);
|
||||
mm_3gpp_profile_set_apn (profile, "internet2");
|
||||
mm_3gpp_profile_set_ip_type (profile, MM_BEARER_IP_FAMILY_IPV4V6);
|
||||
profiles = g_list_append (profiles, profile);
|
||||
|
||||
profile = mm_3gpp_profile_new ();
|
||||
mm_3gpp_profile_set_profile_id (profile, 5);
|
||||
mm_3gpp_profile_set_apn (profile, "internet3");
|
||||
mm_3gpp_profile_set_ip_type (profile, MM_BEARER_IP_FAMILY_IPV6);
|
||||
profiles = g_list_append (profiles, profile);
|
||||
|
||||
result = mm_icera_parse_ipdpcfg_query_response (response, profiles, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (result);
|
||||
|
||||
for (l = profiles; l; l = g_list_next (l)) {
|
||||
MM3gppProfile *iter = l->data;
|
||||
|
||||
switch (mm_3gpp_profile_get_profile_id (iter)) {
|
||||
case 1:
|
||||
cid_1_validated = TRUE;
|
||||
g_assert_cmpuint (mm_3gpp_profile_get_allowed_auth (iter), ==, MM_BEARER_ALLOWED_AUTH_NONE);
|
||||
g_assert (!mm_3gpp_profile_get_user (iter));
|
||||
g_assert (!mm_3gpp_profile_get_password (iter));
|
||||
break;
|
||||
case 2:
|
||||
cid_2_validated = TRUE;
|
||||
g_assert_cmpuint (mm_3gpp_profile_get_allowed_auth (iter), ==, MM_BEARER_ALLOWED_AUTH_PAP);
|
||||
g_assert_cmpstr (mm_3gpp_profile_get_user (iter), ==, "aaaa");
|
||||
g_assert_cmpstr (mm_3gpp_profile_get_password (iter), ==, "bbbbb");
|
||||
break;
|
||||
case 5:
|
||||
cid_5_validated = TRUE;
|
||||
g_assert_cmpuint (mm_3gpp_profile_get_allowed_auth (iter), ==, MM_BEARER_ALLOWED_AUTH_CHAP);
|
||||
g_assert_cmpstr (mm_3gpp_profile_get_user (iter), ==, "user");
|
||||
g_assert_cmpstr (mm_3gpp_profile_get_password (iter), ==, "pass");
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
g_assert (cid_1_validated);
|
||||
g_assert (cid_2_validated);
|
||||
g_assert (cid_5_validated);
|
||||
|
||||
g_list_free_full (profiles, (GDestroyNotify)g_object_unref);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/MM/icera/ipdpaddr", test_ipdpaddr);
|
||||
g_test_add_func ("/MM/icera/ipdpcfg", test_ipdpcfg);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/* -*- 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) 2021-2022 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-broadband-modem-mbim-intel.h"
|
||||
#include "mm-iface-modem-location.h"
|
||||
#include "mm-shared-xmm.h"
|
||||
|
||||
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
||||
static void shared_xmm_init (MMSharedXmm *iface);
|
||||
|
||||
static MMIfaceModemLocation *iface_modem_location_parent;
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimIntel, mm_broadband_modem_mbim_intel, MM_TYPE_BROADBAND_MODEM_MBIM, 0,
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_XMM, shared_xmm_init))
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
setup_ports (MMBroadbandModem *self)
|
||||
{
|
||||
MMPortSerialAt *ports[3];
|
||||
guint i;
|
||||
|
||||
/* Run the shared XMM port setup logic */
|
||||
mm_shared_xmm_setup_ports (self);
|
||||
|
||||
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
||||
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
|
||||
|
||||
/* GNSS control port may or may not be a primary/secondary port */
|
||||
ports[2] = mm_base_modem_peek_port_gps_control (MM_BASE_MODEM (self));
|
||||
if (ports[2] && ((ports[2] == ports[0]) || (ports[2] == ports[1])))
|
||||
ports[2] = NULL;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (ports); i++) {
|
||||
if (!ports[i])
|
||||
continue;
|
||||
|
||||
g_object_set (ports[i],
|
||||
MM_PORT_SERIAL_SEND_DELAY, (guint64) 0,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBroadbandModemMbimIntel *
|
||||
mm_broadband_modem_mbim_intel_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_MBIM_INTEL,
|
||||
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,
|
||||
/* MBIM bearer supports NET only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE,
|
||||
MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE,
|
||||
MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, TRUE,
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
MM_BROADBAND_MODEM_MBIM_QMI_UNSUPPORTED, TRUE,
|
||||
#endif
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_intel_init (MMBroadbandModemMbimIntel *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_location_init (MMIfaceModemLocation *iface)
|
||||
{
|
||||
iface_modem_location_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->load_capabilities = mm_shared_xmm_location_load_capabilities;
|
||||
iface->load_capabilities_finish = mm_shared_xmm_location_load_capabilities_finish;
|
||||
iface->enable_location_gathering = mm_shared_xmm_enable_location_gathering;
|
||||
iface->enable_location_gathering_finish = mm_shared_xmm_enable_location_gathering_finish;
|
||||
iface->disable_location_gathering = mm_shared_xmm_disable_location_gathering;
|
||||
iface->disable_location_gathering_finish = mm_shared_xmm_disable_location_gathering_finish;
|
||||
iface->load_supl_server = mm_shared_xmm_location_load_supl_server;
|
||||
iface->load_supl_server_finish = mm_shared_xmm_location_load_supl_server_finish;
|
||||
iface->set_supl_server = mm_shared_xmm_location_set_supl_server;
|
||||
iface->set_supl_server_finish = mm_shared_xmm_location_set_supl_server_finish;
|
||||
}
|
||||
|
||||
static MMBroadbandModemClass *
|
||||
peek_parent_broadband_modem_class (MMSharedXmm *self)
|
||||
{
|
||||
return MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_mbim_intel_parent_class);
|
||||
}
|
||||
|
||||
static MMIfaceModemLocation *
|
||||
peek_parent_location_interface (MMSharedXmm *self)
|
||||
{
|
||||
return iface_modem_location_parent;
|
||||
}
|
||||
|
||||
static void
|
||||
shared_xmm_init (MMSharedXmm *iface)
|
||||
{
|
||||
iface->peek_parent_broadband_modem_class = peek_parent_broadband_modem_class;
|
||||
iface->peek_parent_location_interface = peek_parent_location_interface;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_mbim_intel_class_init (MMBroadbandModemMbimIntelClass *klass)
|
||||
{
|
||||
MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
|
||||
|
||||
broadband_modem_class->setup_ports = setup_ports;
|
||||
}
|
||||
@@ -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:
|
||||
*
|
||||
* Copyright (C) 2021-2022 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_MBIM_INTEL_H
|
||||
#define MM_BROADBAND_MODEM_MBIM_INTEL_H
|
||||
|
||||
#include "mm-broadband-modem-mbim.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_MBIM_INTEL (mm_broadband_modem_mbim_intel_get_type ())
|
||||
#define MM_BROADBAND_MODEM_MBIM_INTEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_INTEL, MMBroadbandModemMbimIntel))
|
||||
#define MM_BROADBAND_MODEM_MBIM_INTEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_INTEL, MMBroadbandModemMbimIntelClass))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_INTEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_INTEL))
|
||||
#define MM_IS_BROADBAND_MODEM_MBIM_INTEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_INTEL))
|
||||
#define MM_BROADBAND_MODEM_MBIM_INTEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_INTEL, MMBroadbandModemMbimIntelClass))
|
||||
|
||||
typedef struct _MMBroadbandModemMbimIntel MMBroadbandModemMbimIntel;
|
||||
typedef struct _MMBroadbandModemMbimIntelClass MMBroadbandModemMbimIntelClass;
|
||||
|
||||
struct _MMBroadbandModemMbimIntel {
|
||||
MMBroadbandModemMbim parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemMbimIntelClass{
|
||||
MMBroadbandModemMbimClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_mbim_intel_get_type (void);
|
||||
|
||||
MMBroadbandModemMbimIntel *mm_broadband_modem_mbim_intel_new (const gchar *device,
|
||||
const gchar **driver,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_MBIM_INTEL_H */
|
||||
@@ -0,0 +1,91 @@
|
||||
/* -*- 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) 2021-2022 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-plugin-intel.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#if defined WITH_MBIM
|
||||
#include "mm-broadband-modem-mbim-intel.h"
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (MMPluginIntel, mm_plugin_intel, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
#if defined WITH_MBIM
|
||||
if (mm_port_probe_list_has_mbim_port (probes)) {
|
||||
mm_obj_dbg (self, "MBIM-powered Intel modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_mbim_intel_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
#endif
|
||||
|
||||
mm_obj_dbg (self, "Generic Intel modem found...");
|
||||
return MM_BASE_MODEM (mm_broadband_modem_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "net", "wwan", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x8086, 0 };
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_INTEL,
|
||||
MM_PLUGIN_NAME, "Intel",
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
MM_PLUGIN_ALLOWED_MBIM, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_intel_init (MMPluginIntel *self)
|
||||
{
|
||||
/*nothing to be done here, but required for creating intel plugin instance*/
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_intel_class_init (MMPluginIntelClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -*- 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) 2021-2022 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_INTEL_H
|
||||
#define MM_PLUGIN_INTEL_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_INTEL (mm_plugin_intel_get_type ())
|
||||
#define MM_PLUGIN_INTEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_INTEL, MMPluginIntel))
|
||||
#define MM_PLUGIN_INTEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_INTEL, MMPluginIntelClass))
|
||||
#define MM_IS_PLUGIN_INTEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_INTEL))
|
||||
#define MM_IS_PLUGIN_INTEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_INTEL))
|
||||
#define MM_PLUGIN_INTEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_INTEL, MMPluginIntelClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginIntel;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginIntelClass;
|
||||
|
||||
GType mm_plugin_intel_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_INTEL_H */
|
||||
@@ -0,0 +1,266 @@
|
||||
/* -*- 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) 2012 Ammonit Measurement GmbH
|
||||
*/
|
||||
|
||||
#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-bearer-iridium.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
|
||||
/* Allow up to 200s to get a proper IP connection */
|
||||
#define BEARER_IRIDIUM_IP_TIMEOUT_DEFAULT 200
|
||||
|
||||
G_DEFINE_TYPE (MMBearerIridium, mm_bearer_iridium, MM_TYPE_BASE_BEARER)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Connect */
|
||||
|
||||
typedef struct {
|
||||
MMPortSerialAt *primary;
|
||||
GError *saved_error;
|
||||
} ConnectContext;
|
||||
|
||||
static void
|
||||
connect_context_free (ConnectContext *ctx)
|
||||
{
|
||||
if (ctx->saved_error)
|
||||
g_error_free (ctx->saved_error);
|
||||
if (ctx->primary)
|
||||
g_object_unref (ctx->primary);
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static MMBearerConnectResult *
|
||||
connect_finish (MMBaseBearer *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_report_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
ConnectContext *ctx;
|
||||
const gchar *result;
|
||||
|
||||
/* If cancelled, complete */
|
||||
if (g_task_return_error_if_cancelled (task)) {
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* If we got a proper extended reply, build the new error to be set */
|
||||
result = mm_base_modem_at_command_full_finish (modem, res, NULL);
|
||||
if (result && g_str_has_prefix (result, "+CEER: ") && strlen (result) > 7) {
|
||||
g_task_return_new_error (task,
|
||||
ctx->saved_error->domain,
|
||||
ctx->saved_error->code,
|
||||
"%s", &result[7]);
|
||||
} else {
|
||||
/* Otherwise, take the original error as it was */
|
||||
g_task_return_error (task, ctx->saved_error);
|
||||
ctx->saved_error = NULL;
|
||||
}
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
dial_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
ConnectContext *ctx;
|
||||
MMBearerIpConfig *config;
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* DO NOT check for cancellable here. If we got here without errors, the
|
||||
* bearer is really connected and therefore we need to reflect that in
|
||||
* the state machine. */
|
||||
mm_base_modem_at_command_full_finish (modem, res, &(ctx->saved_error));
|
||||
if (ctx->saved_error) {
|
||||
/* Try to get more information why it failed */
|
||||
mm_base_modem_at_command_full (
|
||||
modem,
|
||||
ctx->primary,
|
||||
"+CEER",
|
||||
3,
|
||||
FALSE,
|
||||
FALSE, /* raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback)connect_report_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Port is connected; update the state */
|
||||
mm_port_set_connected (MM_PORT (ctx->primary), TRUE);
|
||||
|
||||
/* Build IP config; always PPP based */
|
||||
config = mm_bearer_ip_config_new ();
|
||||
mm_bearer_ip_config_set_method (config, MM_BEARER_IP_METHOD_PPP);
|
||||
|
||||
/* Return operation result */
|
||||
g_task_return_pointer (
|
||||
task,
|
||||
mm_bearer_connect_result_new (MM_PORT (ctx->primary), config, NULL),
|
||||
(GDestroyNotify)mm_bearer_connect_result_unref);
|
||||
g_object_unref (task);
|
||||
g_object_unref (config);
|
||||
}
|
||||
|
||||
static void
|
||||
service_type_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
ConnectContext *ctx;
|
||||
GError *error = NULL;
|
||||
|
||||
/* If cancelled, complete */
|
||||
if (g_task_return_error_if_cancelled (task)) {
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = g_task_get_task_data (task);
|
||||
|
||||
/* Errors setting the service type will be critical */
|
||||
mm_base_modem_at_command_full_finish (modem, res, &error);
|
||||
if (error) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We just use the default number to dial in the Iridium network. Also note
|
||||
* that we won't specify a specific port to use; Iridium modems only expose
|
||||
* one. */
|
||||
mm_base_modem_at_command_full (
|
||||
modem,
|
||||
ctx->primary,
|
||||
"ATDT008816000025",
|
||||
MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT,
|
||||
FALSE,
|
||||
FALSE, /* raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback)dial_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
connect (MMBaseBearer *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
ConnectContext *ctx;
|
||||
GTask *task;
|
||||
MMBaseModem *modem = NULL;
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
|
||||
if (mm_bearer_properties_get_multiplex (mm_base_bearer_peek_config (self)) == MM_BEARER_MULTIPLEX_SUPPORT_REQUIRED) {
|
||||
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
|
||||
"Multiplex support not available");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_get (self,
|
||||
MM_BASE_BEARER_MODEM, &modem,
|
||||
NULL);
|
||||
g_assert (modem);
|
||||
|
||||
/* Don't bother to get primary and check if connected and all that; we
|
||||
* already do this check when sending the ATDT call */
|
||||
|
||||
/* In this context, we only keep the stuff we'll need later */
|
||||
ctx = g_new0 (ConnectContext, 1);
|
||||
ctx->primary = mm_base_modem_get_port_primary (modem);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify) connect_context_free);
|
||||
|
||||
/* Bearer service type set to 9600bps (V.110), which behaves better than the
|
||||
* default 9600bps (V.32). */
|
||||
mm_base_modem_at_command_full (
|
||||
modem,
|
||||
ctx->primary,
|
||||
"+CBST=71,0,1",
|
||||
3,
|
||||
FALSE,
|
||||
FALSE, /* raw */
|
||||
NULL, /* cancellable */
|
||||
(GAsyncReadyCallback)service_type_ready,
|
||||
task);
|
||||
|
||||
g_object_unref (modem);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseBearer *
|
||||
mm_bearer_iridium_new (MMBroadbandModemIridium *modem,
|
||||
MMBearerProperties *config)
|
||||
{
|
||||
MMBaseBearer *bearer;
|
||||
|
||||
/* The Iridium bearer inherits from MMBaseBearer (so it's not a MMBroadbandBearer)
|
||||
* and that means that the object is not async-initable, so we just use
|
||||
* g_object_get() here */
|
||||
bearer = g_object_new (MM_TYPE_BEARER_IRIDIUM,
|
||||
MM_BASE_BEARER_MODEM, modem,
|
||||
MM_BASE_BEARER_CONFIG, config,
|
||||
"ip-timeout", BEARER_IRIDIUM_IP_TIMEOUT_DEFAULT,
|
||||
NULL);
|
||||
|
||||
/* Only export valid bearers */
|
||||
mm_base_bearer_export (bearer);
|
||||
|
||||
return bearer;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_bearer_iridium_init (MMBearerIridium *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_bearer_iridium_class_init (MMBearerIridiumClass *klass)
|
||||
{
|
||||
MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass);
|
||||
|
||||
/* Virtual methods */
|
||||
base_bearer_class->connect = connect;
|
||||
base_bearer_class->connect_finish = connect_finish;
|
||||
base_bearer_class->load_connection_status = NULL;
|
||||
base_bearer_class->load_connection_status_finish = NULL;
|
||||
#if defined WITH_SUSPEND_RESUME
|
||||
base_bearer_class->reload_connection_status = NULL;
|
||||
base_bearer_class->reload_connection_status_finish = NULL;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/* -*- 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:
|
||||
*
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.com>
|
||||
*
|
||||
* Copyright (C) 2012 Ammonit Measurement GmbH.
|
||||
*/
|
||||
|
||||
#ifndef MM_BEARER_IRIDIUM_H
|
||||
#define MM_BEARER_IRIDIUM_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-base-bearer.h"
|
||||
#include "mm-broadband-modem-iridium.h"
|
||||
|
||||
#define MM_TYPE_BEARER_IRIDIUM (mm_bearer_iridium_get_type ())
|
||||
#define MM_BEARER_IRIDIUM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BEARER_IRIDIUM, MMBearerIridium))
|
||||
#define MM_BEARER_IRIDIUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BEARER_IRIDIUM, MMBearerIridiumClass))
|
||||
#define MM_IS_BEARER_IRIDIUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BEARER_IRIDIUM))
|
||||
#define MM_IS_BEARER_IRIDIUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BEARER_IRIDIUM))
|
||||
#define MM_BEARER_IRIDIUM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BEARER_IRIDIUM, MMBearerIridiumClass))
|
||||
|
||||
typedef struct _MMBearerIridium MMBearerIridium;
|
||||
typedef struct _MMBearerIridiumClass MMBearerIridiumClass;
|
||||
|
||||
struct _MMBearerIridium {
|
||||
MMBaseBearer parent;
|
||||
};
|
||||
|
||||
struct _MMBearerIridiumClass {
|
||||
MMBaseBearerClass parent;
|
||||
};
|
||||
|
||||
GType mm_bearer_iridium_get_type (void);
|
||||
|
||||
/* Iridium bearer creation implementation.
|
||||
* NOTE it is *not* a broadband bearer, so not async-initable */
|
||||
MMBaseBearer *mm_bearer_iridium_new (MMBroadbandModemIridium *modem,
|
||||
MMBearerProperties *config);
|
||||
|
||||
#endif /* MM_BEARER_IRIDIUM_H */
|
||||
@@ -0,0 +1,433 @@
|
||||
/* -*- 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) 2011 - 2012 Ammonit Measurement GmbH
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "ModemManager.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-errors-types.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-3gpp.h"
|
||||
#include "mm-iface-modem-messaging.h"
|
||||
#include "mm-broadband-modem-iridium.h"
|
||||
#include "mm-sim-iridium.h"
|
||||
#include "mm-bearer-iridium.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
|
||||
static void iface_modem_init (MMIfaceModem *iface);
|
||||
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
||||
static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemIridium, mm_broadband_modem_iridium, MM_TYPE_BROADBAND_MODEM, 0,
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
|
||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init))
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Operator Code loading (3GPP interface) */
|
||||
|
||||
static gchar *
|
||||
load_operator_code_finish (MMIfaceModem3gpp *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
load_operator_code (MMIfaceModem3gpp *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
/* Only "90103" operator code is assumed */
|
||||
g_task_return_pointer (task, g_strdup ("90103"), g_free);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Operator Name loading (3GPP interface) */
|
||||
|
||||
static gchar *
|
||||
load_operator_name_finish (MMIfaceModem3gpp *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
load_operator_name (MMIfaceModem3gpp *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
/* Only "IRIDIUM" operator name is assumed */
|
||||
g_task_return_pointer (task, g_strdup ("IRIDIUM"), g_free);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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 <bm> can only be 0,
|
||||
* and <ds> can only be either 0 or 1
|
||||
*
|
||||
* Note: Modem may return +CMS ERROR:322, which indicates Memory Full,
|
||||
* not a big deal
|
||||
*/
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"+CNMI=2,1,0,0,1",
|
||||
3,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Signal quality (Modem interface) */
|
||||
|
||||
static guint
|
||||
load_signal_quality_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
gint quality = 0;
|
||||
const gchar *result;
|
||||
|
||||
result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
/* Skip possible whitespaces after '+CSQF:' and before the response */
|
||||
result = mm_strip_tag (result, "+CSQF:");
|
||||
while (*result == ' ')
|
||||
result++;
|
||||
|
||||
if (sscanf (result, "%d", &quality))
|
||||
/* Normalize the quality. <rssi> is NOT given in dBs,
|
||||
* given as a relative value between 0 and 5 */
|
||||
quality = CLAMP (quality, 0, 5) * 100 / 5;
|
||||
else
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Could not parse signal quality results");
|
||||
|
||||
return quality;
|
||||
}
|
||||
|
||||
static void
|
||||
load_signal_quality (MMIfaceModem *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* The iridium modem may have a huge delay to get signal quality if we pass
|
||||
* AT+CSQ, so we'll default to use AT+CSQF, which is a fast version that
|
||||
* returns right away the last signal quality value retrieved */
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"+CSQF",
|
||||
3,
|
||||
FALSE,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Flow control (Modem interface) */
|
||||
|
||||
static gboolean
|
||||
setup_flow_control_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_flow_control_ready (MMBroadbandModemIridium *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error))
|
||||
/* Let the error be critical. We DO need RTS/CTS in order to have
|
||||
* proper modem disabling. */
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_flow_control (MMIfaceModem *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Enable RTS/CTS flow control.
|
||||
* Other available values:
|
||||
* AT&K0: Disable flow control
|
||||
* AT&K3: RTS/CTS
|
||||
* AT&K4: XOFF/XON
|
||||
* AT&K6: Both RTS/CTS and XOFF/XON
|
||||
*/
|
||||
g_object_set (self, MM_BROADBAND_MODEM_FLOW_CONTROL, MM_FLOW_CONTROL_RTS_CTS, NULL);
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"&K3",
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)setup_flow_control_ready,
|
||||
g_task_new (self, NULL, callback, user_data));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Load supported modes (Modem inteface) */
|
||||
|
||||
static GArray *
|
||||
load_supported_modes_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
load_supported_modes (MMIfaceModem *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GArray *combinations;
|
||||
MMModemModeCombination mode;
|
||||
GTask *task;
|
||||
|
||||
/* Build list of combinations */
|
||||
combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1);
|
||||
|
||||
/* Report CS only, Iridium connections are circuit-switched */
|
||||
mode.allowed = MM_MODEM_MODE_CS;
|
||||
mode.preferred = MM_MODEM_MODE_NONE;
|
||||
g_array_append_val (combinations, mode);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_return_pointer (task, combinations, (GDestroyNotify) g_array_unref);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Create SIM (Modem inteface) */
|
||||
|
||||
static MMBaseSim *
|
||||
create_sim_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return mm_sim_iridium_new_finish (res, error);
|
||||
}
|
||||
|
||||
static void
|
||||
create_sim (MMIfaceModem *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* New Iridium SIM */
|
||||
mm_sim_iridium_new (MM_BASE_MODEM (self),
|
||||
NULL, /* cancellable */
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Create Bearer (Modem interface) */
|
||||
|
||||
static MMBaseBearer *
|
||||
create_bearer_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_pointer (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
create_bearer (MMIfaceModem *self,
|
||||
MMBearerProperties *properties,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBaseBearer *bearer;
|
||||
GTask *task;
|
||||
|
||||
mm_obj_dbg (self, "creating Iridium bearer...");
|
||||
bearer = mm_bearer_iridium_new (MM_BROADBAND_MODEM_IRIDIUM (self),
|
||||
properties);
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_return_pointer (task, bearer, g_object_unref);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const gchar *primary_init_sequence[] = {
|
||||
/* Disable echo */
|
||||
"E0",
|
||||
/* Get word responses */
|
||||
"V1",
|
||||
/* Extended numeric codes */
|
||||
"+CMEE=1",
|
||||
NULL
|
||||
};
|
||||
|
||||
static void
|
||||
setup_ports (MMBroadbandModem *self)
|
||||
{
|
||||
MMPortSerialAt *primary;
|
||||
|
||||
/* Call parent's setup ports first always */
|
||||
MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_iridium_parent_class)->setup_ports (self);
|
||||
|
||||
/* Set 9600 baudrate by default in the AT port */
|
||||
mm_obj_dbg (self, "baudrate will be set to 9600 bps...");
|
||||
primary = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
|
||||
if (!primary)
|
||||
return;
|
||||
|
||||
g_object_set (G_OBJECT (primary),
|
||||
MM_PORT_SERIAL_BAUD, 9600,
|
||||
MM_PORT_SERIAL_AT_INIT_SEQUENCE, primary_init_sequence,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBroadbandModemIridium *
|
||||
mm_broadband_modem_iridium_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id)
|
||||
{
|
||||
return g_object_new (MM_TYPE_BROADBAND_MODEM_IRIDIUM,
|
||||
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,
|
||||
/* Iridium bearer supports TTY only */
|
||||
MM_BASE_MODEM_DATA_NET_SUPPORTED, FALSE,
|
||||
MM_BASE_MODEM_DATA_TTY_SUPPORTED, TRUE,
|
||||
/* Allow only up to 3 consecutive timeouts in the serial port */
|
||||
MM_BASE_MODEM_MAX_TIMEOUTS, 3,
|
||||
/* Only CS network is supported by the Iridium modem */
|
||||
MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED, FALSE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_iridium_init (MMBroadbandModemIridium *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_init (MMIfaceModem *iface)
|
||||
{
|
||||
/* Create Iridium-specific SIM and bearer*/
|
||||
iface->create_sim = create_sim;
|
||||
iface->create_sim_finish = create_sim_finish;
|
||||
iface->create_bearer = create_bearer;
|
||||
iface->create_bearer_finish = create_bearer_finish;
|
||||
|
||||
/* CSQF-based signal quality */
|
||||
iface->load_signal_quality = load_signal_quality;
|
||||
iface->load_signal_quality_finish = load_signal_quality_finish;
|
||||
|
||||
/* RTS/CTS flow control */
|
||||
iface->setup_flow_control = setup_flow_control;
|
||||
iface->setup_flow_control_finish = setup_flow_control_finish;
|
||||
|
||||
/* No need to power-up/power-down the modem */
|
||||
iface->load_power_state = NULL;
|
||||
iface->load_power_state_finish = NULL;
|
||||
iface->modem_power_up = NULL;
|
||||
iface->modem_power_up_finish = NULL;
|
||||
iface->modem_power_down = NULL;
|
||||
iface->modem_power_down_finish = NULL;
|
||||
|
||||
/* Supported modes cannot be queried */
|
||||
iface->load_supported_modes = load_supported_modes;
|
||||
iface->load_supported_modes_finish = load_supported_modes_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
|
||||
{
|
||||
/* Fixed operator code and name to be reported */
|
||||
iface->load_operator_name = load_operator_name;
|
||||
iface->load_operator_name_finish = load_operator_name_finish;
|
||||
iface->load_operator_code = load_operator_code;
|
||||
iface->load_operator_code_finish = load_operator_code_finish;
|
||||
|
||||
/* Don't try to scan networks with AT+COPS=?.
|
||||
* It does work, but it will only reply about the Iridium network
|
||||
* being found (so not very helpful, as that is the only one expected), but
|
||||
* also, it will use a non-standard reply format. Instead of supporting that
|
||||
* specific format used, just fully skip it.
|
||||
* For reference, the result is:
|
||||
* +COPS:(002),"IRIDIUM","IRIDIUM","90103",,(000-001),(000-002)
|
||||
*/
|
||||
iface->scan_networks = NULL;
|
||||
iface->scan_networks_finish = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
iface_modem_messaging_init (MMIfaceModemMessaging *iface)
|
||||
{
|
||||
iface->enable_unsolicited_events = messaging_enable_unsolicited_events;
|
||||
iface->enable_unsolicited_events_finish = messaging_enable_unsolicited_events_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_broadband_modem_iridium_class_init (MMBroadbandModemIridiumClass *klass)
|
||||
{
|
||||
MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
|
||||
|
||||
broadband_modem_class->setup_ports = setup_ports;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2011 Red Hat, Inc.
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*/
|
||||
|
||||
#ifndef MM_BROADBAND_MODEM_IRIDIUM_H
|
||||
#define MM_BROADBAND_MODEM_IRIDIUM_H
|
||||
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM_IRIDIUM (mm_broadband_modem_iridium_get_type ())
|
||||
#define MM_BROADBAND_MODEM_IRIDIUM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_IRIDIUM, MMBroadbandModemIridium))
|
||||
#define MM_BROADBAND_MODEM_IRIDIUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_IRIDIUM, MMBroadbandModemIridiumClass))
|
||||
#define MM_IS_BROADBAND_MODEM_IRIDIUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_IRIDIUM))
|
||||
#define MM_IS_BROADBAND_MODEM_IRIDIUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_IRIDIUM))
|
||||
#define MM_BROADBAND_MODEM_IRIDIUM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_IRIDIUM, MMBroadbandModemIridiumClass))
|
||||
|
||||
typedef struct _MMBroadbandModemIridium MMBroadbandModemIridium;
|
||||
typedef struct _MMBroadbandModemIridiumClass MMBroadbandModemIridiumClass;
|
||||
|
||||
struct _MMBroadbandModemIridium {
|
||||
MMBroadbandModem parent;
|
||||
};
|
||||
|
||||
struct _MMBroadbandModemIridiumClass{
|
||||
MMBroadbandModemClass parent;
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_iridium_get_type (void);
|
||||
|
||||
MMBroadbandModemIridium *mm_broadband_modem_iridium_new (const gchar *device,
|
||||
const gchar **drivers,
|
||||
const gchar *plugin,
|
||||
guint16 vendor_id,
|
||||
guint16 product_id);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_IRIDIUM_H */
|
||||
@@ -0,0 +1,89 @@
|
||||
/* -*- 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) 2011 - 2012 Ammonit Measurement GmbH
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-plugin-iridium.h"
|
||||
#include "mm-broadband-modem-iridium.h"
|
||||
#include "mm-private-boxed-types.h"
|
||||
|
||||
G_DEFINE_TYPE (MMPluginIridium, mm_plugin_iridium, MM_TYPE_PLUGIN)
|
||||
|
||||
MM_PLUGIN_DEFINE_MAJOR_VERSION
|
||||
MM_PLUGIN_DEFINE_MINOR_VERSION
|
||||
|
||||
static MMBaseModem *
|
||||
create_modem (MMPlugin *self,
|
||||
const gchar *uid,
|
||||
const gchar **drivers,
|
||||
guint16 vendor,
|
||||
guint16 product,
|
||||
guint16 subsystem_vendor,
|
||||
GList *probes,
|
||||
GError **error)
|
||||
{
|
||||
return MM_BASE_MODEM (mm_broadband_modem_iridium_new (uid,
|
||||
drivers,
|
||||
mm_plugin_get_name (self),
|
||||
vendor,
|
||||
product));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *
|
||||
mm_plugin_create (void)
|
||||
{
|
||||
static const gchar *subsystems[] = { "tty", NULL };
|
||||
static const guint16 vendor_ids[] = { 0x1edd, 0 };
|
||||
static const gchar *vendor_strings[] = { "iridium", NULL };
|
||||
/* Also support motorola-branded Iridium modems */
|
||||
static const mm_str_pair product_strings[] = {{(gchar *)"motorola", (gchar *)"satellite" },
|
||||
{ NULL, NULL }};
|
||||
|
||||
return MM_PLUGIN (
|
||||
g_object_new (MM_TYPE_PLUGIN_IRIDIUM,
|
||||
MM_PLUGIN_NAME, MM_MODULE_NAME,
|
||||
MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_STRINGS, vendor_strings,
|
||||
MM_PLUGIN_ALLOWED_PRODUCT_STRINGS, product_strings,
|
||||
MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids,
|
||||
MM_PLUGIN_ALLOWED_AT, TRUE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_iridium_init (MMPluginIridium *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_plugin_iridium_class_init (MMPluginIridiumClass *klass)
|
||||
{
|
||||
MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->create_modem = create_modem;
|
||||
}
|
||||
@@ -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) 2011 - 2012 Ammonit Measurement GmbH
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.com>
|
||||
*/
|
||||
|
||||
#ifndef MM_PLUGIN_IRIDIUM_H
|
||||
#define MM_PLUGIN_IRIDIUM_H
|
||||
|
||||
#include "mm-plugin.h"
|
||||
|
||||
#define MM_TYPE_PLUGIN_IRIDIUM (mm_plugin_iridium_get_type ())
|
||||
#define MM_PLUGIN_IRIDIUM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_IRIDIUM, MMPluginIridium))
|
||||
#define MM_PLUGIN_IRIDIUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_IRIDIUM, MMPluginIridiumClass))
|
||||
#define MM_IS_PLUGIN_IRIDIUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_IRIDIUM))
|
||||
#define MM_IS_PLUGIN_IRIDIUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_IRIDIUM))
|
||||
#define MM_PLUGIN_IRIDIUM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_IRIDIUM, MMPluginIridiumClass))
|
||||
|
||||
typedef struct {
|
||||
MMPlugin parent;
|
||||
} MMPluginIridium;
|
||||
|
||||
typedef struct {
|
||||
MMPluginClass parent;
|
||||
} MMPluginIridiumClass;
|
||||
|
||||
GType mm_plugin_iridium_get_type (void);
|
||||
|
||||
G_MODULE_EXPORT MMPlugin *mm_plugin_create (void);
|
||||
|
||||
#endif /* MM_PLUGIN_IRIDIUM_H */
|
||||
@@ -0,0 +1,95 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2011 - 2012 Ammonit Measurement GmbH.
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.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-sim-iridium.h"
|
||||
|
||||
G_DEFINE_TYPE (MMSimIridium, mm_sim_iridium, MM_TYPE_BASE_SIM)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseSim *
|
||||
mm_sim_iridium_new_finish (GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
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_base_sim_export (MM_BASE_SIM (sim));
|
||||
|
||||
return MM_BASE_SIM (sim);
|
||||
}
|
||||
|
||||
void
|
||||
mm_sim_iridium_new (MMBaseModem *modem,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_async_initable_new_async (MM_TYPE_SIM_IRIDIUM,
|
||||
G_PRIORITY_DEFAULT,
|
||||
cancellable,
|
||||
callback,
|
||||
user_data,
|
||||
MM_BASE_SIM_MODEM, modem,
|
||||
"active", TRUE, /* by default always active */
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sim_iridium_init (MMSimIridium *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sim_iridium_class_init (MMSimIridiumClass *klass)
|
||||
{
|
||||
MMBaseSimClass *base_sim_class = MM_BASE_SIM_CLASS (klass);
|
||||
|
||||
/* Skip querying the SIM card info, not supported by Iridium modems */
|
||||
base_sim_class->load_sim_identifier = NULL;
|
||||
base_sim_class->load_sim_identifier_finish = NULL;
|
||||
base_sim_class->load_imsi = NULL;
|
||||
base_sim_class->load_imsi_finish = NULL;
|
||||
base_sim_class->load_operator_identifier = NULL;
|
||||
base_sim_class->load_operator_identifier_finish = NULL;
|
||||
base_sim_class->load_operator_name = NULL;
|
||||
base_sim_class->load_operator_name_finish = NULL;
|
||||
|
||||
/* Skip managing preferred networks, not applicable to Iridium modems */
|
||||
base_sim_class->load_preferred_networks = NULL;
|
||||
base_sim_class->load_preferred_networks_finish = NULL;
|
||||
base_sim_class->set_preferred_networks = NULL;
|
||||
base_sim_class->set_preferred_networks_finish = NULL;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user