Merge cros/upstream to cros/master
Part of an uprev that contains the following commits:
" 95fec5ad Merge cros/upstream to cros/master (Pavan Holla)"
" 1c4ba762 plugin, telit: set last band to EUTRAN_85 (Alexey Orishko)"
" 8ecc0f64 plugin, telit: add support for LPWA modem (Alexey Orishko)"
" 908ab333 foxconn: updating the T77W968 requires MCFG+APPS version (Fanice.luo)"
" 1ef46a68 fibocom: Don't disconnect initial EPS bearer (Sven Schwermer)"
" 71a9739f fibocom: Set initial EPS bearer CID for MA510 (Sven Schwermer)"
" c509159d fibocom: Add initial EPS bearer support (Sven Schwermer)"
" 855977c4 fibocom: Implement power down/off (Sven Schwermer)"
" e5bb33a4 fibocom: Monitor connection status using +GTRNDIS? (Sven Schwermer)"
" 04ed52a7 mm-iface-modem: always require a SIM card in 3GPP modules (Akash Aggarwal)"
" ead9f180 fcc-unlock: add FCC unlock support for Quectel EM05-G (Aleksander Morgado)"
" fab04810 foxconn: remove QMI_SERVICE_FOX from Generic MBIM modem object (Fanice.luo)"
" a93c1f6f i18n: Update German translation (Jürgen Benvenuti)"
" 1db9cf46 sms-part-3gpp: coding style fixes (Aleksander Morgado)"
" 795103cf broadband-modem-mbim: ensure message array contains valid PDUs (Aleksander Morgado)"
" 125ef272 sim-mbim: fix race condition when sync requested during preload (Aleksander Morgado)"
" eee9a6f6 iface-modem-3gpp: disallow Scan() or Register() if Locked (Aleksander Morgado)"
" 976a3d4d libmm-glib,common-helpers: minor coding style fix in mm_new_iso8601_time() (Aleksander Morgado)"
" bfba2650 libmm-glib,common-helpers: don't assume new_from_unix_utc() always succeeds (Aleksander Morgado)"
" 4628056a mm-modem-helpers.c: adjust the RING regex (Angus Ainslie)"
" a74f11ae sim-mbim: fallback to AT commands if reading GID via MBIM fails (Aleksander Morgado)"
" fa6d6455 base-sim: implement GID1 and GID2 loading using AT commands (Aleksander Morgado)"
" 651ddb95 plugins,telit: LM940 has LTE band ext after given version (Carlo Lobrano)"
" 072c8eba plugins,telit: LM960 has LTE extended bands (Carlo Lobrano)"
" 7f82c38d plugins,telit: Detect alternate_3g_bands flag from modem model (Carlo Lobrano)"
" 72ca6676 plugins,telit: Detect ext_4g_bands flag from modem model (Carlo Lobrano)"
" b0c5756b plugins,telit: Add MM_TELIT_MODEL_FN990 (Carlo Lobrano)"
" 049c5ab2 plugins,telit: remove unnecessary argument (Carlo Lobrano)"
" 3ab3d5e8 plugins,telit: refactor to reduce scope of variable (Carlo Lobrano)"
" a55384d7 plugins,telit: refactor functions dealing with #BND (Carlo Lobrano)"
" 99cde839 cinterion: Fix CDC-ECM support for ELS61-E2 (Christian Taedcke)"
" a25b45f7 cinterion: add support for mode setting using SXRAT (Christian Taedcke)"
" fcd393a6 quectel: Trigger reprobe upon RDY URC (Sven Schwermer)"
" 2c66d43b broadband-modem-qmi: select last used level when enabling SAR (Aleksander Morgado)"
" 1ea5a577 iface-modem-sar: report updated level on SAR enable (Aleksander Morgado)"
" 950d36d4 iface-modem-sar: avoid changing level if already in the target level (Aleksander Morgado)"
" 72457c25 iface-modem-sar: avoid changing state if already in the target state (Aleksander Morgado)"
" b50c24ac iface-modem-sar: disallow changing SAR level if SAR disabled (Aleksander Morgado)"
" 0994087f iface-modem-sar: fix set power level async method completion (Aleksander Morgado)"
" 258b8f8e broadband-modem-qmi: attempt to preallocate SAR client (Aleksander Morgado)"
" 04e7f777 broadband-modem-qmi: Implement the SAR interface (Madhav)"
" 4a36f50d iface-modem-3gpp-profile-manager: fix requested IP type normalization (Aleksander Morgado)"
BUG=None
TEST=None
Cq-Depend: chromium:3960706,chromium:3961586,chromium:3961280
Change-Id: If0c85b7d141b3b07f78a8d6c4a59a0b36000c742
diff --git a/cli/mmcli-output.c b/cli/mmcli-output.c
index 1bb17f8..ef1c7cb 100644
--- a/cli/mmcli-output.c
+++ b/cli/mmcli-output.c
@@ -621,11 +621,11 @@
/* (Custom) Bearer start date output */
void
-mmcli_output_start_date (guint64 value)
+mmcli_output_start_date (guint64 value)
{
/* Merge value and recent flag in a single item in human output */
if (selected_type == MMC_OUTPUT_TYPE_HUMAN) {
- output_item_new_take_single (MMC_F_BEARER_STATS_START_DATE, mm_new_iso8601_time_from_unix_time (value));
+ output_item_new_take_single (MMC_F_BEARER_STATS_START_DATE, mm_new_iso8601_time_from_unix_time (value, NULL));
return;
}
diff --git a/data/dispatcher-fcc-unlock/2c7c b/data/dispatcher-fcc-unlock/2c7c
new file mode 100644
index 0000000..1161aec
--- /dev/null
+++ b/data/dispatcher-fcc-unlock/2c7c
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# SPDX-License-Identifier: CC0-1.0
+# 2022 Leah Oswald <mail@leahoswald.de>
+#
+# Queltec EM05-G FCC unlock mechanism
+#
+
+# require program name and at least 2 arguments
+[ $# -lt 2 ] && exit 1
+
+# first argument is DBus path, not needed here
+shift
+
+# second and next arguments are control port names
+for PORT in "$@"; do
+ # match port name
+ echo "$PORT" | grep -q cdc-wdm && {
+ CDC_WDM_PORT=$PORT
+ break
+ }
+done
+
+# fail if no cdc-wdm port exposed
+[ -n "$CDC_WDM_PORT" ] || exit 2
+
+# run mbimcli operation
+mbimcli --device-open-proxy --device="/dev/$CDC_WDM_PORT" --quectel-set-radio-state=on
+exit $?
diff --git a/data/dispatcher-fcc-unlock/Makefile.am b/data/dispatcher-fcc-unlock/Makefile.am
index a98a68f..7f6224c 100644
--- a/data/dispatcher-fcc-unlock/Makefile.am
+++ b/data/dispatcher-fcc-unlock/Makefile.am
@@ -11,6 +11,7 @@
105b \
1199 \
1eac \
+ 2c7c \
$(NULL)
EXTRA_DIST = $(fccunlockavailable_SCRIPTS)
@@ -26,6 +27,7 @@
$(LN_S) -f 1199 413c:81a3; \
$(LN_S) -f 1199 413c:81a8; \
$(LN_S) -f 1eac 1eac:1001; \
+ $(LN_S) -f 2c7c 2c7c:030a; \
$(NULL)
uninstall-hook:
diff --git a/data/dispatcher-fcc-unlock/meson.build b/data/dispatcher-fcc-unlock/meson.build
index f945fbf..5dc3b6a 100644
--- a/data/dispatcher-fcc-unlock/meson.build
+++ b/data/dispatcher-fcc-unlock/meson.build
@@ -14,6 +14,7 @@
'105b',
'1199',
'1eac',
+ '2c7c',
)
install_data(
@@ -29,6 +30,7 @@
'413c:81a3': '1199',
'413c:81a8': '1199',
'1eac:1001': '1eac',
+ '2c7c:030a': '2c7c',
}
ln_cmd = 'ln -fs @0@ ${DESTDIR}@1@'
diff --git a/libmm-glib/mm-common-helpers.c b/libmm-glib/mm-common-helpers.c
index 085177b..5f3af4a 100644
--- a/libmm-glib/mm-common-helpers.c
+++ b/libmm-glib/mm-common-helpers.c
@@ -1752,11 +1752,18 @@
}
gchar *
-mm_new_iso8601_time_from_unix_time (guint64 timestamp)
+mm_new_iso8601_time_from_unix_time (guint64 timestamp,
+ GError **error)
{
g_autoptr(GDateTime) dt = NULL;
dt = g_date_time_new_from_unix_utc ((gint64)timestamp);
+ if (!dt) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid unix time: %" G_GUINT64_FORMAT,
+ timestamp);
+ return NULL;
+ }
return date_time_format_iso8601 (dt);
}
@@ -1782,11 +1789,9 @@
} else
dt = g_date_time_new_utc (year, month, day, hour, minute, second);
- if (dt == NULL) {
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_INVALID_ARGS,
- "Invalid input for date: got year:%u, month:%u, day:%u, hour:%u, minute:%u, second:%u",
+ if (!dt) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid date: year: %u, month: %u, day: %u, hour: %u, minute: %u, second: %u",
year, month, day, hour, minute, second);
return NULL;
}
diff --git a/libmm-glib/mm-common-helpers.h b/libmm-glib/mm-common-helpers.h
index 490f882..a92d5b5 100644
--- a/libmm-glib/mm-common-helpers.h
+++ b/libmm-glib/mm-common-helpers.h
@@ -208,16 +208,17 @@
gchar *mm_get_string_unquoted_from_match_info (GMatchInfo *match_info,
guint32 match_index);
-gchar *mm_new_iso8601_time_from_unix_time (guint64 timestamp);
-gchar *mm_new_iso8601_time (guint year,
- guint month,
- guint day,
- guint hour,
- guint minute,
- guint second,
- gboolean have_offset,
- gint offset_minutes,
- GError **error);
+gchar *mm_new_iso8601_time_from_unix_time (guint64 timestamp,
+ GError **error);
+gchar *mm_new_iso8601_time (guint year,
+ guint month,
+ guint day,
+ guint hour,
+ guint minute,
+ guint second,
+ gboolean have_offset,
+ gint offset_minutes,
+ GError **error);
/******************************************************************************/
/* Type checkers and conversion utilities */
diff --git a/libmm-glib/tests/test-common-helpers.c b/libmm-glib/tests/test-common-helpers.c
index a1a2e61..fff37a8 100644
--- a/libmm-glib/tests/test-common-helpers.c
+++ b/libmm-glib/tests/test-common-helpers.c
@@ -604,7 +604,8 @@
gchar *date = NULL;
GError *error = NULL;
- date = mm_new_iso8601_time_from_unix_time (1634307342);
+ date = mm_new_iso8601_time_from_unix_time (1634307342, &error);
+ g_assert_no_error (error);
g_assert_cmpstr (date, ==, "2021-10-15T14:15:42Z");
g_free (date);
@@ -636,6 +637,12 @@
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
g_assert_null (date);
g_clear_error (&error);
+
+ /* Too far into the future */
+ date = mm_new_iso8601_time_from_unix_time (G_MAXINT64, &error);
+ g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS);
+ g_assert_null (date);
+ g_clear_error (&error);
}
/**************************************************************/
diff --git a/plugins/cinterion/mm-broadband-bearer-cinterion.c b/plugins/cinterion/mm-broadband-bearer-cinterion.c
index e7ff392..e67d461 100644
--- a/plugins/cinterion/mm-broadband-bearer-cinterion.c
+++ b/plugins/cinterion/mm-broadband-bearer-cinterion.c
@@ -272,6 +272,23 @@
}
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;
@@ -299,6 +316,8 @@
{
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);
@@ -310,16 +329,19 @@
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: {
- gchar *command;
+ g_autofree gchar *command = NULL;
command = mm_cinterion_build_auth_string (self,
- mm_broadband_modem_cinterion_get_family (MM_BROADBAND_MODEM_CINTERION (ctx->modem)),
+ modem_family,
mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)),
ctx->cid);
@@ -336,7 +358,6 @@
NULL,
(GAsyncReadyCallback) common_dial_operation_ready,
task);
- g_free (command);
return;
}
@@ -345,13 +366,31 @@
} /* fall through */
case DIAL_3GPP_CONTEXT_STEP_START_SWWAN: {
- gchar *command;
+ 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,
@@ -359,13 +398,15 @@
FALSE,
FALSE,
NULL,
- (GAsyncReadyCallback) common_dial_operation_ready,
- task);
- g_free (command);
+ (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,
diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c
index 3be8da8..9079135 100644
--- a/plugins/cinterion/mm-broadband-modem-cinterion.c
+++ b/plugins/cinterion/mm-broadband-modem-cinterion.c
@@ -88,6 +88,10 @@
GArray *cnmi_supported_ds;
GArray *cnmi_supported_bfr;
+ /* Cached supported rats for SXRAT */
+ GArray *sxrat_supported_rat;
+ GArray *sxrat_supported_pref1;
+
/* ignore regex */
GRegex *sysstart_regex;
/* +CIEV indications as configured via AT^SIND */
@@ -100,6 +104,10 @@
FeatureSupport sind_psinfo_support;
FeatureSupport smoni_support;
FeatureSupport sind_simstatus_support;
+ FeatureSupport sxrat_support;
+
+ /* Mode combination to apply if "any" requested */
+ MMModemMode any_allowed;
/* Flags for model-based behaviors */
MMCinterionModemFamily modem_family;
@@ -1797,15 +1805,186 @@
}
static void
-load_supported_modes (MMIfaceModem *self,
+sxrat_load_supported_modes_ready (MMBroadbandModemCinterion *self,
+ GTask *task)
+{
+ GArray *combinations;
+ MMModemModeCombination mode;
+
+ g_assert (self->priv->sxrat_supported_rat);
+ g_assert (self->priv->sxrat_supported_pref1);
+
+ /* Build list of combinations */
+ combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3);
+
+ if (value_supported (self->priv->sxrat_supported_rat, 0)) {
+ /* 2G only */
+ mode.allowed = MM_MODEM_MODE_2G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ }
+ if (value_supported (self->priv->sxrat_supported_rat, 1)) {
+ /* 2G+3G with none preferred */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+
+ self->priv->any_allowed = mode.allowed;
+
+ if (value_supported (self->priv->sxrat_supported_pref1, 0)) {
+ /* 2G preferred */
+ mode.preferred = MM_MODEM_MODE_2G;
+ g_array_append_val (combinations, mode);
+ }
+ if (value_supported (self->priv->sxrat_supported_pref1, 2)) {
+ /* 3G preferred */
+ mode.preferred = MM_MODEM_MODE_3G;
+ g_array_append_val (combinations, mode);
+ }
+ }
+ if (value_supported (self->priv->sxrat_supported_rat, 2)) {
+ /* 3G only */
+ mode.allowed = MM_MODEM_MODE_3G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ }
+ if (value_supported (self->priv->sxrat_supported_rat, 3)) {
+ /* 4G only */
+ mode.allowed = MM_MODEM_MODE_4G;
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+ }
+ if (value_supported (self->priv->sxrat_supported_rat, 4)) {
+ /* 3G+4G with none preferred */
+ mode.allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+
+ self->priv->any_allowed = mode.allowed;
+
+ if (value_supported (self->priv->sxrat_supported_pref1, 2)) {
+ /* 3G preferred */
+ mode.preferred = MM_MODEM_MODE_3G;
+ g_array_append_val (combinations, mode);
+ }
+ if (value_supported (self->priv->sxrat_supported_pref1, 3)) {
+ /* 4G preferred */
+ mode.preferred = MM_MODEM_MODE_4G;
+ g_array_append_val (combinations, mode);
+ }
+ }
+ if (value_supported (self->priv->sxrat_supported_rat, 5)) {
+ /* 2G+4G with none preferred */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_4G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+
+ self->priv->any_allowed = mode.allowed;
+
+ if (value_supported (self->priv->sxrat_supported_pref1, 0)) {
+ /* 2G preferred */
+ mode.preferred = MM_MODEM_MODE_2G;
+ g_array_append_val (combinations, mode);
+ }
+ if (value_supported (self->priv->sxrat_supported_pref1, 3)) {
+ /* 4G preferred */
+ mode.preferred = MM_MODEM_MODE_4G;
+ g_array_append_val (combinations, mode);
+ }
+ }
+ if (value_supported (self->priv->sxrat_supported_rat, 6)) {
+ /* 2G+3G+4G with none preferred */
+ mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G);
+ mode.preferred = MM_MODEM_MODE_NONE;
+ g_array_append_val (combinations, mode);
+
+ self->priv->any_allowed = mode.allowed;
+
+ if (value_supported (self->priv->sxrat_supported_pref1, 0)) {
+ /* 2G preferred */
+ mode.preferred = MM_MODEM_MODE_2G;
+ g_array_append_val (combinations, mode);
+ }
+ if (value_supported (self->priv->sxrat_supported_pref1, 2)) {
+ /* 3G preferred */
+ mode.preferred = MM_MODEM_MODE_3G;
+ g_array_append_val (combinations, mode);
+ }
+ if (value_supported (self->priv->sxrat_supported_pref1, 3)) {
+ /* 4G preferred */
+ mode.preferred = MM_MODEM_MODE_4G;
+ g_array_append_val (combinations, mode);
+ }
+ }
+
+ g_task_return_pointer (task, combinations, (GDestroyNotify) g_array_unref);
+ g_object_unref (task);
+}
+
+static void
+sxrat_test_ready (MMBaseModem *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
+ g_autoptr(GError) error = NULL;
+ const gchar *response;
+
+ response = mm_base_modem_at_command_finish (_self, res, &error);
+ if (!error) {
+ mm_cinterion_parse_sxrat_test (response,
+ &self->priv->sxrat_supported_rat,
+ &self->priv->sxrat_supported_pref1,
+ NULL,
+ &error);
+ if (!error) {
+ self->priv->sxrat_support = FEATURE_SUPPORTED;
+ sxrat_load_supported_modes_ready (self, task);
+ return;
+ }
+ mm_obj_warn (self, "error reading SXRAT response: %s", error->message);
+ }
+
+ self->priv->sxrat_support = FEATURE_NOT_SUPPORTED;
+
+ /* Run parent's loading in case SXRAT is not supported */
+ iface_modem_parent->load_supported_modes (
+ MM_IFACE_MODEM (self),
+ (GAsyncReadyCallback)parent_load_supported_modes_ready,
+ task);
+}
+
+static void
+load_supported_modes (MMIfaceModem *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ /* First check SXRAT support, if not already done */
+ if (self->priv->sxrat_support == FEATURE_SUPPORT_UNKNOWN) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "^SXRAT=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback)sxrat_test_ready,
+ task);
+ return;
+ }
+
+ if (self->priv->sxrat_support == FEATURE_SUPPORTED) {
+ sxrat_load_supported_modes_ready (self, task);
+ return;
+ }
+
/* Run parent's loading */
iface_modem_parent->load_supported_modes (
MM_IFACE_MODEM (self),
(GAsyncReadyCallback)parent_load_supported_modes_ready,
- g_task_new (self, NULL, callback, user_data));
+ task);
}
/*****************************************************************************/
@@ -1849,20 +2028,15 @@
}
static void
-set_current_modes (MMIfaceModem *_self,
- MMModemMode allowed,
- MMModemMode preferred,
- GAsyncReadyCallback callback,
- gpointer user_data)
+cops_set_current_modes (MMBroadbandModemCinterion *self,
+ MMModemMode allowed,
+ MMModemMode preferred,
+ GTask *task)
{
- MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
- gchar *command;
- GTask *task;
+ gchar *command;
g_assert (preferred == MM_MODEM_MODE_NONE);
- task = g_task_new (self, NULL, callback, user_data);
-
/* We will try to simulate the possible allowed modes here. The
* Cinterion devices do not seem to allow setting preferred access
* technology in devices, but they allow restricting to a given
@@ -1874,11 +2048,11 @@
* which is based on the quality of the connection.
*/
- if (mm_iface_modem_is_4g (_self) && allowed == MM_MODEM_MODE_4G)
+ if (mm_iface_modem_is_4g (MM_IFACE_MODEM (self)) && allowed == MM_MODEM_MODE_4G)
command = g_strdup ("+COPS=,,,7");
- else if (mm_iface_modem_is_3g (_self) && allowed == MM_MODEM_MODE_3G)
+ else if (mm_iface_modem_is_3g (MM_IFACE_MODEM (self)) && allowed == MM_MODEM_MODE_3G)
command = g_strdup ("+COPS=,,,2");
- else if (mm_iface_modem_is_2g (_self) && allowed == MM_MODEM_MODE_2G)
+ else if (mm_iface_modem_is_2g (MM_IFACE_MODEM (self)) && allowed == MM_MODEM_MODE_2G)
command = g_strdup ("+COPS=,,,0");
else {
/* For any other combination (e.g. ANY or no AcT given, defaults to Auto. For this case, we cannot provide
@@ -1902,6 +2076,60 @@
g_free (command);
}
+static void
+sxrat_set_current_modes (MMBroadbandModemCinterion *self,
+ MMModemMode allowed,
+ MMModemMode preferred,
+ GTask *task)
+{
+ gchar *command;
+ GError *error = NULL;
+
+ g_assert (self->priv->any_allowed != MM_MODEM_MODE_NONE);
+
+ /* Handle ANY */
+ if (allowed == MM_MODEM_MODE_ANY)
+ allowed = self->priv->any_allowed;
+
+ command = mm_cinterion_build_sxrat_set_command (allowed, preferred, &error);
+
+ if (!command) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ mm_base_modem_at_command (
+ MM_BASE_MODEM (self),
+ command,
+ 30,
+ FALSE,
+ (GAsyncReadyCallback)allowed_access_technology_update_ready,
+ task);
+
+ g_free (command);
+}
+
+static void
+set_current_modes (MMIfaceModem *_self,
+ MMModemMode allowed,
+ MMModemMode preferred,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ if (self->priv->sxrat_support == FEATURE_SUPPORTED)
+ sxrat_set_current_modes (self, allowed, preferred, task);
+ else if (self->priv->sxrat_support == FEATURE_NOT_SUPPORTED)
+ cops_set_current_modes (self, allowed, preferred, task);
+ else
+ g_assert_not_reached ();
+}
+
/*****************************************************************************/
/* Supported bands (Modem interface) */
@@ -2917,6 +3145,7 @@
self->priv->swwan_support = FEATURE_SUPPORT_UNKNOWN;
self->priv->smoni_support = FEATURE_SUPPORT_UNKNOWN;
self->priv->sind_simstatus_support = FEATURE_SUPPORT_UNKNOWN;
+ self->priv->sxrat_support = FEATURE_SUPPORT_UNKNOWN;
self->priv->ciev_regex = g_regex_new ("\\r\\n\\+CIEV:\\s*([a-z]+),(\\d+)\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
@@ -2924,6 +3153,8 @@
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
self->priv->scks_regex = g_regex_new ("\\^SCKS:\\s*([0-3])\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+
+ self->priv->any_allowed = MM_MODEM_MODE_NONE;
}
static void
@@ -2943,6 +3174,10 @@
g_array_unref (self->priv->cnmi_supported_ds);
if (self->priv->cnmi_supported_bfr)
g_array_unref (self->priv->cnmi_supported_bfr);
+ if (self->priv->sxrat_supported_rat)
+ g_array_unref (self->priv->sxrat_supported_rat);
+ if (self->priv->sxrat_supported_pref1)
+ g_array_unref (self->priv->sxrat_supported_pref1);
g_regex_unref (self->priv->ciev_regex);
g_regex_unref (self->priv->sysstart_regex);
diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.c b/plugins/cinterion/mm-modem-helpers-cinterion.c
index 9219bff..f22a998 100644
--- a/plugins/cinterion/mm-modem-helpers-cinterion.c
+++ b/plugins/cinterion/mm-modem-helpers-cinterion.c
@@ -638,6 +638,94 @@
}
/*****************************************************************************/
+/* ^SXRAT test parser
+ *
+ * Example (ELS61-E2):
+ * AT^SXRAT=?
+ * ^SXRAT: (0-6),(0,2,3),(0,2,3)
+ */
+
+gboolean
+mm_cinterion_parse_sxrat_test (const gchar *response,
+ GArray **supported_rat,
+ GArray **supported_pref1,
+ GArray **supported_pref2,
+ GError **error)
+{
+ g_autoptr(GRegex) r = NULL;
+ g_autoptr(GMatchInfo) match_info = NULL;
+ GError *inner_error = NULL;
+ GArray *tmp_supported_rat = NULL;
+ GArray *tmp_supported_pref1 = NULL;
+ GArray *tmp_supported_pref2 = NULL;
+
+ if (!response) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response");
+ return FALSE;
+ }
+
+ r = g_regex_new ("\\^SXRAT:\\s*\\(([^\\)]*)\\),\\(([^\\)]*)\\)(,\\(([^\\)]*)\\))?(?:\\r\\n)?",
+ G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
+ 0, NULL);
+
+ g_assert (r != NULL);
+
+ g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
+
+ if (!inner_error && g_match_info_matches (match_info)) {
+ if (supported_rat) {
+ g_autofree gchar *str = NULL;
+
+ str = mm_get_string_unquoted_from_match_info (match_info, 1);
+ tmp_supported_rat = mm_parse_uint_list (str, &inner_error);
+
+ if (inner_error)
+ goto out;
+ }
+ if (supported_pref1) {
+ g_autofree gchar *str = NULL;
+
+ str = mm_get_string_unquoted_from_match_info (match_info, 2);
+ tmp_supported_pref1 = mm_parse_uint_list (str, &inner_error);
+
+ if (inner_error)
+ goto out;
+ }
+ if (supported_pref2) {
+ g_autofree gchar *str = NULL;
+
+ /* this match is optional */
+ str = mm_get_string_unquoted_from_match_info (match_info, 4);
+ if (str) {
+ tmp_supported_pref2 = mm_parse_uint_list (str, &inner_error);
+
+ if (inner_error)
+ goto out;
+ }
+ }
+ }
+
+out:
+
+ if (inner_error) {
+ g_clear_pointer (&tmp_supported_rat, g_array_unref);
+ g_clear_pointer (&tmp_supported_pref1, g_array_unref);
+ g_clear_pointer (&tmp_supported_pref2, g_array_unref);
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ if (supported_rat)
+ *supported_rat = tmp_supported_rat;
+ if (supported_pref1)
+ *supported_pref1 = tmp_supported_pref1;
+ if (supported_pref2)
+ *supported_pref2 = tmp_supported_pref2;
+
+ return TRUE;
+}
+
+/*****************************************************************************/
/* Build Cinterion-specific band value */
gboolean
@@ -1651,3 +1739,66 @@
quoted_passwd,
quoted_user);
}
+
+/*****************************************************************************/
+/* ^SXRAT set command builder */
+
+/* Index of the array is the centerion-specific sxrat value */
+static const MMModemMode sxrat_combinations[] = {
+ [0] = ( MM_MODEM_MODE_2G ),
+ [1] = ( MM_MODEM_MODE_2G | MM_MODEM_MODE_3G ),
+ [2] = ( MM_MODEM_MODE_3G ),
+ [3] = ( MM_MODEM_MODE_4G ),
+ [4] = ( MM_MODEM_MODE_3G | MM_MODEM_MODE_4G ),
+ [5] = ( MM_MODEM_MODE_2G | MM_MODEM_MODE_4G ),
+ [6] = ( MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G ),
+};
+
+static gboolean
+append_sxrat_rat_value (GString *str,
+ MMModemMode mode,
+ GError **error)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (sxrat_combinations); i++) {
+ if (sxrat_combinations[i] == mode) {
+ g_string_append_printf (str, "%u", i);
+ return TRUE;
+ }
+ }
+
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "No AcT value matches requested mode");
+ return FALSE;
+}
+
+gchar *
+mm_cinterion_build_sxrat_set_command (MMModemMode allowed,
+ MMModemMode preferred,
+ GError **error)
+{
+ GString *command;
+
+ command = g_string_new ("^SXRAT=");
+ if (!append_sxrat_rat_value (command, allowed, error)) {
+ g_string_free (command, TRUE);
+ return NULL;
+ }
+
+ if (preferred != MM_MODEM_MODE_NONE) {
+ if (mm_count_bits_set (preferred) != 1) {
+ *error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "AcT preferred value should be a single AcT");
+ g_string_free (command, TRUE);
+ return NULL;
+ }
+ g_string_append (command, ",");
+ if (!append_sxrat_rat_value (command, preferred, error)) {
+ g_string_free (command, TRUE);
+ return NULL;
+ }
+ }
+
+ return g_string_free (command, FALSE);
+}
diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.h b/plugins/cinterion/mm-modem-helpers-cinterion.h
index 7bbd789..3155d0c 100644
--- a/plugins/cinterion/mm-modem-helpers-cinterion.h
+++ b/plugins/cinterion/mm-modem-helpers-cinterion.h
@@ -84,6 +84,15 @@
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,
@@ -192,4 +201,11 @@
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 */
diff --git a/plugins/cinterion/tests/test-modem-helpers-cinterion.c b/plugins/cinterion/tests/test-modem-helpers-cinterion.c
index 8332700..d481619 100644
--- a/plugins/cinterion/tests/test-modem-helpers-cinterion.c
+++ b/plugins/cinterion/tests/test-modem-helpers-cinterion.c
@@ -1744,6 +1744,187 @@
}
/*****************************************************************************/
+/* Test ^SXRAT responses */
+
+static void
+common_test_sxrat (const gchar *response,
+ const GArray *expected_rat,
+ const GArray *expected_pref1,
+ const GArray *expected_pref2)
+{
+ GArray *supported_rat = NULL;
+ GArray *supported_pref1 = NULL;
+ GArray *supported_pref2 = NULL;
+ GError *error = NULL;
+ gboolean res;
+
+ g_assert (expected_rat != NULL);
+ g_assert (expected_pref1 != NULL);
+
+ res = mm_cinterion_parse_sxrat_test (response,
+ &supported_rat,
+ &supported_pref1,
+ &supported_pref2,
+ &error);
+ g_assert_no_error (error);
+ g_assert (res == TRUE);
+ g_assert (supported_rat != NULL);
+ g_assert (supported_pref1 != NULL);
+ if (expected_pref2)
+ g_assert (supported_pref2 != NULL);
+ else
+ g_assert (supported_pref2 == NULL);
+
+ compare_arrays (supported_rat, expected_rat);
+ compare_arrays (supported_pref1, expected_pref1);
+ if (expected_pref2)
+ compare_arrays (supported_pref2, expected_pref2);
+
+ g_array_unref (supported_rat);
+ g_array_unref (supported_pref1);
+ if (supported_pref2)
+ g_array_unref (supported_pref2);
+}
+
+static void
+test_sxrat_response_els61 (void)
+{
+ GArray *expected_rat;
+ GArray *expected_pref1;
+ GArray *expected_pref2;
+ guint val;
+ const gchar *response =
+ "^SXRAT: (0-6),(0,2,3),(0,2,3)\r\n"
+ "\r\n";
+
+ expected_rat = g_array_sized_new (FALSE, FALSE, sizeof (guint), 7);
+ val = 0, g_array_append_val (expected_rat, val);
+ val = 1, g_array_append_val (expected_rat, val);
+ val = 2, g_array_append_val (expected_rat, val);
+ val = 3, g_array_append_val (expected_rat, val);
+ val = 4, g_array_append_val (expected_rat, val);
+ val = 5, g_array_append_val (expected_rat, val);
+ val = 6, g_array_append_val (expected_rat, val);
+
+ expected_pref1 = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3);
+ val = 0, g_array_append_val (expected_pref1, val);
+ val = 2, g_array_append_val (expected_pref1, val);
+ val = 3, g_array_append_val (expected_pref1, val);
+
+ expected_pref2 = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3);
+ val = 0, g_array_append_val (expected_pref2, val);
+ val = 2, g_array_append_val (expected_pref2, val);
+ val = 3, g_array_append_val (expected_pref2, val);
+
+ common_test_sxrat (response,
+ expected_rat,
+ expected_pref1,
+ expected_pref2);
+
+ g_array_unref (expected_rat);
+ g_array_unref (expected_pref1);
+ g_array_unref (expected_pref2);
+}
+
+static void
+test_sxrat_response_other (void)
+{
+ GArray *expected_rat;
+ GArray *expected_pref1;
+ GArray *expected_pref2 = NULL;
+ guint val;
+ const gchar *response =
+ "^SXRAT: (0-2),(0,2)\r\n"
+ "\r\n";
+
+ expected_rat = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3);
+ val = 0, g_array_append_val (expected_rat, val);
+ val = 1, g_array_append_val (expected_rat, val);
+ val = 2, g_array_append_val (expected_rat, val);
+
+ expected_pref1 = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3);
+ val = 0, g_array_append_val (expected_pref1, val);
+ val = 2, g_array_append_val (expected_pref1, val);
+
+ common_test_sxrat (response,
+ expected_rat,
+ expected_pref1,
+ expected_pref2);
+
+ g_array_unref (expected_rat);
+ g_array_unref (expected_pref1);
+}
+
+typedef struct {
+ const gchar *str;
+ MMModemMode allowed;
+ MMModemMode preferred;
+ gboolean success;
+} SxratBuildTest;
+
+static const SxratBuildTest sxrat_build_tests[] = {
+ {
+ .str = "^SXRAT=0",
+ .allowed = MM_MODEM_MODE_2G,
+ .preferred = MM_MODEM_MODE_NONE,
+ .success = TRUE,
+ },
+ {
+ .str = "^SXRAT=3",
+ .allowed = MM_MODEM_MODE_4G,
+ .preferred = MM_MODEM_MODE_NONE,
+ .success = TRUE,
+ },
+ {
+ .str = "^SXRAT=1,2",
+ .allowed = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G,
+ .preferred = MM_MODEM_MODE_3G,
+ .success = TRUE,
+ },
+ {
+ .str = "^SXRAT=6,3",
+ .allowed = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G,
+ .preferred = MM_MODEM_MODE_4G,
+ .success = TRUE,
+ },
+ {
+ .str = NULL,
+ .allowed = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G,
+ .preferred = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G,
+ .success = FALSE,
+ },
+ {
+ .str = NULL,
+ .allowed = MM_MODEM_MODE_5G,
+ .preferred = MM_MODEM_MODE_NONE,
+ .success = FALSE,
+ },
+
+};
+
+static void
+test_sxrat (void)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (sxrat_build_tests); i++) {
+ GError *error = NULL;
+ gchar* result;
+
+ result = mm_cinterion_build_sxrat_set_command (sxrat_build_tests[i].allowed,
+ sxrat_build_tests[i].preferred,
+ &error);
+ if (sxrat_build_tests[i].success) {
+ g_assert_no_error (error);
+ g_assert (result);
+ g_assert_cmpstr (result, ==, sxrat_build_tests[i].str);
+ } else {
+ g_assert (error);
+ g_assert (!result);
+ }
+ }
+}
+/*****************************************************************************/
int main (int argc, char **argv)
{
@@ -1778,6 +1959,9 @@
g_test_add_func ("/MM/cinterion/smoni/query_response_to_signal", test_smoni_response_to_signal);
g_test_add_func ("/MM/cinterion/scfg/provcfg", test_provcfg_response);
g_test_add_func ("/MM/cinterion/sgauth", test_sgauth_response);
+ g_test_add_func ("/MM/cinterion/sxrat", test_sxrat);
+ g_test_add_func ("/MM/cinterion/sxrat/response/els61", test_sxrat_response_els61);
+ g_test_add_func ("/MM/cinterion/sxrat/response/other", test_sxrat_response_other);
return g_test_run ();
}
diff --git a/plugins/fibocom/77-mm-fibocom-port-types.rules b/plugins/fibocom/77-mm-fibocom-port-types.rules
index 1b6c105..a2b9cfc 100644
--- a/plugins/fibocom/77-mm-fibocom-port-types.rules
+++ b/plugins/fibocom/77-mm-fibocom-port-types.rules
@@ -63,6 +63,7 @@
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
@@ -70,12 +71,14 @@
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
diff --git a/plugins/fibocom/mm-broadband-bearer-fibocom-ecm.c b/plugins/fibocom/mm-broadband-bearer-fibocom-ecm.c
index 6d045e1..bc4ee1e 100644
--- a/plugins/fibocom/mm-broadband-bearer-fibocom-ecm.c
+++ b/plugins/fibocom/mm-broadband-bearer-fibocom-ecm.c
@@ -64,6 +64,73 @@
}
/*****************************************************************************/
+/* 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 {
@@ -458,8 +525,12 @@
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;
diff --git a/plugins/fibocom/mm-broadband-modem-fibocom.c b/plugins/fibocom/mm-broadband-modem-fibocom.c
index 9a81943..9d65969 100644
--- a/plugins/fibocom/mm-broadband-modem-fibocom.c
+++ b/plugins/fibocom/mm-broadband-modem-fibocom.c
@@ -18,14 +18,22 @@
#include "mm-broadband-modem-fibocom.h"
#include "mm-broadband-bearer-fibocom-ecm.h"
#include "mm-broadband-modem.h"
-#include "mm-iface-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_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, 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,
@@ -36,6 +44,8 @@
struct _MMBroadbandModemFibocomPrivate {
FeatureSupport gtrndis_support;
GRegex *sim_ready_regex;
+ FeatureSupport initial_eps_bearer_support;
+ gint initial_eps_bearer_cid;
};
/*****************************************************************************/
@@ -164,12 +174,12 @@
}
/*****************************************************************************/
-/* Reset (Modem interface) */
+/* Reset / Power (Modem interface) */
static gboolean
-modem_reset_finish (MMIfaceModem *self,
- GAsyncResult *res,
- GError **error)
+modem_common_power_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
{
return !!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, error);
}
@@ -181,6 +191,32 @@
{
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,
@@ -188,6 +224,430 @@
}
/*****************************************************************************/
+/* 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)
@@ -240,9 +700,9 @@
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
@@ -261,7 +721,31 @@
iface->create_bearer = modem_create_bearer;
iface->create_bearer_finish = modem_create_bearer_finish;
iface->reset = modem_reset;
- iface->reset_finish = modem_reset_finish;
+ 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
diff --git a/plugins/foxconn/mm-broadband-modem-mbim-foxconn.c b/plugins/foxconn/mm-broadband-modem-mbim-foxconn.c
index cfc0237..cec1c61 100644
--- a/plugins/foxconn/mm-broadband-modem-mbim-foxconn.c
+++ b/plugins/foxconn/mm-broadband-modem-mbim-foxconn.c
@@ -36,6 +36,7 @@
#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);
@@ -96,6 +97,31 @@
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)
@@ -164,15 +190,19 @@
}
static void
-firmware_load_update_settings (MMIfaceModemFirmware *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+mbim_port_allocate_qmi_client_ready (MMPortMbim *mbim,
+ GAsyncResult *res,
+ GTask *task)
{
- GTask *task;
- QmiClient *fox_client = NULL;
- QmiClient *dms_client = NULL;
+ MMIfaceModemFirmware *self;
+ QmiClient *fox_client = NULL;
+ QmiClient *dms_client = NULL;
+ g_autoptr(GError) error = NULL;
- task = g_task_new (self, NULL, callback, user_data);
+ 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);
@@ -209,7 +239,7 @@
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_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);
@@ -225,6 +255,24 @@
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
/*****************************************************************************/
diff --git a/plugins/quectel/mm-shared-quectel.c b/plugins/quectel/mm-shared-quectel.c
index c383dc0..47d7cd3 100644
--- a/plugins/quectel/mm-shared-quectel.c
+++ b/plugins/quectel/mm-shared-quectel.c
@@ -56,6 +56,7 @@
FeatureSupport qgps_supported;
GRegex *qgpsurc_regex;
GRegex *qlwurc_regex;
+ GRegex *rdy_regex;
} Private;
static void
@@ -63,6 +64,7 @@
{
g_regex_unref (priv->qgpsurc_regex);
g_regex_unref (priv->qlwurc_regex);
+ g_regex_unref (priv->rdy_regex);
g_slice_free (Private, priv);
}
@@ -83,6 +85,11 @@
priv->qgps_supported = FEATURE_SUPPORT_UNKNOWN;
priv->qgpsurc_regex = g_regex_new ("\\r\\n\\+QGPSURC:.*", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
priv->qlwurc_regex = g_regex_new ("\\r\\n\\+QLWURC:.*", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ priv->rdy_regex = g_regex_new ("\\r\\nRDY", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+
+ g_assert (priv->qgpsurc_regex);
+ g_assert (priv->qlwurc_regex);
+ g_assert (priv->rdy_regex);
g_assert (MM_SHARED_QUECTEL_GET_INTERFACE (self)->peek_parent_broadband_modem_class);
priv->broadband_modem_class_parent = MM_SHARED_QUECTEL_GET_INTERFACE (self)->peek_parent_broadband_modem_class (self);
@@ -99,6 +106,23 @@
}
/*****************************************************************************/
+/* RDY unsolicited event handler */
+
+static void
+rdy_handler (MMPortSerialAt *port,
+ GMatchInfo *match_info,
+ MMBroadbandModem *self)
+{
+ /* The RDY URC indicates a modem reset that may or may not go hand-in-hand
+ * with USB re-enumeration. For the latter case, we must make sure to
+ * re-synchronize modem and ModemManager states by re-probing.
+ */
+ mm_obj_warn (self, "modem reset detected, triggering reprobe");
+ mm_base_modem_set_reprobe (MM_BASE_MODEM (self), TRUE);
+ mm_base_modem_set_valid (MM_BASE_MODEM (self), FALSE);
+}
+
+/*****************************************************************************/
/* Setup ports (Broadband modem class) */
void
@@ -134,6 +158,14 @@
ports[i],
priv->qlwurc_regex,
NULL, NULL, NULL);
+
+ /* Handle RDY */
+ mm_port_serial_at_add_unsolicited_msg_handler (
+ ports[i],
+ priv->rdy_regex,
+ (MMPortSerialAtUnsolicitedMsgFn)rdy_handler,
+ self,
+ NULL);
}
}
diff --git a/plugins/telit/77-mm-telit-port-types.rules b/plugins/telit/77-mm-telit-port-types.rules
index b422984..b9439ff 100644
--- a/plugins/telit/77-mm-telit-port-types.rules
+++ b/plugins/telit/77-mm-telit-port-types.rules
@@ -122,20 +122,6 @@
ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="7011", ENV{.MM_USBIFNUM}=="03", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="7011", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
-# LM940/960 use alternate settings for 3G band management
-ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1040", ENV{ID_MM_TELIT_BND_ALTERNATE}="1"
-ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1041", ENV{ID_MM_TELIT_BND_ALTERNATE}="1"
-ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1042", ENV{ID_MM_TELIT_BND_ALTERNATE}="1"
-ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1043", ENV{ID_MM_TELIT_BND_ALTERNATE}="1"
-
-# FN980 use alternate settings for 3G band management
-ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1050", ENV{ID_MM_TELIT_BND_ALTERNATE}="1"
-ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1051", ENV{ID_MM_TELIT_BND_ALTERNATE}="1"
-
-# LN920 use alternate settings for 3G band management
-ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1060", ENV{ID_MM_TELIT_BND_ALTERNATE}="1"
-ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1061", ENV{ID_MM_TELIT_BND_ALTERNATE}="1"
-
# LM940/960 initial port delay
ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1040", ENV{ID_MM_TELIT_PORT_DELAY}="1"
ATTRS{idVendor}=="1bc7", ATTRS{idProduct}=="1041", ENV{ID_MM_TELIT_PORT_DELAY}="1"
diff --git a/plugins/telit/mm-broadband-modem-telit.c b/plugins/telit/mm-broadband-modem-telit.c
index bbf3f76..3254eef 100644
--- a/plugins/telit/mm-broadband-modem-telit.c
+++ b/plugins/telit/mm-broadband-modem-telit.c
@@ -69,7 +69,6 @@
MMModemLocationSource enabled_sources;
};
-
typedef struct {
MMModemLocationSource source;
guint gps_enable_step;
@@ -1070,11 +1069,11 @@
/* Load access technologies (Modem interface) */
static gboolean
-load_access_technologies_finish (MMIfaceModem *self,
- GAsyncResult *res,
+load_access_technologies_finish (MMIfaceModem *self,
+ GAsyncResult *res,
MMModemAccessTechnology *access_technologies,
- guint *mask,
- GError **error)
+ guint *mask,
+ GError **error)
{
GVariant *result;
@@ -1091,6 +1090,106 @@
}
static MMBaseModemAtResponseProcessorResult
+response_processor_cops_ignore_at_errors (MMBaseModem *self,
+ gpointer none,
+ const gchar *command,
+ const gchar *response,
+ gboolean last_command,
+ const GError *error,
+ GVariant **result,
+ GError **result_error)
+{
+ g_autoptr(GMatchInfo) match_info = NULL;
+ g_autoptr(GRegex) r = NULL;
+ guint actval = 0;
+ guint mode = 0;
+ guint vid;
+ guint pid;
+
+ *result = NULL;
+ *result_error = NULL;
+
+ if (error) {
+ /* Ignore AT errors (ie, ERROR or CMx ERROR) */
+ if (error->domain != MM_MOBILE_EQUIPMENT_ERROR || last_command) {
+ *result_error = g_error_copy (error);
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE;
+ }
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE;
+ }
+
+ vid = mm_base_modem_get_vendor_id (self);
+ pid = mm_base_modem_get_product_id (self);
+
+ if (!(vid == 0x1bc7 && (pid == 0x110a || pid == 0x110b))) {
+ /* AcT for non-LPWA modems would be checked by other command */
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE;
+ }
+
+ r = g_regex_new ("\\+COPS:\\s*(\\d+),(\\d+),([^,]*)(?:,(\\d+))?(?:\\r\\n)?",
+ 0,
+ 0,
+ NULL);
+ g_assert (r != NULL);
+
+ if (!g_regex_match (r, response, 0, &match_info)) {
+ g_set_error (result_error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Can't match +COPS? response: '%s'",
+ response);
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE;
+ }
+
+ if (!mm_get_uint_from_match_info (match_info, 1, &mode)) {
+ g_set_error (result_error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Failed to parse mode in +COPS? response: '%s'",
+ response);
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE;
+ }
+
+ if (mode == 2) {
+ g_set_error (result_error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Modem deregistered from the network: aborting AcT query");
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE;
+ }
+
+ if (!mm_get_uint_from_match_info (match_info, 4, &actval)) {
+ g_set_error (result_error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Failed to parse act in +COPS? response: '%s'",
+ response);
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE;
+ }
+
+ switch (actval) {
+ case 0:
+ *result = g_variant_new_uint32 (MM_MODEM_ACCESS_TECHNOLOGY_GSM);
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS;
+ case 8:
+ *result = g_variant_new_uint32 (MM_MODEM_ACCESS_TECHNOLOGY_LTE_CAT_M);
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS;
+ case 9:
+ *result = g_variant_new_uint32 (MM_MODEM_ACCESS_TECHNOLOGY_LTE_NB_IOT);
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS;
+ default:
+ break;
+ }
+
+ g_set_error (result_error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Failed to map act in +COPS? response: '%s'",
+ response);
+ return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE;
+}
+
+static MMBaseModemAtResponseProcessorResult
response_processor_psnt_ignore_at_errors (MMBaseModem *self,
gpointer none,
const gchar *command,
@@ -1208,6 +1307,7 @@
}
static const MMBaseModemAtCommand access_tech_commands[] = {
+ { "+COPS?", 3, FALSE, response_processor_cops_ignore_at_errors },
{ "#PSNT?", 3, FALSE, response_processor_psnt_ignore_at_errors },
{ "+SERVICE?", 3, FALSE, response_processor_service_ignore_at_errors },
{ NULL }
diff --git a/plugins/telit/mm-modem-helpers-telit.c b/plugins/telit/mm-modem-helpers-telit.c
index 54cd6a0..c0df809 100644
--- a/plugins/telit/mm-modem-helpers-telit.c
+++ b/plugins/telit/mm-modem-helpers-telit.c
@@ -187,7 +187,7 @@
#define B4G_FLAG(band) (((guint64) 1) << (band - MM_MODEM_BAND_TELIT_4G_FIRST))
#define MM_MODEM_BAND_TELIT_EXT_4G_FIRST MM_MODEM_BAND_EUTRAN_65
-#define MM_MODEM_BAND_TELIT_EXT_4G_LAST MM_MODEM_BAND_EUTRAN_71
+#define MM_MODEM_BAND_TELIT_EXT_4G_LAST MM_MODEM_BAND_EUTRAN_85
#define B4G_FLAG_EXT(band) (((guint64) 1) << (band - MM_MODEM_BAND_TELIT_EXT_4G_FIRST))
@@ -195,13 +195,9 @@
/* Set current bands helpers */
gchar *
-mm_telit_build_bnd_request (GArray *bands_array,
- gboolean modem_is_2g,
- gboolean modem_is_3g,
- gboolean modem_is_4g,
- gboolean modem_alternate_3g_bands,
- gboolean modem_ext_4g_bands,
- GError **error)
+mm_telit_build_bnd_request (GArray *bands_array,
+ MMTelitBNDParseConfig *config,
+ GError **error)
{
guint32 mask2g = 0;
guint64 mask3g = 0;
@@ -212,19 +208,9 @@
gint64 flag3g = -1;
gint64 flag4g = -1;
gchar *cmd;
- const guint64 *telit_3g_to_mm_band_mask;
- guint telit_3g_to_mm_band_mask_n_elements;
-
- initialize_telit_3g_to_mm_band_masks ();
-
- /* Select correct 3G band mask */
- if (modem_alternate_3g_bands) {
- telit_3g_to_mm_band_mask = telit_3g_to_mm_band_mask_alternate;
- telit_3g_to_mm_band_mask_n_elements = G_N_ELEMENTS (telit_3g_to_mm_band_mask_alternate);
- } else {
- telit_3g_to_mm_band_mask = telit_3g_to_mm_band_mask_default;
- telit_3g_to_mm_band_mask_n_elements = G_N_ELEMENTS (telit_3g_to_mm_band_mask_default);
- }
+ gboolean modem_is_2g = config->modem_is_2g;
+ gboolean modem_is_3g = config->modem_is_3g;
+ gboolean modem_is_4g = config->modem_is_4g;
for (i = 0; i < bands_array->len; i++) {
MMModemBand band;
@@ -273,6 +259,19 @@
/* Get 3G-specific telit value */
if (mask3g) {
+ const guint64 *telit_3g_to_mm_band_mask;
+ guint telit_3g_to_mm_band_mask_n_elements;
+
+ initialize_telit_3g_to_mm_band_masks ();
+
+ /* Select correct 3G band mask */
+ if (config->modem_alternate_3g_bands) {
+ telit_3g_to_mm_band_mask = telit_3g_to_mm_band_mask_alternate;
+ telit_3g_to_mm_band_mask_n_elements = G_N_ELEMENTS (telit_3g_to_mm_band_mask_alternate);
+ } else {
+ telit_3g_to_mm_band_mask = telit_3g_to_mm_band_mask_default;
+ telit_3g_to_mm_band_mask_n_elements = G_N_ELEMENTS (telit_3g_to_mm_band_mask_default);
+ }
for (i = 0; i < telit_3g_to_mm_band_mask_n_elements; i++) {
if (mask3g == telit_3g_to_mm_band_mask[i]) {
flag3g = i;
@@ -318,24 +317,24 @@
else if (modem_is_2g && modem_is_3g && !modem_is_4g)
cmd = g_strdup_printf ("#BND=%d,%" G_GINT64_FORMAT, flag2g, flag3g);
else if (!modem_is_2g && !modem_is_3g && modem_is_4g) {
- if (!modem_ext_4g_bands)
+ if (!config->modem_ext_4g_bands)
cmd = g_strdup_printf ("#BND=0,0,%" G_GINT64_FORMAT, flag4g);
else
cmd = g_strdup_printf ("#BND=0,0,%" G_GINT64_MODIFIER "x" ",%" G_GINT64_MODIFIER "x", mask4g, mask4gext);
} else if (!modem_is_2g && modem_is_3g && modem_is_4g) {
- if (!modem_ext_4g_bands)
+ if (!config->modem_ext_4g_bands)
cmd = g_strdup_printf ("#BND=0,%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT, flag3g, flag4g);
else
cmd = g_strdup_printf ("#BND=0,%" G_GINT64_FORMAT ",%" G_GINT64_MODIFIER "x" ",%" G_GINT64_MODIFIER "x", flag3g, mask4g, mask4gext);
} else if (modem_is_2g && !modem_is_3g && modem_is_4g) {
- if (!modem_ext_4g_bands)
+ if (!config->modem_ext_4g_bands)
cmd = g_strdup_printf ("#BND=%d,0,%" G_GINT64_FORMAT, flag2g, flag4g);
else
cmd = g_strdup_printf ("#BND=%d,0,%" G_GINT64_MODIFIER "x" ",%" G_GINT64_MODIFIER "x", flag2g, mask4g, mask4gext);
} else if (modem_is_2g && modem_is_3g && modem_is_4g) {
- if (!modem_ext_4g_bands)
+ if (!config->modem_ext_4g_bands)
cmd = g_strdup_printf ("#BND=%d,%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT, flag2g, flag3g, flag4g);
- else
+ else
cmd = g_strdup_printf ("#BND=%d,%" G_GINT64_FORMAT ",%" G_GINT64_MODIFIER "x" ",%" G_GINT64_MODIFIER "x", flag2g, flag3g, mask4g, mask4gext);
} else
g_assert_not_reached ();
@@ -668,15 +667,6 @@
LOAD_BANDS_TYPE_CURRENT,
} LoadBandsType;
-static gboolean
-bnd_response_has_ext_4g_bands (const gchar *response)
-{
- g_auto(GStrv) tokens = NULL;
-
- tokens = mm_split_string_groups (response);
- return g_strv_length (tokens) == 4;
-}
-
/* Regex tokens for #BND parsing */
#define MM_SUPPORTED_BANDS_2G "\\s*\\((?P<Bands2G>[0-9\\-,]*)\\)"
#define MM_SUPPORTED_BANDS_3G "(,\\s*\\((?P<Bands3G>[0-9\\-,]*)\\))?"
@@ -690,16 +680,11 @@
#define MM_CURRENT_BANDS_4G_EXT "(,\\s*(?P<Bands4GHex>[0-9A-F]+))?(,\\s*(?P<Bands4GExt>[0-9A-F]+))?"
static GArray *
-common_parse_bnd_response (const gchar *response,
- gboolean modem_is_2g,
- gboolean modem_is_3g,
- gboolean modem_is_4g,
- gboolean modem_alternate_3g_bands,
- gboolean modem_has_hex_format_4g_bands,
- gboolean modem_ext_4g_bands,
- LoadBandsType load_type,
- gpointer log_object,
- GError **error)
+common_parse_bnd_response (const gchar *response,
+ MMTelitBNDParseConfig *config,
+ LoadBandsType load_type,
+ gpointer log_object,
+ GError **error)
{
g_autoptr(GMatchInfo) match_info = NULL;
g_autoptr(GRegex) r = NULL;
@@ -721,9 +706,9 @@
[LOAD_BANDS_TYPE_CURRENT] = "#BND:"MM_CURRENT_BANDS_2G MM_CURRENT_BANDS_3G MM_CURRENT_BANDS_4G_EXT,
};
- if (modem_ext_4g_bands)
+ if (config->modem_ext_4g_bands)
load_bands_regex = load_bands_regex_4g_ext[load_type];
- else if (modem_has_hex_format_4g_bands)
+ else if (config->modem_has_hex_format_4g_bands)
load_bands_regex = load_bands_regex_4g_hex[load_type];
else
load_bands_regex = load_bands_regex_4g_dec[load_type];
@@ -745,16 +730,16 @@
bands = g_array_new (TRUE, TRUE, sizeof (MMModemBand));
- if (modem_is_2g && !telit_get_2g_mm_bands (match_info, log_object, &bands, &inner_error))
+ if (config->modem_is_2g && !telit_get_2g_mm_bands (match_info, log_object, &bands, &inner_error))
goto out;
- if (modem_is_3g && !telit_get_3g_mm_bands (match_info, log_object, modem_alternate_3g_bands, &bands, &inner_error))
+ if (config->modem_is_3g && !telit_get_3g_mm_bands (match_info, log_object, config->modem_alternate_3g_bands, &bands, &inner_error))
goto out;
- if (modem_is_4g) {
+ if (config->modem_is_4g) {
gboolean ok;
- ok = modem_ext_4g_bands?
+ ok = config->modem_ext_4g_bands?
telit_get_ext_4g_mm_bands (match_info, &bands, &inner_error) :
telit_get_4g_mm_bands (match_info, &bands, &inner_error);
if (!ok)
@@ -771,43 +756,26 @@
}
GArray *
-mm_telit_parse_bnd_query_response (const gchar *response,
- gboolean modem_is_2g,
- gboolean modem_is_3g,
- gboolean modem_is_4g,
- gboolean modem_alternate_3g_bands,
- gboolean modem_has_hex_format_4g_bands,
- gboolean modem_ext_4g_bands,
- gpointer log_object,
- GError **error)
+mm_telit_parse_bnd_query_response (const gchar *response,
+ MMTelitBNDParseConfig *config,
+ gpointer log_object,
+ GError **error)
{
return common_parse_bnd_response (response,
- modem_is_2g, modem_is_3g, modem_is_4g,
- modem_alternate_3g_bands,
- modem_has_hex_format_4g_bands,
- modem_ext_4g_bands,
+ config,
LOAD_BANDS_TYPE_CURRENT,
log_object,
error);
}
GArray *
-mm_telit_parse_bnd_test_response (const gchar *response,
- gboolean modem_is_2g,
- gboolean modem_is_3g,
- gboolean modem_is_4g,
- gboolean modem_alternate_3g_bands,
- gboolean modem_has_hex_format_4g_bands,
- gboolean *modem_ext_4g_bands,
- gpointer log_object,
- GError **error)
+mm_telit_parse_bnd_test_response (const gchar *response,
+ MMTelitBNDParseConfig *config,
+ gpointer log_object,
+ GError **error)
{
- *modem_ext_4g_bands = bnd_response_has_ext_4g_bands (response);
return common_parse_bnd_response (response,
- modem_is_2g, modem_is_3g, modem_is_4g,
- modem_alternate_3g_bands,
- modem_has_hex_format_4g_bands,
- *modem_ext_4g_bands,
+ config,
LOAD_BANDS_TYPE_SUPPORTED,
log_object,
error);
@@ -937,7 +905,8 @@
{"25.", MM_TELIT_MODEL_LE910C1},
{"32.", MM_TELIT_MODEL_LM960},
{"38.", MM_TELIT_MODEL_FN980},
- {"40.", MM_TELIT_MODEL_LN920}
+ {"40.", MM_TELIT_MODEL_LN920},
+ {"45.00", MM_TELIT_MODEL_FN990},
};
if (!revision)
@@ -950,3 +919,49 @@
return MM_TELIT_MODEL_DEFAULT;
}
+
+static MMTelitSwRevCmp lm9x0_software_revision_cmp (const gchar *revision_a,
+ const gchar *revision_b)
+{
+ /* LM940 and LM960 share the same software revision format
+ * WW.XY.ABC[-ZZZZ], where WW is the chipset code and C the major version.
+ * If WW is the same, the other values X, Y, A and B are also the same, so
+ * we can limit the comparison to C only. ZZZZ is the minor version (it
+ * includes if version is beta, test, or alpha), but at this stage we are
+ * not interested in compare it. */
+ guint chipset_a, chipset_b;
+ guint major_a, major_b;
+ guint x, y, a, b;
+
+ g_return_val_if_fail (
+ sscanf (revision_a, "%2u.%1u%1u.%1u%1u%1u", &chipset_a, &x, &y, &a, &b, &major_a) == 6,
+ MM_TELIT_SW_REV_CMP_INVALID);
+ g_return_val_if_fail (
+ sscanf (revision_b, "%2u.%1u%1u.%1u%1u%1u", &chipset_b, &x, &y, &a, &b, &major_b) == 6,
+ MM_TELIT_SW_REV_CMP_INVALID);
+
+ if (chipset_a != chipset_b)
+ return MM_TELIT_SW_REV_CMP_INVALID;
+ if (major_a > major_b)
+ return MM_TELIT_SW_REV_CMP_NEWER;
+ if (major_a < major_b)
+ return MM_TELIT_SW_REV_CMP_OLDER;
+ return MM_TELIT_SW_REV_CMP_EQUAL;
+}
+
+MMTelitSwRevCmp mm_telit_software_revision_cmp (const gchar *revision_a,
+ const gchar *revision_b)
+{
+ MMTelitModel model_a;
+ MMTelitModel model_b;
+
+ model_a = mm_telit_model_from_revision (revision_a);
+ model_b = mm_telit_model_from_revision (revision_b);
+
+ if ((model_a == MM_TELIT_MODEL_LM940 || model_a == MM_TELIT_MODEL_LM960) &&
+ (model_b == MM_TELIT_MODEL_LM940 || model_b == MM_TELIT_MODEL_LM960)) {
+ return lm9x0_software_revision_cmp (revision_a, revision_b);
+ }
+
+ return MM_TELIT_SW_REV_CMP_UNSUPPORTED;
+}
diff --git a/plugins/telit/mm-modem-helpers-telit.h b/plugins/telit/mm-modem-helpers-telit.h
index 97eaf47..3844976 100644
--- a/plugins/telit/mm-modem-helpers-telit.h
+++ b/plugins/telit/mm-modem-helpers-telit.h
@@ -26,34 +26,38 @@
MM_TELIT_MODEL_LM940,
MM_TELIT_MODEL_LM960,
MM_TELIT_MODEL_LN920,
+ MM_TELIT_MODEL_FN990,
} MMTelitModel;
+typedef struct {
+ gboolean modem_is_2g;
+ gboolean modem_is_3g;
+ gboolean modem_is_4g;
+ gboolean modem_alternate_3g_bands;
+ gboolean modem_has_hex_format_4g_bands;
+ gboolean modem_ext_4g_bands;
+} MMTelitBNDParseConfig;
+
+typedef enum {
+ MM_TELIT_SW_REV_CMP_INVALID,
+ MM_TELIT_SW_REV_CMP_UNSUPPORTED,
+ MM_TELIT_SW_REV_CMP_OLDER,
+ MM_TELIT_SW_REV_CMP_EQUAL,
+ MM_TELIT_SW_REV_CMP_NEWER,
+} MMTelitSwRevCmp;
+
/* #BND response parsers and request builder */
-GArray *mm_telit_parse_bnd_query_response (const gchar *response,
- gboolean modem_is_2g,
- gboolean modem_is_3g,
- gboolean modem_is_4g,
- gboolean modem_alternate_3g_bands,
- gboolean modem_has_hex_format_4g_bands,
- gboolean modem_ext_4g_bands,
- gpointer log_object,
- GError **error);
-GArray *mm_telit_parse_bnd_test_response (const gchar *response,
- gboolean modem_is_2g,
- gboolean modem_is_3g,
- gboolean modem_is_4g,
- gboolean modem_alternate_3g_bands,
- gboolean modem_has_hex_format_4g_bands,
- gboolean *modem_ext_4g_bands,
- gpointer log_object,
- GError **error);
-gchar *mm_telit_build_bnd_request (GArray *bands_array,
- gboolean modem_is_2g,
- gboolean modem_is_3g,
- gboolean modem_is_4g,
- gboolean modem_alternate_3g_bands,
- gboolean modem_ext_4g_bands,
- GError **error);
+GArray *mm_telit_parse_bnd_query_response (const gchar *response,
+ MMTelitBNDParseConfig *config,
+ gpointer log_object,
+ GError **error);
+GArray *mm_telit_parse_bnd_test_response (const gchar *response,
+ MMTelitBNDParseConfig *config,
+ gpointer log_object,
+ GError **error);
+gchar *mm_telit_build_bnd_request (GArray *bands_array,
+ MMTelitBNDParseConfig *config,
+ GError **error);
/* #QSS? response parser */
typedef enum { /*< underscore_name=mm_telit_qss_status >*/
@@ -80,4 +84,7 @@
MMTelitModel mm_telit_model_from_revision (const gchar *revision);
+MMTelitSwRevCmp mm_telit_software_revision_cmp (const gchar *reference,
+ const gchar *revision);
+
#endif /* MM_MODEM_HELPERS_TELIT_H */
diff --git a/plugins/telit/mm-shared-telit.c b/plugins/telit/mm-shared-telit.c
index e5f4413..09c122b 100644
--- a/plugins/telit/mm-shared-telit.c
+++ b/plugins/telit/mm-shared-telit.c
@@ -34,6 +34,8 @@
/*****************************************************************************/
/* Private data context */
+#define TELIT_LM940_EXT_LTE_BND_SW_REVISION "24.01.516"
+
#define PRIVATE_TAG "shared-telit-private-tag"
static GQuark private_quark;
@@ -58,10 +60,22 @@
}
static gboolean
-is_bnd_4g_format_hex (MMBaseModem *self,
- const gchar *revision)
+has_alternate_3g_bands (const gchar *revision)
{
- MMTelitModel model;
+ MMTelitModel model;
+
+ model = mm_telit_model_from_revision (revision);
+ return (model == MM_TELIT_MODEL_FN980 ||
+ model == MM_TELIT_MODEL_FN990 ||
+ model == MM_TELIT_MODEL_LM940 ||
+ model == MM_TELIT_MODEL_LM960 ||
+ model == MM_TELIT_MODEL_LN920);
+}
+
+static gboolean
+is_bnd_4g_format_hex (const gchar *revision)
+{
+ MMTelitModel model;
model = mm_telit_model_from_revision (revision);
@@ -72,22 +86,19 @@
model == MM_TELIT_MODEL_LN920);
}
-static void
-initialize_alternate_3g_band (MMSharedTelit *self,
- Private *priv)
+static gboolean
+has_extended_4g_bands (const gchar *revision)
{
- MMPort *primary;
- MMKernelDevice *port;
+ MMTelitModel model;
- primary = MM_PORT (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)));
- if (primary) {
- port = mm_port_peek_kernel_device (primary);
+ model = mm_telit_model_from_revision (revision);
+ if (model == MM_TELIT_MODEL_LM940)
+ return mm_telit_software_revision_cmp (revision, TELIT_LM940_EXT_LTE_BND_SW_REVISION) >= MM_TELIT_SW_REV_CMP_EQUAL;
- /* Lookup for the tag specifying that we're using the alternate 3G band mapping */
- priv->alternate_3g_bands = mm_kernel_device_get_global_property_as_boolean (port, "ID_MM_TELIT_BND_ALTERNATE");
- if (priv->alternate_3g_bands)
- mm_obj_dbg (self, "telit modem using alternate 3G band mask setup");
- }
+ return (model == MM_TELIT_MODEL_FN980 ||
+ model == MM_TELIT_MODEL_FN990 ||
+ model == MM_TELIT_MODEL_LM960 ||
+ model == MM_TELIT_MODEL_LN920);
}
static Private *
@@ -101,8 +112,6 @@
priv = g_object_get_qdata (G_OBJECT (self), private_quark);
if (!priv) {
priv = g_slice_new0 (Private);
- initialize_alternate_3g_band (self, priv);
- /* ext_4g_bands field is initialized inside #BND=? response handler */
if (MM_SHARED_TELIT_GET_INTERFACE (self)->peek_parent_modem_interface)
priv->iface_modem_parent = MM_SHARED_TELIT_GET_INTERFACE (self)->peek_parent_modem_interface (self);
@@ -132,6 +141,23 @@
priv = get_private (MM_SHARED_TELIT (self));
g_clear_pointer (&priv->software_package_version, g_free);
priv->software_package_version = g_strdup (revision);
+ priv->alternate_3g_bands = has_alternate_3g_bands (revision);
+ priv->ext_4g_bands = has_extended_4g_bands (revision);
+}
+
+void
+mm_shared_telit_get_bnd_parse_config (MMIfaceModem *self, MMTelitBNDParseConfig *config)
+{
+ Private *priv;
+
+ priv = get_private (MM_SHARED_TELIT (self));
+
+ config->modem_is_2g = mm_iface_modem_is_2g (self);
+ config->modem_is_3g = mm_iface_modem_is_3g (self);
+ config->modem_is_4g = mm_iface_modem_is_4g (self);
+ config->modem_alternate_3g_bands = priv->alternate_3g_bands;
+ config->modem_has_hex_format_4g_bands = is_bnd_4g_format_hex (priv->software_package_version);
+ config->modem_ext_4g_bands = priv->ext_4g_bands;
}
/*****************************************************************************/
@@ -241,16 +267,11 @@
g_task_return_error (task, error);
else {
GArray *bands;
+ MMTelitBNDParseConfig config;
- bands = mm_telit_parse_bnd_test_response (response,
- mm_iface_modem_is_2g (MM_IFACE_MODEM (self)),
- mm_iface_modem_is_3g (MM_IFACE_MODEM (self)),
- mm_iface_modem_is_4g (MM_IFACE_MODEM (self)),
- priv->alternate_3g_bands,
- is_bnd_4g_format_hex (self, priv->software_package_version),
- &priv->ext_4g_bands,
- self,
- &error);
+ mm_shared_telit_get_bnd_parse_config (MM_IFACE_MODEM (self), &config);
+
+ bands = mm_telit_parse_bnd_test_response (response, &config, self, &error);
if (!bands)
g_task_return_error (task, error);
else {
@@ -338,25 +359,17 @@
{
const gchar *response;
GError *error = NULL;
- Private *priv;
-
- priv = get_private (MM_SHARED_TELIT (self));
response = mm_base_modem_at_command_finish (self, res, &error);
if (!response)
g_task_return_error (task, error);
else {
GArray *bands;
+ MMTelitBNDParseConfig config;
- bands = mm_telit_parse_bnd_query_response (response,
- mm_iface_modem_is_2g (MM_IFACE_MODEM (self)),
- mm_iface_modem_is_3g (MM_IFACE_MODEM (self)),
- mm_iface_modem_is_4g (MM_IFACE_MODEM (self)),
- priv->alternate_3g_bands,
- is_bnd_4g_format_hex (self, priv->software_package_version),
- priv->ext_4g_bands,
- self,
- &error);
+ mm_shared_telit_get_bnd_parse_config (MM_IFACE_MODEM (self), &config);
+
+ bands = mm_telit_parse_bnd_query_response (response, &config, self, &error);
if (!bands)
g_task_return_error (task, error);
else
@@ -454,15 +467,16 @@
{
GError *error = NULL;
gchar *cmd;
- Private *priv;
GArray *bands_array;
-
- priv = get_private (MM_SHARED_TELIT (self));
+ MMTelitBNDParseConfig config;
bands_array = g_task_get_task_data (task);
g_assert (bands_array);
if (bands_array->len == 1 && g_array_index (bands_array, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
+ Private *priv;
+
+ priv = get_private (MM_SHARED_TELIT (self));
if (!priv->supported_bands) {
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Couldn't build ANY band settings: unknown supported bands");
@@ -472,13 +486,8 @@
bands_array = priv->supported_bands;
}
- cmd = mm_telit_build_bnd_request (bands_array,
- mm_iface_modem_is_2g (self),
- mm_iface_modem_is_3g (self),
- mm_iface_modem_is_4g (self),
- priv->alternate_3g_bands,
- priv->ext_4g_bands,
- &error);
+ mm_shared_telit_get_bnd_parse_config (self, &config);
+ cmd = mm_telit_build_bnd_request (bands_array, &config, &error);
if (!cmd) {
g_task_return_error (task, error);
g_object_unref (task);
@@ -783,3 +792,4 @@
return shared_telit_type;
}
+
diff --git a/plugins/telit/mm-shared-telit.h b/plugins/telit/mm-shared-telit.h
index 6dfcb63..bf093ea 100644
--- a/plugins/telit/mm-shared-telit.h
+++ b/plugins/telit/mm-shared-telit.h
@@ -25,6 +25,7 @@
#include "mm-broadband-modem.h"
#include "mm-iface-modem.h"
#include "mm-iface-modem-location.h"
+#include "mm-modem-helpers-telit.h"
#define MM_TYPE_SHARED_TELIT (mm_shared_telit_get_type ())
#define MM_SHARED_TELIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SHARED_TELIT, MMSharedTelit))
@@ -101,4 +102,6 @@
void mm_shared_telit_store_revision (MMSharedTelit *self,
const gchar *revision);
+void mm_shared_telit_get_bnd_parse_config (MMIfaceModem *self,
+ MMTelitBNDParseConfig *config);
#endif /* MM_SHARED_TELIT_H */
diff --git a/plugins/telit/tests/test-mm-modem-helpers-telit.c b/plugins/telit/tests/test-mm-modem-helpers-telit.c
index 1b96d08..e14ba6b 100644
--- a/plugins/telit/tests/test-mm-modem-helpers-telit.c
+++ b/plugins/telit/tests/test-mm-modem-helpers-telit.c
@@ -35,26 +35,21 @@
typedef struct {
const gchar *response;
- gboolean modem_is_2g;
- gboolean modem_is_3g;
- gboolean modem_is_4g;
- gboolean modem_alternate_3g_bands;
- gboolean modem_has_4g_bands_hex_format;
- gboolean modem_ext_4g_bands;
+ MMTelitBNDParseConfig config;
guint mm_bands_len;
MMModemBand mm_bands [MAX_BANDS_LIST_LEN];
} BndResponseTest;
static BndResponseTest supported_band_mapping_tests [] = {
{
- "#BND: (0-3)", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, 4,
+ "#BND: (0-3)", {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE}, 4,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_PCS,
MM_MODEM_BAND_G850 }
},
{
- "#BND: (0-3),(0,2,5,6)", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, 7,
+ "#BND: (0-3),(0,2,5,6)", {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE}, 7,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_PCS,
@@ -64,7 +59,7 @@
MM_MODEM_BAND_UTRAN_8 }
},
{
- "#BND: (0,3),(0,2,5,6)", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, 7,
+ "#BND: (0,3),(0,2,5,6)", {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE}, 7,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_PCS,
@@ -74,7 +69,7 @@
MM_MODEM_BAND_UTRAN_8 }
},
{
- "#BND: (0,2),(0,2,5,6)", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, 6,
+ "#BND: (0,2),(0,2,5,6)", {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE}, 6,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_G850,
@@ -83,7 +78,7 @@
MM_MODEM_BAND_UTRAN_8 }
},
{
- "#BND: (0,2),(0-4,5,6)", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, 7,
+ "#BND: (0,2),(0-4,5,6)", {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE}, 7,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_G850,
@@ -93,7 +88,7 @@
MM_MODEM_BAND_UTRAN_8 }
},
{
- "#BND: (0-3),(0,2,5,6),(1-1)", TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, 8,
+ "#BND: (0-3),(0,2,5,6),(1-1)", {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE}, 8,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_PCS,
@@ -104,7 +99,7 @@
MM_MODEM_BAND_EUTRAN_1 }
},
{
- "#BND: (0),(0),(1-3)", TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, 5,
+ "#BND: (0),(0),(1-3)", {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE}, 5,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_UTRAN_1,
@@ -112,13 +107,13 @@
MM_MODEM_BAND_EUTRAN_2 }
},
{
- "#BND: (0),(0),(1-3)", FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, 2,
+ "#BND: (0),(0),(1-3)", {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE}, 2,
{ MM_MODEM_BAND_EUTRAN_1,
MM_MODEM_BAND_EUTRAN_2 }
},
/* 3G alternate band settings: default */
{
- "#BND: (0),(0,2,5,6,12,25)", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 5,
+ "#BND: (0),(0,2,5,6,12,25)", {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE}, 5,
{ MM_MODEM_BAND_UTRAN_1,
MM_MODEM_BAND_UTRAN_5,
MM_MODEM_BAND_UTRAN_8,
@@ -127,7 +122,7 @@
},
/* 3G alternate band settings: alternate */
{
- "#BND: (0),(0,2,5,6,12,13)", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, 4,
+ "#BND: (0),(0,2,5,6,12,13)", {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE}, 4,
{ MM_MODEM_BAND_UTRAN_1,
MM_MODEM_BAND_UTRAN_3,
MM_MODEM_BAND_UTRAN_5,
@@ -137,7 +132,7 @@
* 168695967: 0xA0E189F: 0000 1010 0000 1110 0001 1000 1001 1111
*/
{
- "#BND: (0-5),(0),(1-168695967)", TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, 17,
+ "#BND: (0-5),(0),(1-168695967)", {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE}, 17,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_PCS,
@@ -158,7 +153,7 @@
},
/* 4G ext band settings: devices such as LN920 */
{
- "#BND: (0),(0),(1003100185A),(42)", FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, 13,
+ "#BND: (0),(0),(1003100185A),(42)", {FALSE, TRUE, TRUE, FALSE, TRUE, TRUE}, 13,
{ MM_MODEM_BAND_UTRAN_1,
MM_MODEM_BAND_EUTRAN_2,
MM_MODEM_BAND_EUTRAN_4,
@@ -175,7 +170,7 @@
},
/* 4G band in hex format: devices such as LE910C1-EUX */
{
- "#BND: (0),(0,5,6,13,15,23),(80800C5)", TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, 11,
+ "#BND: (0),(0,5,6,13,15,23),(80800C5)", {TRUE, TRUE, TRUE, FALSE, TRUE, FALSE}, 11,
{
MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
@@ -199,20 +194,13 @@
for (i = 0; i < G_N_ELEMENTS (supported_band_mapping_tests); i++) {
GError *error = NULL;
GArray *bands = NULL;
- gboolean modem_ext_4g_bands;
bands = mm_telit_parse_bnd_test_response (supported_band_mapping_tests[i].response,
- supported_band_mapping_tests[i].modem_is_2g,
- supported_band_mapping_tests[i].modem_is_3g,
- supported_band_mapping_tests[i].modem_is_4g,
- supported_band_mapping_tests[i].modem_alternate_3g_bands,
- supported_band_mapping_tests[i].modem_has_4g_bands_hex_format,
- &modem_ext_4g_bands,
+ &supported_band_mapping_tests[i].config,
NULL,
&error);
g_assert_no_error (error);
g_assert (bands);
- g_assert (supported_band_mapping_tests[i].modem_ext_4g_bands == modem_ext_4g_bands);
mm_test_helpers_compare_bands (bands,
supported_band_mapping_tests[i].mm_bands,
@@ -223,18 +211,18 @@
static BndResponseTest current_band_mapping_tests [] = {
{
- "#BND: 0", TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, 2,
+ "#BND: 0", {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE}, 2,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS }
},
{
- "#BND: 0,5", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, 3,
+ "#BND: 0,5", {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE}, 3,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_UTRAN_8 }
},
{
- "#BND: 1,3", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, 5,
+ "#BND: 1,3", {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE}, 5,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_PCS,
MM_MODEM_BAND_UTRAN_1,
@@ -242,38 +230,38 @@
MM_MODEM_BAND_UTRAN_5 }
},
{
- "#BND: 2,7", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, 3,
+ "#BND: 2,7", {TRUE, TRUE, FALSE, FALSE, FALSE, FALSE}, 3,
{ MM_MODEM_BAND_DCS,
MM_MODEM_BAND_G850,
MM_MODEM_BAND_UTRAN_4 }
},
{
- "#BND: 3,0,1", TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, 4,
+ "#BND: 3,0,1", {TRUE, TRUE, TRUE, FALSE, FALSE, FALSE}, 4,
{ MM_MODEM_BAND_PCS,
MM_MODEM_BAND_G850,
MM_MODEM_BAND_UTRAN_1,
MM_MODEM_BAND_EUTRAN_1 }
},
{
- "#BND: 0,0,3", TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, 4,
+ "#BND: 0,0,3", {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE}, 4,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_EUTRAN_1,
MM_MODEM_BAND_EUTRAN_2 }
},
{
- "#BND: 0,0,3", FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, 2,
+ "#BND: 0,0,3", {FALSE, FALSE, TRUE, FALSE, FALSE, FALSE}, 2,
{ MM_MODEM_BAND_EUTRAN_1,
MM_MODEM_BAND_EUTRAN_2 }
},
/* 3G alternate band settings: default */
{
- "#BND: 0,12", FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 1,
+ "#BND: 0,12", {FALSE, TRUE, FALSE, FALSE, FALSE, FALSE}, 1,
{ MM_MODEM_BAND_UTRAN_6 }
},
/* 3G alternate band settings: alternate */
{
- "#BND: 0,12", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, 4,
+ "#BND: 0,12", {FALSE, TRUE, FALSE, TRUE, FALSE, FALSE}, 4,
{ MM_MODEM_BAND_UTRAN_1,
MM_MODEM_BAND_UTRAN_3,
MM_MODEM_BAND_UTRAN_5,
@@ -283,7 +271,7 @@
* 168695967: 0xA0E189F: 0000 1010 0000 1110 0001 1000 1001 1111
*/
{
- "#BND: 5,0,168695967", TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, 17,
+ "#BND: 5,0,168695967", {TRUE, FALSE, TRUE, FALSE, FALSE, FALSE}, 17,
{ MM_MODEM_BAND_EGSM,
MM_MODEM_BAND_DCS,
MM_MODEM_BAND_PCS,
@@ -304,7 +292,7 @@
},
/* 4G ext band settings: devices such as LN920 */
{
- "#BND: 0,0,1003100185A,42", FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, 13,
+ "#BND: 0,0,1003100185A,42", {FALSE, TRUE, TRUE, FALSE, FALSE, TRUE}, 13,
{ MM_MODEM_BAND_UTRAN_1,
MM_MODEM_BAND_EUTRAN_2,
MM_MODEM_BAND_EUTRAN_4,
@@ -331,12 +319,7 @@
GArray *bands = NULL;
bands = mm_telit_parse_bnd_query_response (current_band_mapping_tests[i].response,
- current_band_mapping_tests[i].modem_is_2g,
- current_band_mapping_tests[i].modem_is_3g,
- current_band_mapping_tests[i].modem_is_4g,
- current_band_mapping_tests[i].modem_alternate_3g_bands,
- supported_band_mapping_tests[i].modem_has_4g_bands_hex_format,
- current_band_mapping_tests[i].modem_ext_4g_bands,
+ ¤t_band_mapping_tests[i].config,
NULL,
&error);
g_assert_no_error (error);
@@ -362,12 +345,15 @@
{
gchar *cmd;
GError *error = NULL;
+ MMTelitBNDParseConfig config = {
+ .modem_is_2g = modem_is_2g,
+ .modem_is_3g = modem_is_3g,
+ .modem_is_4g = modem_is_4g,
+ .modem_alternate_3g_bands = modem_alternate_3g_bands,
+ .modem_ext_4g_bands = modem_ext_4g_bands
+ };
- cmd = mm_telit_build_bnd_request (bands_array,
- modem_is_2g, modem_is_3g, modem_is_4g,
- modem_alternate_3g_bands,
- modem_ext_4g_bands,
- &error);
+ cmd = mm_telit_build_bnd_request (bands_array, &config, &error);
g_assert_no_error (error);
g_assert_cmpstr (cmd, ==, expected_cmd);
g_free (cmd);
@@ -386,11 +372,14 @@
{
gchar *cmd;
GError *error = NULL;
-
- cmd = mm_telit_build_bnd_request (bands_array,
- modem_is_2g, modem_is_3g, modem_is_4g,
- FALSE, FALSE,
- &error);
+ MMTelitBNDParseConfig config = {
+ .modem_is_2g = modem_is_2g,
+ .modem_is_3g = modem_is_3g,
+ .modem_is_4g = modem_is_4g,
+ .modem_alternate_3g_bands = FALSE,
+ .modem_ext_4g_bands = FALSE,
+ };
+ cmd = mm_telit_build_bnd_request (bands_array, &config, &error);
g_assert_error (error, MM_CORE_ERROR, (gint)expected_error);
g_assert (!cmd);
}
@@ -657,6 +646,35 @@
}
}
+static void
+test_telit_compare_software_revision_string (void)
+{
+ struct {
+ const char *revision_a;
+ const char *revision_b;
+ MMTelitSwRevCmp expected;
+ } tt [] = {
+ {"24.01.514", "24.01.514", MM_TELIT_SW_REV_CMP_EQUAL},
+ {"24.01.514", "24.01.513", MM_TELIT_SW_REV_CMP_NEWER},
+ {"24.01.513", "24.01.514", MM_TELIT_SW_REV_CMP_OLDER},
+ {"32.00.013", "24.01.514", MM_TELIT_SW_REV_CMP_INVALID},
+ {"32.00.014", "32.00.014", MM_TELIT_SW_REV_CMP_EQUAL},
+ {"32.00.014", "32.00.013", MM_TELIT_SW_REV_CMP_NEWER},
+ {"32.00.013", "32.00.014", MM_TELIT_SW_REV_CMP_OLDER},
+ {"38.00.000", "38.00.000", MM_TELIT_SW_REV_CMP_UNSUPPORTED},
+ /* LM9x0 Minor version (e.g. beta, test, alpha) value is currently
+ * ignored because not required by any implemented feature. */
+ {"24.01.516-B123", "24.01.516-B134", MM_TELIT_SW_REV_CMP_EQUAL},
+ };
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (tt); i++) {
+ g_assert_cmpint (tt[i].expected,
+ ==,
+ mm_telit_software_revision_cmp (tt[i].revision_a, tt[i].revision_b));
+ }
+}
+
/******************************************************************************/
int main (int argc, char **argv)
@@ -672,5 +690,6 @@
g_test_add_func ("/MM/telit/bands/current/set_bands/4g", test_telit_get_4g_bnd_flag);
g_test_add_func ("/MM/telit/qss/query", test_telit_parse_qss_query);
g_test_add_func ("/MM/telit/swpkv/parse_response", test_telit_parse_swpkgv_response);
+ g_test_add_func ("/MM/telit/revision/compare", test_telit_compare_software_revision_string);
return g_test_run ();
}
diff --git a/po/de.po b/po/de.po
index b626725..7877cb8 100644
--- a/po/de.po
+++ b/po/de.po
@@ -3,21 +3,22 @@
# This file is distributed under the same license as the Modem Manager package.
#
# Mario Blättermann <mario.blaettermann@gmail.com>, 2013.
+# Jürgen Benvenuti <gastornis@posteo.org>, 2022.
#
msgid ""
msgstr ""
"Project-Id-Version: ModemManager\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/mobile-broadband/"
"ModemManager/issues\n"
-"POT-Creation-Date: 2022-07-16 14:32+0200\n"
-"PO-Revision-Date: 2014-01-06 21:23+0100\n"
-"Last-Translator: Mario Blättermann <mario.blaettermann@gmail.com>\n"
-"Language-Team: German <debian-l10n-german@lists.debian.org>\n"
+"POT-Creation-Date: 2022-09-09 15:25+0000\n"
+"PO-Revision-Date: 2022-09-10 21:20+0200\n"
+"Last-Translator: Jürgen Benvenuti <gastornis@posteo.org>\n"
+"Language-Team: German <gnome-de@gnome.org>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.5.4\n"
+"X-Generator: Poedit 3.1.1\n"
#: data/org.freedesktop.ModemManager1.policy.in.in:13
msgid "Control the Modem Manager daemon"
@@ -54,7 +55,6 @@
msgstr "Textnachrichten senden, speichern, bearbeiten und löschen"
#: data/org.freedesktop.ModemManager1.policy.in.in:41
-#, fuzzy
msgid ""
"System policy prevents sending or manipulating this device's text messages."
msgstr ""
@@ -64,34 +64,32 @@
#: data/org.freedesktop.ModemManager1.policy.in.in:49
msgid "Accept incoming voice calls or start outgoing voice calls."
msgstr ""
+"Eingehende Sprachanrufe annehmen oder ausgehende Sprachanrufe beginnen."
#: data/org.freedesktop.ModemManager1.policy.in.in:50
-#, fuzzy
msgid "System policy prevents voice calls."
-msgstr "Die Systemrichtlinien verhindern die Steuerung von ModemManager."
+msgstr "Die Systemrichtlinien verhindern Sprachanrufe."
#: data/org.freedesktop.ModemManager1.policy.in.in:58
msgid "Query network time and timezone information"
-msgstr ""
+msgstr "Netzwerkzeit und Zeitzonen-Information abfragen"
#: data/org.freedesktop.ModemManager1.policy.in.in:59
-#, fuzzy
msgid "System policy prevents querying network time information."
msgstr ""
-"Die Systemrichtlinien verhindern die Abfrage der Netzwerkinformationen und -"
-"dienste."
+"Die Systemrichtlinien verhindern die Abfrage der Netzwerkzeit-Information."
#: data/org.freedesktop.ModemManager1.policy.in.in:67
msgid "Enable and view geographic location and positioning information"
msgstr ""
-"Informationen zum geografischen Standort und Positionierung aktivieren und "
-"anzeigen"
+"Informationen zum geografischen Standort und zur Positionierung aktivieren "
+"und anzeigen"
#: data/org.freedesktop.ModemManager1.policy.in.in:68
msgid ""
"System policy prevents enabling or viewing geographic location information."
msgstr ""
-"Die Systemrichtlinien verhindern das Aktivieren oder Ändern der "
+"Die Systemrichtlinien verhindern das Aktivieren oder Anzeigen der "
"Informationen zum geografischen Standort."
#: data/org.freedesktop.ModemManager1.policy.in.in:76
@@ -118,4 +116,4 @@
#: src/mm-sleep-monitor-systemd.c:125
msgid "ModemManager needs to reset devices"
-msgstr ""
+msgstr "ModemManager muss Geräte zurücksetzen"
diff --git a/src/mm-base-sim.c b/src/mm-base-sim.c
index be25e86..5fb83dc 100644
--- a/src/mm-base-sim.c
+++ b/src/mm-base-sim.c
@@ -12,7 +12,8 @@
*
* Copyright (C) 2008 - 2009 Novell, Inc.
* Copyright (C) 2009 - 2011 Red Hat, Inc.
- * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2011 - 2022 Aleksander Morgado <aleksander@aleksander.es>
+ * Copyright (C) 2011 - 2022 Google, Inc.
*/
#include <config.h>
@@ -2287,6 +2288,90 @@
}
/*****************************************************************************/
+/* GID1 and GID2 */
+
+static GByteArray *
+parse_gid (const gchar *response,
+ GError **error)
+{
+ guint sw1 = 0;
+ guint sw2 = 0;
+ g_autofree gchar *hex = NULL;
+
+ if (!mm_3gpp_parse_crsm_response (response, &sw1, &sw2, &hex, error))
+ return NULL;
+
+ if ((sw1 == 0x90 && sw2 == 0x00) ||
+ (sw1 == 0x91) ||
+ (sw1 == 0x92) ||
+ (sw1 == 0x9f)) {
+ guint8 *bin = NULL;
+ gsize binlen = 0;
+
+ /* Convert hex string to binary */
+ bin = mm_utils_hexstr2bin (hex, -1, &binlen, error);
+ if (!bin) {
+ g_prefix_error (error, "SIM returned malformed response '%s': ", hex);
+ return NULL;
+ }
+
+ /* return as bytearray */
+ return g_byte_array_new_take (bin, binlen);
+ }
+
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "SIM failed to handle CRSM request (sw1 %d sw2 %d)", sw1, sw2);
+ return NULL;
+}
+
+static GByteArray *
+common_load_gid_finish (MMBaseSim *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ g_autofree gchar *result = NULL;
+
+ result = g_task_propagate_pointer (G_TASK (res), error);
+ if (!result)
+ return NULL;
+
+ return parse_gid (result, error);
+}
+
+STR_REPLY_READY_FN (load_gid1)
+STR_REPLY_READY_FN (load_gid2)
+
+static void
+load_gid1 (MMBaseSim *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ /* READ BINARY of EFgid1 */
+ mm_base_modem_at_command (
+ self->priv->modem,
+ "+CRSM=176,28478,0,0,15",
+ 10,
+ FALSE,
+ (GAsyncReadyCallback)load_gid1_command_ready,
+ g_task_new (self, NULL, callback, user_data));
+}
+
+static void
+load_gid2 (MMBaseSim *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ /* READ BINARY of EFgid2 */
+ mm_base_modem_at_command (
+ self->priv->modem,
+ "+CRSM=176,28479,0,0,15",
+ 10,
+ FALSE,
+ (GAsyncReadyCallback)load_gid2_command_ready,
+ g_task_new (self, NULL, callback, user_data));
+}
+
+/*****************************************************************************/
MMBaseSim *
mm_base_sim_new_initialized (MMBaseModem *modem,
@@ -3080,6 +3165,10 @@
klass->load_emergency_numbers_finish = load_emergency_numbers_finish;
klass->load_preferred_networks = load_preferred_networks;
klass->load_preferred_networks_finish = load_preferred_networks_finish;
+ klass->load_gid1 = load_gid1;
+ klass->load_gid1_finish = common_load_gid_finish;
+ klass->load_gid2 = load_gid2;
+ klass->load_gid2_finish = common_load_gid_finish;
klass->set_preferred_networks = set_preferred_networks;
klass->set_preferred_networks_finish = set_preferred_networks_finish;
klass->send_pin = send_pin;
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c
index 33ba2c5..644aaee 100644
--- a/src/mm-broadband-modem-mbim.c
+++ b/src/mm-broadband-modem-mbim.c
@@ -2945,7 +2945,6 @@
QMI_SERVICE_PDS,
QMI_SERVICE_LOC,
QMI_SERVICE_PDC,
- QMI_SERVICE_FOX,
QMI_SERVICE_UIM,
};
@@ -8235,9 +8234,18 @@
static gboolean
sar_enable_finish (MMIfaceModemSar *self,
GAsyncResult *res,
+ guint *out_sar_power_level,
GError **error)
{
- return g_task_propagate_boolean (G_TASK (res), error);
+ guint level;
+
+ if (!g_task_propagate_boolean (G_TASK (res), error))
+ return FALSE;
+
+ level = GPOINTER_TO_UINT (g_task_get_task_data (G_TASK (res)));
+ if (out_sar_power_level)
+ *out_sar_power_level = level;
+ return TRUE;
}
static void
@@ -8287,6 +8295,8 @@
#endif
config_state->backoff_index = mm_iface_modem_sar_get_power_level (_self);
+ g_task_set_task_data (task, GUINT_TO_POINTER (config_state->backoff_index), NULL);
+
message = mbim_message_ms_sar_config_set_new (MBIM_SAR_CONTROL_MODE_OS,
enable ? MBIM_SAR_BACKOFF_STATE_ENABLED : MBIM_SAR_BACKOFF_STATE_DISABLED,
1, (const MbimSarConfigState **)&config_state, NULL);
@@ -8342,17 +8352,6 @@
if (!peek_device (self, &device, callback, user_data))
return;
- if (!mm_iface_modem_get_sar_state (_self)) {
- g_task_report_new_error (self,
- callback,
- user_data,
- sar_set_power_level,
- MM_CORE_ERROR,
- MM_CORE_ERROR_WRONG_STATE,
- "Couldn't set power level of SAR, because the SAR is disabled");
- return;
- }
-
/*
* the value 0xFFFFFFFF means all antennas
* the backoff index set to the input power level
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index 0eb03b3..6281c16 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -62,8 +62,8 @@
static void iface_modem_location_init (MMIfaceModemLocation *iface);
static void iface_modem_oma_init (MMIfaceModemOma *iface);
static void iface_modem_firmware_init (MMIfaceModemFirmware *iface);
-static void iface_modem_signal_init (MMIfaceModemSignal *iface);
static void iface_modem_sar_init (MMIfaceModemSar *iface);
+static void iface_modem_signal_init (MMIfaceModemSignal *iface);
static void shared_qmi_init (MMSharedQmi *iface);
static MMIfaceModemLocation *iface_modem_location_parent;
@@ -79,8 +79,8 @@
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SIGNAL, iface_modem_signal_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SAR, iface_modem_sar_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SIGNAL, iface_modem_signal_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_OMA, iface_modem_oma_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_FIRMWARE, iface_modem_firmware_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_QMI, shared_qmi_init))
@@ -183,9 +183,6 @@
gboolean profile_manager_unsolicited_events_setup;
guint refresh_indication_id;
- /* SAR Operation */
- gboolean is_sar_supported;
-
/* PS registration helpers when using NAS System Info and DSD
* (not applicable when using NAS Serving System) */
gboolean dsd_supported;
@@ -8302,24 +8299,26 @@
/*****************************************************************************/
-
/* Check support (SAR interface) */
+/* SAR level 0 is assumed DISABLED, and any other level is assumed ENABLED */
+#define QMI_SAR_ENABLE_POWER_INDEX QMI_SAR_RF_STATE_1
+#define QMI_SAR_DISABLED_POWER_INDEX QMI_SAR_RF_STATE_0
+
static gboolean
-sar_check_support_finish (MMIfaceModemSar *self,
- GAsyncResult *res,
- GError **error)
+sar_check_support_finish (MMIfaceModemSar *self,
+ GAsyncResult *res,
+ GError **error)
{
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
-sar_check_support (MMIfaceModemSar *_self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+sar_check_support (MMIfaceModemSar *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
- GTask *task;
+ GTask *task;
task = g_task_new (self, NULL, callback, user_data);
@@ -8328,15 +8327,19 @@
QMI_SERVICE_SAR,
MM_PORT_QMI_FLAG_DEFAULT,
NULL)) {
- self->priv->is_sar_supported = FALSE;
- } else
- self->priv->is_sar_supported = TRUE;
+ mm_obj_dbg (self, "SAR capabilities not supported");
+ g_task_return_boolean (task, FALSE);
+ } else {
+ mm_obj_dbg (self, "SAR capabilities supported");
+ g_task_return_boolean (task, TRUE);
+ }
- mm_obj_dbg (self, "SAR capabilities %s", self->priv->is_sar_supported ? "supported" : "not supported");
- g_task_return_boolean (task, self->priv->is_sar_supported);
g_object_unref (task);
}
+/*****************************************************************************/
+/* Load SAR state (SAR interface) */
+
static gboolean
sar_load_state_finish (MMIfaceModemSar *self,
GAsyncResult *res,
@@ -8358,33 +8361,69 @@
}
static void
-sar_load_state (MMIfaceModemSar *_self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+sar_load_state_ready (QmiClientSar *client,
+ GAsyncResult *res,
+ GTask *task)
{
- MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
- GTask *task;
+ g_autoptr(QmiMessageSarRfGetStateOutput) output = NULL;
+ GError *error = NULL;
+ QmiSarRfState rf_state;
- task = g_task_new (self, NULL, callback, user_data);
+ output = qmi_client_sar_rf_get_state_finish (client, res, &error);
+ if (output &&
+ qmi_message_sar_rf_get_state_output_get_result (output, &error) &&
+ qmi_message_sar_rf_get_state_output_get_state (output, &rf_state, &error)) {
+ if (rf_state == QMI_SAR_DISABLED_POWER_INDEX)
+ g_task_return_boolean (task, FALSE);
+ else
+ g_task_return_boolean (task, TRUE);
+ } else
+ g_task_return_error (task, error);
- mm_obj_dbg (self, "SAR enabled %s", self->priv->is_sar_supported ? "yes" : "no");
- g_task_return_boolean (task, self->priv->is_sar_supported);
g_object_unref (task);
}
+static void
+sar_load_state (MMIfaceModemSar *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ QmiClient *client = NULL;
+
+ if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
+ QMI_SERVICE_SAR, &client,
+ callback, user_data))
+ return;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ qmi_client_sar_rf_get_state (
+ QMI_CLIENT_SAR (client),
+ NULL,
+ 5,
+ NULL,
+ (GAsyncReadyCallback)sar_load_state_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Load SAR power level (SAR interface) */
+
static gboolean
-sar_load_power_level_finish (MMIfaceModemSar *self,
- GAsyncResult *res,
- guint *out_power_level,
+sar_load_power_level_finish (MMIfaceModemSar *self,
+ GAsyncResult *res,
+ guint *out_power_level,
GError **error)
{
gssize result;
- result = g_task_propagate_int(G_TASK (res), error);
+ result = g_task_propagate_int (G_TASK (res), error);
if (result < 0)
return FALSE;
- *out_power_level = (guint) result;
+ if (out_power_level)
+ *out_power_level = (guint) result;
return TRUE;
}
@@ -8393,29 +8432,28 @@
GAsyncResult *res,
GTask *task)
{
- g_autoptr(QmiMessageSarRfGetStateOutput) output = NULL;
- GError *error = NULL;
- QmiSarRfState rf_state;
+ g_autoptr(QmiMessageSarRfGetStateOutput) output = NULL;
+ GError *error = NULL;
+ QmiSarRfState rf_state;
output = qmi_client_sar_rf_get_state_finish (client, res, &error);
if (output &&
qmi_message_sar_rf_get_state_output_get_result (output, &error) &&
- qmi_message_sar_rf_get_state_output_get_state (output, &rf_state, &error)) {
- g_task_return_int (task, rf_state);
- } else
+ qmi_message_sar_rf_get_state_output_get_state (output, &rf_state, &error))
+ g_task_return_int (task, rf_state);
+ else
g_task_return_error (task, error);
g_object_unref (task);
}
static void
-sar_load_power_level (MMIfaceModemSar *_self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+sar_load_power_level (MMIfaceModemSar *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
- GTask *task;
- QmiClient *client = NULL;
+ GTask *task;
+ QmiClient *client = NULL;
if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
QMI_SERVICE_SAR, &client,
@@ -8433,12 +8471,24 @@
task);
}
+/*****************************************************************************/
+/* Enable/Disable SAR (SAR interface) */
+
static gboolean
sar_enable_finish (MMIfaceModemSar *self,
GAsyncResult *res,
+ guint *out_sar_power_level,
GError **error)
{
- return g_task_propagate_boolean (G_TASK (res), error);
+ QmiSarRfState level;
+
+ if (!g_task_propagate_boolean (G_TASK (res), error))
+ return FALSE;
+
+ level = GPOINTER_TO_UINT (g_task_get_task_data (G_TASK (res)));
+ if (out_sar_power_level)
+ *out_sar_power_level = level;
+ return TRUE;
}
static void
@@ -8446,31 +8496,28 @@
GAsyncResult *res,
GTask *task)
{
- g_autoptr(QmiMessageSarRfSetStateOutput) output = NULL;
- GError *error = NULL;
+ g_autoptr(QmiMessageSarRfSetStateOutput) output = NULL;
+ GError *error = NULL;
output = qmi_client_sar_rf_set_state_finish (client, res, &error);
- if (output &&
- qmi_message_sar_rf_set_state_output_get_result (output, &error)) {
- g_task_return_boolean (task, TRUE);
- } else
+ if (output && qmi_message_sar_rf_set_state_output_get_result (output, &error))
+ g_task_return_boolean (task, TRUE);
+ else
g_task_return_error (task, error);
g_object_unref (task);
}
-
static void
-sar_enable (MMIfaceModemSar *_self,
- gboolean enable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+sar_enable (MMIfaceModemSar *self,
+ gboolean enable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
- g_autoptr(QmiMessageSarRfSetStateInput) input = NULL;
- GTask *task;
- QmiClient *client = NULL;
- GError *error = NULL;
+ g_autoptr(QmiMessageSarRfSetStateInput) input = NULL;
+ GTask *task;
+ QmiClient *client = NULL;
+ QmiSarRfState level;
if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
QMI_SERVICE_SAR, &client,
@@ -8479,10 +8526,18 @@
task = g_task_new (self, NULL, callback, user_data);
input = qmi_message_sar_rf_set_state_input_new ();
- qmi_message_sar_rf_set_state_input_set_state (
- input,
- 0,
- &error);
+
+ /* When enabling, try to set the last valid known power level used, instead
+ * of defaulting to level 1 */
+ if (enable) {
+ level = mm_iface_modem_sar_get_power_level (self);
+ if (level == QMI_SAR_DISABLED_POWER_INDEX)
+ level = QMI_SAR_ENABLE_POWER_INDEX;
+ } else
+ level = QMI_SAR_DISABLED_POWER_INDEX;
+
+ qmi_message_sar_rf_set_state_input_set_state (input, level, NULL);
+ g_task_set_task_data (task, GUINT_TO_POINTER (level), NULL);
qmi_client_sar_rf_set_state (
QMI_CLIENT_SAR (client),
@@ -8493,6 +8548,8 @@
task);
}
+/*****************************************************************************/
+/* Set SAR power level (SAR interface) */
static gboolean
sar_set_power_level_finish (MMIfaceModemSar *self,
@@ -8511,27 +8568,23 @@
GError *error = NULL;
output = qmi_client_sar_rf_set_state_finish (client, res, &error);
- if (output &&
- qmi_message_sar_rf_set_state_output_get_result (output, &error)) {
- g_task_return_boolean (task, TRUE);
- } else
+ if (output && qmi_message_sar_rf_set_state_output_get_result (output, &error))
+ g_task_return_boolean (task, TRUE);
+ else
g_task_return_error (task, error);
g_object_unref (task);
}
-
static void
-sar_set_power_level (MMIfaceModemSar *_self,
+sar_set_power_level (MMIfaceModemSar *self,
guint power_level,
GAsyncReadyCallback callback,
gpointer user_data)
{
- MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
- g_autoptr(QmiMessageSarRfSetStateInput) input = NULL;
- GTask *task;
- QmiClient *client = NULL;
- GError *error = NULL;
+ g_autoptr(QmiMessageSarRfSetStateInput) input = NULL;
+ GTask *task;
+ QmiClient *client = NULL;
if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self),
QMI_SERVICE_SAR, &client,
@@ -8539,11 +8592,17 @@
return;
task = g_task_new (self, NULL, callback, user_data);
+
+ if (power_level == QMI_SAR_DISABLED_POWER_INDEX) {
+ g_task_return_new_error (task,
+ MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "Unsupported power level");
+ g_object_unref (task);
+ return;
+ }
+
input = qmi_message_sar_rf_set_state_input_new ();
- qmi_message_sar_rf_set_state_input_set_state (
- input,
- power_level,
- &error);
+ qmi_message_sar_rf_set_state_input_set_state (input, power_level, NULL);
qmi_client_sar_rf_set_state (
QMI_CLIENT_SAR (client),
input,
@@ -13109,8 +13168,8 @@
QMI_SERVICE_LOC,
QMI_SERVICE_PDC,
QMI_SERVICE_VOICE,
- QMI_SERVICE_SAR,
QMI_SERVICE_DSD,
+ QMI_SERVICE_SAR,
};
typedef struct {
@@ -13825,15 +13884,6 @@
}
static void
-iface_modem_signal_init (MMIfaceModemSignal *iface)
-{
- iface->check_support = signal_check_support;
- iface->check_support_finish = signal_check_support_finish;
- iface->load_values = signal_load_values;
- iface->load_values_finish = signal_load_values_finish;
-}
-
-static void
iface_modem_sar_init (MMIfaceModemSar *iface)
{
iface->check_support = sar_check_support;
@@ -13849,6 +13899,15 @@
}
static void
+iface_modem_signal_init (MMIfaceModemSignal *iface)
+{
+ iface->check_support = signal_check_support;
+ iface->check_support_finish = signal_check_support_finish;
+ iface->load_values = signal_load_values;
+ iface->load_values_finish = signal_load_values_finish;
+}
+
+static void
iface_modem_oma_init (MMIfaceModemOma *iface)
{
iface->check_support = oma_check_support;
diff --git a/src/mm-iface-modem-sar.c b/src/mm-iface-modem-sar.c
index 2e92af1..63105d6 100644
--- a/src/mm-iface-modem-sar.c
+++ b/src/mm-iface-modem-sar.c
@@ -35,24 +35,6 @@
{
}
-gboolean
-mm_iface_modem_get_sar_state (MMIfaceModemSar *self)
-{
- MmGdbusModemSar *skeleton = NULL;
- gboolean state;
-
- g_object_get (self,
- MM_IFACE_MODEM_SAR_DBUS_SKELETON, &skeleton,
- NULL);
-
- if (!skeleton)
- return FALSE;
-
- state = mm_gdbus_modem_sar_get_state (skeleton);
- g_object_unref (skeleton);
- return state;
-}
-
guint
mm_iface_modem_sar_get_power_level (MMIfaceModemSar *self)
{
@@ -96,12 +78,15 @@
HandleEnableContext *ctx)
{
GError *error = NULL;
+ guint power_level = 0;
- if (!MM_IFACE_MODEM_SAR_GET_INTERFACE (ctx->self)->enable_finish (self, res, &error))
+ if (!MM_IFACE_MODEM_SAR_GET_INTERFACE (ctx->self)->enable_finish (self, res, &power_level, &error))
g_dbus_method_invocation_take_error (ctx->invocation, error);
else {
/* Update current features in the interface */
mm_gdbus_modem_sar_set_state (ctx->skeleton, ctx->enable);
+ if (ctx->enable)
+ mm_gdbus_modem_sar_set_power_level (ctx->skeleton, power_level);
mm_gdbus_modem_sar_complete_enable (ctx->skeleton, ctx->invocation);
}
@@ -132,6 +117,12 @@
return;
}
+ if (mm_gdbus_modem_sar_get_state (ctx->skeleton) == ctx->enable) {
+ mm_gdbus_modem_sar_complete_enable (ctx->skeleton, ctx->invocation);
+ handle_enable_context_free (ctx);
+ return;
+ }
+
mm_obj_dbg (self, "%s SAR...", ctx->enable ? "Enabling" : "Disabling");
MM_IFACE_MODEM_SAR_GET_INTERFACE (ctx->self)->enable (ctx->self,
@@ -188,7 +179,7 @@
{
GError *error = NULL;
- if (!MM_IFACE_MODEM_SAR_GET_INTERFACE (ctx->self)->enable_finish (self, res, &error)) {
+ if (!MM_IFACE_MODEM_SAR_GET_INTERFACE (ctx->self)->set_power_level_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
} else {
mm_gdbus_modem_sar_set_power_level (ctx->skeleton, ctx->power_level);
@@ -222,6 +213,21 @@
return;
}
+ if (!mm_gdbus_modem_sar_get_state (ctx->skeleton)) {
+ g_dbus_method_invocation_return_error (ctx->invocation,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_WRONG_STATE,
+ "Cannot set SAR power level: SAR is disabled");
+ handle_set_power_level_context_free (ctx);
+ return;
+ }
+
+ if (mm_gdbus_modem_sar_get_power_level (ctx->skeleton) == ctx->power_level) {
+ mm_gdbus_modem_sar_complete_set_power_level (ctx->skeleton, ctx->invocation);
+ handle_set_power_level_context_free (ctx);
+ return;
+ }
+
mm_obj_dbg (self, "Set SAR power level to: '%d'", ctx->power_level);
MM_IFACE_MODEM_SAR_GET_INTERFACE (ctx->self)->set_power_level (
ctx->self,
diff --git a/src/mm-iface-modem-sar.h b/src/mm-iface-modem-sar.h
index 2dba700..e6518f1 100644
--- a/src/mm-iface-modem-sar.h
+++ b/src/mm-iface-modem-sar.h
@@ -48,6 +48,7 @@
gpointer user_data);
gboolean (* enable_finish) (MMIfaceModemSar *self,
GAsyncResult *res,
+ guint *out_sar_power_level,
GError **error);
/* Get SAR state (async) */
void (* load_state) (MMIfaceModemSar *self,
@@ -96,7 +97,6 @@
void mm_iface_modem_sar_bind_simple_status (MMIfaceModemSar*self,
MMSimpleStatus *status);
-gboolean mm_iface_modem_get_sar_state (MMIfaceModemSar *self);
-guint mm_iface_modem_sar_get_power_level (MMIfaceModemSar *self);
+guint mm_iface_modem_sar_get_power_level (MMIfaceModemSar *self);
#endif /* MM_IFACE_MODEM_SAR_H */
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c
index c9d1619..911c139 100644
--- a/src/mm-iface-modem.c
+++ b/src/mm-iface-modem.c
@@ -3758,16 +3758,16 @@
g_error_matches (error,
MM_MOBILE_EQUIPMENT_ERROR,
MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
- /* SIM errors are only critical in 3GPP-only devices */
- if (!mm_iface_modem_is_cdma (self)) {
+ /* SIM errors are only critical in 3GPP-capable devices */
+ if (mm_iface_modem_is_3gpp (self)) {
ctx->saved_error = error;
ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST;
update_lock_info_context_step (task);
return;
}
- /* For mixed 3GPP+3GPP2 devices, skip SIM errors */
- mm_obj_dbg (self, "skipping SIM error in 3GPP2-capable device, assuming no lock is needed");
+ /* For non 3GPP-capable devices, skip SIM errors */
+ mm_obj_dbg (self, "skipping SIM error in non 3GPP-capable device, assuming no lock is needed");
g_error_free (error);
ctx->lock = MM_MODEM_LOCK_NONE;
} else {
@@ -4778,48 +4778,6 @@
}
static void
-current_capabilities_internal_load_unlock_required_ready (MMIfaceModem *self,
- GAsyncResult *res,
- GTask *task)
-{
- InitializationContext *ctx;
- GError *error = NULL;
-
- ctx = g_task_get_task_data (task);
-
- internal_load_unlock_required_finish (self, res, &error);
- if (error) {
- /* These SIM errors indicate that there is NO valid SIM available. So,
- * remove all 3GPP caps from the current capabilities */
- if (g_error_matches (error,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) ||
- g_error_matches (error,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) ||
- g_error_matches (error,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) {
- MMModemCapability caps;
-
- mm_obj_dbg (self, "multimode device without SIM, no 3GPP capabilities");
- caps = mm_gdbus_modem_get_current_capabilities (ctx->skeleton);
- caps &= ~MM_MODEM_CAPABILITY_3GPP;
-
- /* CDMA-EVDO must still be around */
- g_assert (caps & MM_MODEM_CAPABILITY_CDMA_EVDO);
- mm_gdbus_modem_set_current_capabilities (ctx->skeleton, caps);
- }
-
- g_error_free (error);
- }
-
- /* Keep on */
- ctx->step++;
- interface_initialization_step (task);
-}
-
-static void
load_current_capabilities_ready (MMIfaceModem *self,
GAsyncResult *res,
GTask *task)
@@ -4871,22 +4829,8 @@
NULL);
}
- /* Update current caps right away, even if we may fix them during the
- * multimode device check. No big deal in updating them twice, as we're not
- * exposed in DBus yet. */
mm_gdbus_modem_set_current_capabilities (ctx->skeleton, caps);
- /* If the device is a multimode device (3GPP+3GPP2) check whether we have a
- * SIM or not. */
- if ((caps & MM_MODEM_CAPABILITY_CDMA_EVDO) && (caps & MM_MODEM_CAPABILITY_3GPP)) {
- mm_obj_dbg (self, "checking if multimode device has a SIM...");
- internal_load_unlock_required (
- self,
- (GAsyncReadyCallback)current_capabilities_internal_load_unlock_required_ready,
- task);
- return;
- }
-
ctx->step++;
interface_initialization_step (task);
}
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index b339812..93d9fda 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -460,7 +460,7 @@
/* Example:
* <CR><LF>RING<CR><LF>
*/
- return g_regex_new ("\\r\\nRING\\r\\n",
+ return g_regex_new ("\\r\\nRING(?:\\r)?\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE,
0,
NULL);
diff --git a/src/mm-sim-mbim.c b/src/mm-sim-mbim.c
index 10f29f0..68c35dc 100644
--- a/src/mm-sim-mbim.c
+++ b/src/mm-sim-mbim.c
@@ -961,7 +961,7 @@
}
static GByteArray *
-common_read_binary_finish (MMBaseSim *self,
+common_read_binary_finish (MMSimMbim *self,
GAsyncResult *res,
GError **error)
{
@@ -1076,14 +1076,56 @@
}
/*****************************************************************************/
-/* Read GID1 and GID2 */
+/* Read GID1 */
static GByteArray *
load_gid1_finish (MMBaseSim *self,
GAsyncResult *res,
GError **error)
{
- return common_read_binary_finish (self, res, error);
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static void
+parent_load_gid1_ready (MMBaseSim *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(GError) error = NULL;
+ GByteArray *value;
+
+ value = MM_BASE_SIM_CLASS(mm_sim_mbim_parent_class)->load_gid1_finish (self, res, &error);
+ if (value) {
+ g_task_return_pointer (task, value, (GDestroyNotify)g_byte_array_unref);
+ } else {
+ mm_obj_dbg (self, "failed reading GID1 using AT: %s", error->message);
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Failed reading GID1 from SIM card");
+ }
+
+ g_object_unref (task);
+}
+
+static void
+common_read_binary_gid1_ready (MMSimMbim *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(GError) error = NULL;
+ GByteArray *value;
+
+ value = common_read_binary_finish (self, res, &error);
+ if (value) {
+ g_task_return_pointer (task, value, (GDestroyNotify)g_byte_array_unref);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Fallback to parent implementation if possible */
+ mm_obj_dbg (self, "failed reading GID1 using MBIM: %s", error->message);
+ MM_BASE_SIM_CLASS(mm_sim_mbim_parent_class)->load_gid1 (MM_BASE_SIM (self),
+ (GAsyncReadyCallback)parent_load_gid1_ready,
+ task);
}
static void
@@ -1091,17 +1133,69 @@
GAsyncReadyCallback callback,
gpointer user_data)
{
- const guint8 file_path[] = { 0x7F, 0xFF, 0x6F, 0x3E };
+ GTask *task;
+ const guint8 file_path[] = { 0x7F, 0xFF, 0x6F, 0x3E };
- common_read_binary (MM_SIM_MBIM (self), file_path, G_N_ELEMENTS (file_path), callback, user_data);
+ task = g_task_new (self, NULL, callback, user_data);
+
+ common_read_binary (MM_SIM_MBIM (self),
+ file_path,
+ G_N_ELEMENTS (file_path),
+ (GAsyncReadyCallback)common_read_binary_gid1_ready,
+ task);
}
+/*****************************************************************************/
+/* Read GID2 */
+
static GByteArray *
load_gid2_finish (MMBaseSim *self,
GAsyncResult *res,
GError **error)
{
- return common_read_binary_finish (self, res, error);
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static void
+parent_load_gid2_ready (MMBaseSim *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(GError) error = NULL;
+ GByteArray *value;
+
+ value = MM_BASE_SIM_CLASS(mm_sim_mbim_parent_class)->load_gid2_finish (self, res, &error);
+ if (value) {
+ g_task_return_pointer (task, value, (GDestroyNotify)g_byte_array_unref);
+ } else {
+ mm_obj_dbg (self, "failed reading GID2 using AT: %s", error->message);
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Failed reading GID2 from SIM card");
+ }
+
+ g_object_unref (task);
+}
+
+static void
+common_read_binary_gid2_ready (MMSimMbim *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(GError) error = NULL;
+ GByteArray *value;
+
+ value = common_read_binary_finish (self, res, &error);
+ if (value) {
+ g_task_return_pointer (task, value, (GDestroyNotify)g_byte_array_unref);
+ g_object_unref (task);
+ return;
+ }
+
+ /* Fallback to parent implementation if possible */
+ mm_obj_dbg (self, "failed reading GID2 using MBIM: %s", error->message);
+ MM_BASE_SIM_CLASS(mm_sim_mbim_parent_class)->load_gid2 (MM_BASE_SIM (self),
+ (GAsyncReadyCallback)parent_load_gid2_ready,
+ task);
}
static void
@@ -1109,9 +1203,16 @@
GAsyncReadyCallback callback,
gpointer user_data)
{
- const guint8 file_path[] = { 0x7F, 0xFF, 0x6F, 0x3F };
+ GTask *task;
+ const guint8 file_path[] = { 0x7F, 0xFF, 0x6F, 0x3F };
- common_read_binary (MM_SIM_MBIM (self), file_path, G_N_ELEMENTS (file_path), callback, user_data);
+ task = g_task_new (self, NULL, callback, user_data);
+
+ common_read_binary (MM_SIM_MBIM (self),
+ file_path,
+ G_N_ELEMENTS (file_path),
+ (GAsyncReadyCallback)common_read_binary_gid2_ready,
+ task);
}
/*****************************************************************************/
diff --git a/src/mm-sms-part-3gpp.c b/src/mm-sms-part-3gpp.c
index 07d3ef8..8a36cab 100644
--- a/src/mm-sms-part-3gpp.c
+++ b/src/mm-sms-part-3gpp.c
@@ -422,23 +422,22 @@
PDU_SIZE_CHECK (1, "cannot read SMSC address length");
smsc_addr_size_bytes = pdu[offset++];
if (smsc_addr_size_bytes > 0) {
- PDU_SIZE_CHECK (offset + smsc_addr_size_bytes, "cannot read SMSC address");
- /* SMSC may not be given in DELIVER PDUs */
- address = sms_decode_address (&pdu[1], 2 * (smsc_addr_size_bytes - 1), error);
- if (!address) {
- g_prefix_error (error, "Couldn't read SMSC address: ");
- mm_sms_part_free (sms_part);
- return NULL;
- }
- mm_sms_part_take_smsc (sms_part, g_steal_pointer (&address));
- mm_obj_dbg (log_object, " SMSC address parsed: '%s'", mm_sms_part_get_smsc (sms_part));
- offset += smsc_addr_size_bytes;
+ PDU_SIZE_CHECK (offset + smsc_addr_size_bytes, "cannot read SMSC address");
+ /* SMSC may not be given in DELIVER PDUs */
+ address = sms_decode_address (&pdu[1], 2 * (smsc_addr_size_bytes - 1), error);
+ if (!address) {
+ g_prefix_error (error, "Couldn't read SMSC address: ");
+ mm_sms_part_free (sms_part);
+ return NULL;
+ }
+ mm_sms_part_take_smsc (sms_part, g_steal_pointer (&address));
+ mm_obj_dbg (log_object, " SMSC address parsed: '%s'", mm_sms_part_get_smsc (sms_part));
+ offset += smsc_addr_size_bytes;
} else
- mm_obj_dbg (log_object, " no SMSC address given");
+ mm_obj_dbg (log_object, " no SMSC address given");
} else
mm_obj_dbg (log_object, " This is a transfer-route message");
-
/* ---------------------------------------------------------------------- */
/* TP-MTI (1 byte) */
PDU_SIZE_CHECK (offset + 1, "cannot read TP-MTI");
@@ -492,7 +491,6 @@
offset++;
}
-
/* ---------------------------------------------------------------------- */
/* TP-DA or TP-OA or TP-RA
* First byte represents the number of DIGITS in the number.
@@ -519,6 +517,7 @@
if (pdu_type == SMS_TP_MTI_SMS_DELIVER) {
gchar *str = NULL;
+
PDU_SIZE_CHECK (offset + 9,
"cannot read PID/DCS/Timestamp"); /* 1+1+7=9 */
@@ -534,8 +533,7 @@
mm_sms_part_free (sms_part);
return NULL;
}
- mm_sms_part_take_timestamp (sms_part,
- str);
+ mm_sms_part_take_timestamp (sms_part, str);
offset += 7;
tp_user_data_len_offset = offset;
@@ -577,9 +575,9 @@
}
tp_user_data_len_offset = offset;
- }
- else if (pdu_type == SMS_TP_MTI_SMS_STATUS_REPORT) {
+ } else if (pdu_type == SMS_TP_MTI_SMS_STATUS_REPORT) {
gchar *str = NULL;
+
/* We have 2 timestamps in status report PDUs:
* first, the timestamp for when the PDU was received in the SMSC
* second, the timestamp for when the PDU was forwarded by the SMSC