Compare commits

..
Author SHA1 Message Date
81046da179 Update README.md
Some checks failed
image / image (push) Has been cancelled
2026-10-16 21:23:38 +00:00
bbad150335
aports: our own packages are GPL-3.0-only, as the repository is
Some checks failed
image / image (push) Has been cancelled
fp6-charging-mode, fp6-device-tweaks, fp6-vendor-blobs and catcrafts-fp6-repo
declared license="MIT"; their contents are ours and GPL-3.0-only, as LICENSE
says since c9bac2c. No pkgrel bump: the field reaches the published packages
at each package's next bump.
2026-10-16 23:08:14 +02:00
c9bac2c78a
LICENSE, README, FUNDING.yml: GPL-3.0-only for our code, Forgejo's funding file and the shared footer
The repository had no license file. Our own code is GPL-3.0-only; the
patches and package recipes carried from other projects keep the license
their files name. FUNDING.yml is the file Forgejo reads for a repository's
Donate button (Forgejo 17.0 and later: .forgejo/, .github/, then the root
of the default branch); it points at https://catcrafts.net/shop/donation.
The README closes with the footer shared by imsd, fingerprintd and
fp6-img: License, Funding, Copyright.
2026-10-16 23:01:47 +02:00
6938ec10b2
modemmanager r102: quiet the bearer's WDS event reports in terse
With --test-quick-suspend-resume (fp6-device-tweaks 6) ModemManager sets
the modem terse before a suspend, but every connected QMI bearer keeps its
WDS event report subscription, and on the FP6 the data bearer technology
flips every few seconds while idle (LTE with 5G NSA), so the report still
ended a deep cycle within seconds. The patch adds a bearer step to terse:
the QMI bearer drops the event report of its WDS clients and the resume
sync re-arms them.

Dev phone, six logind-driven deep cycles: the report is gone from the
wake trace; three cycles ran their full 60 s alarm, the other three were
ended only by the modem writing its EFS through rmtfs. Same upstream
commit, patch 0004 on top of the three GNSS patches.
2026-10-14 18:42:47 +02:00
7191410852
fp6-device-tweaks 6: run ModemManager in its quick suspend/resume mode
Deep suspend on the FP6 is ended every few seconds by the modem's QMI
indications that ModemManager subscribes to: signal info on a 5 dB delta,
system info, DSD system status (16 + 3 of 25 deep cycles on 2026-10-14).
ModemManager already has the answer: started with
--test-quick-suspend-resume it sets the modem "terse" on logind's
PrepareForSleep (those subscriptions off, calls and texts still delivered)
and synchronises on resume. On the dev phone a logind-driven deep cycle
then runs to its 60 s alarm with the modem registered and imsd up, where
none of 21 did before.

Ship the flag as a drop-in. It does nothing while the sleep targets stay
masked, and is the modem side of the suspend policy when they go.
2026-10-14 18:03:13 +02:00
04695c128a
fp6-vendor-blobs 1-r4: build the ath11k board data from the stock modem partition
The device tree asks ath11k for the Fairphone_Gen_6 board data entry.
Upstream linux-firmware's WCN6750 board-2.bin has no Fairphone entry, so
the driver silently falls back to the generic board-id 255 data; the FP6
Plus does not associate on it (user report 2026-10-14), the FP6 happens
to. The stock modem partition carries the device's own calibration as
image/qca6750/bdwlan.elf.

New manifest directive ath11k-bdf: copy that ELF and wrap it into a
container under /lib/firmware/updates (searched first by the loader) that
is upstream's board-2.bin with every entry kept plus one BOARD entry under
the requested name. Verified structurally (ELF magic, size, the container
magic), no hash pin: calibration data is OEM data and the WLAN firmware
checks what it is given. If the base already carries the name the override
is not built and a stale one is removed. --refresh re-derives it. The
fragment re-probes ath11k as the fallback for a driver that probed before
extraction (WPSS restart, the association comes back via NetworkManager).

zstd joins the dependencies to read the compressed base. On the dev phone
the built container is byte-identical to the one hand-made from the stock
image by the reporter (sha256 186202ee...), built in 1.2 s.
2026-10-14 17:39:16 +02:00
7 changed files with 465 additions and 7 deletions

View file

@ -19,8 +19,8 @@
# retried it every 30 s forever (its StartLimit never trips)
maintainer="Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>"
pkgname=fp6-device-tweaks
pkgver=5
pkgrel=1
pkgver=6
pkgrel=0
pkgdesc="Fairphone 6 device-critical system configuration"
url="https://forgejo.catcrafts.net/Catcrafts/fp6-img"
arch="noarch"
@ -36,6 +36,7 @@ source="
iio-sensor-proxy-restart.conf
modem-gnss-nmea-optional.conf
91-fp6-no-ssc-sensors.rules
modemmanager-quick-suspend.conf
"
package() {
@ -53,6 +54,8 @@ package() {
"$pkgdir"/etc/systemd/system/modem-gnss.service.d/10-nmea-types-optional.conf
install -Dm644 "$srcdir"/91-fp6-no-ssc-sensors.rules \
"$pkgdir"/etc/udev/rules.d/91-fp6-no-ssc-sensors.rules
install -Dm644 "$srcdir"/modemmanager-quick-suspend.conf \
"$pkgdir"/etc/systemd/system/ModemManager.service.d/50-quick-suspend.conf
}
sha512sums="
@ -61,4 +64,5 @@ cc13f6abc4538fef976c59893992dd2c193cd0eac5da37a9fb01ba421b3ba8ff303aa438ec2fe4d1
f74c6c5d0ba3015cf123808452e9677c1d087e9540ea7037c30316e48a5c5bbdafe712ff0b07f17969337b1576a34cdfef4319c464ffe38c092a67d313129b57 iio-sensor-proxy-restart.conf
8fec832be59ca616d3e6a4c0a5ef8067d25f767c79155d8b0ef5761b8d21532932235a3236807305937029efe6255a16696d05523e3e654e2dc2212a281fe12c modem-gnss-nmea-optional.conf
1c5fd4a5a2a2c19165dca1381c8c6550fb61c6311561be450c9c6f88046d7649e4c7c6f4a86b163a2ecc1ef5ec93cc1dac1e2aded933a6b3d6d68292a1b609d0 91-fp6-no-ssc-sensors.rules
3e75ac137e76d556279866d8e34080f9724c3d02e58e9d4f55458b59047fcc62b9eff3d7c8a54faff13e6583d76ca5b5f62f362fc4f874b6c748211d1e9d26a5 modemmanager-quick-suspend.conf
"

View file

@ -0,0 +1,11 @@
# ModemManager's quick suspend/resume mode (fp6 repo journal/power/, 2026-10-14):
# on logind's PrepareForSleep the modem is set "terse" (the NAS signal-info,
# system-info and DSD system-status subscriptions are dropped, calls and
# texts still reach us) and on resume its state is synchronised. Without it
# the modem's indications end a deep suspend cycle every few seconds; with
# it a cycle runs to its wake alarm while the modem stays registered. The
# option still carries MM's --test- prefix; it is the only switch for the
# daemon's built-in terse mode.
[Service]
ExecStart=
ExecStart=/usr/sbin/ModemManager --test-quick-suspend-resume

View file

@ -0,0 +1,17 @@
# WCN6750 WLAN board data (calibration, Qualcomm/Fairphone) - taken from the
# stock modem partition on-device instead of being shipped (fp6 repo
# journal/base/ 2026-10-14, journal/blobs/). The device tree asks ath11k for
# the Fairphone_Gen_6 entry; upstream linux-firmware's board-2.bin has none,
# the driver silently falls back to generic data, and the FP6 Plus does not
# associate on that (user report 2026-10-14; the FP6 happens to work either
# way). The container built here is upstream's file with every entry kept
# plus the device's own bdwlan.elf under the requested name; it lives in
# /lib/firmware/updates, which the loader searches first. Active slot first,
# the other slot as fallback; no hash pin - calibration data is OEM data and
# the WLAN firmware verifies what it is given.
ath11k-bdf modem_a,modem_b image/qca6750/bdwlan.elf bus=ahb,qmi-chip-id=1,qmi-board-id=255,variant=Fairphone_Gen_6 /usr/lib/firmware/ath11k/WCN6750/hw1.0/board-2.bin.zst /usr/lib/firmware/updates/ath11k/WCN6750/hw1.0/board-2.bin
# Fallback for a driver that probed before extraction (the service runs
# pre-coldplug, so this normally no-ops): re-probing ath11k restarts the
# WPSS remoteproc and the firmware reads the new container; the association
# comes back through NetworkManager.
rebind platform 17110040.wifi

View file

@ -21,19 +21,20 @@
maintainer="Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>"
pkgname=fp6-vendor-blobs
pkgver=1
pkgrel=3
pkgrel=4
pkgdesc="On-device extraction of vendor blobs from the stock Android partitions"
url="https://forgejo.catcrafts.net/Catcrafts/fp6-img"
arch="noarch"
license="GPL-3.0-only"
# fallback mapper for when the initramfs didn't map the dynamic partitions
depends="make-dynpart-mappings"
depends="make-dynpart-mappings zstd"
install="$pkgname.post-upgrade"
options="!check"
source="
fp6-vendor-blobs-extract
fp6-vendor-blobs.service
fp6-vendor-blobs.preset
30-ath11k-board-data.manifest
"
package() {
@ -58,11 +59,13 @@ package() {
# extracted, no sound card. See journal/blobs/ 2026-08-28.
install -Dm644 "$srcdir"/fp6-vendor-blobs.preset \
"$pkgdir"/usr/lib/systemd/system-preset/50-fp6-vendor-blobs.preset
mkdir -p "$pkgdir"/usr/share/fp6-vendor-blobs/manifest.d
install -Dm644 "$srcdir"/30-ath11k-board-data.manifest \
"$pkgdir"/usr/share/fp6-vendor-blobs/manifest.d/30-ath11k-board-data.manifest
}
sha512sums="
e9618b4a1ccbe0913a608b32a1a9e87337e3da79a3d7ccc7f49292ae9aaa9406d2ea9817d63b3cfff2c4346b80dd2476c10725f4f0f95c859acd17b22ec03a16 fp6-vendor-blobs-extract
2aa740a2c4999d7e09c328664fe9c03e8a4ac8ddf1215b2d2b2755b12383dce873b9eafbce4706e87405cf2b0aa2e29ed582f31d9ee085346f911c11269c1f22 fp6-vendor-blobs-extract
b4c290095d9f39515378dfef08de720ce49324210342aa13c131dfce1103785e796e6f821f0c659671a4c44b46f466ce0e03f11f216fdcdee2a99db5e7970800 fp6-vendor-blobs.service
9e79dd0aed13f11a71282aa24b2a26331e85c105e25ab0c0fed6189b8c300769a5f4308b18b91d9855868d658ad3a57c03e26c9b11bd27fd5e03f9a5decbbd6a fp6-vendor-blobs.preset
1265a0f78aa4d9566e4a9f7827c8cead3a1848dc8bbd4288165085e87a824ea0c0940a16e5426f74074fcb29c1fddccf76f6dd3b16efa7ddffc2c437b9531439 30-ath11k-board-data.manifest
"

View file

@ -11,6 +11,7 @@
#
# file <partition[,partition...]> <path-in-partition> <dest> <sha256>
# mbn <partition[,partition...]> <dir-in-partition> <name> <dest> <sha256|->
# ath11k-bdf <partition[,partition...]> <path-in-partition> <entry-name> <base> <dest>
# rebind <bus> <device>
#
# Partition lists are tried in the order written, except that on an A/B
@ -47,6 +48,21 @@
# itself and refuses a damaged or foreign image (one flipped byte ->
# ERROR_ELF_SIGNATURE_ERROR, measured 2026-09-03). The sha256 of what was
# installed is logged either way.
# ath11k-bdf: the WLAN board data (calibration) the device tree asks ath11k
# for by name, e.g. bus=ahb,qmi-chip-id=1,qmi-board-id=255,variant=Fairphone_Gen_6.
# Upstream linux-firmware's board-2.bin carries no Fairphone entry, so the
# driver silently falls back to the generic board-id data; the FP6 Plus does
# not associate on it (user report 2026-10-14, fp6 repo journal/base/). The
# stock modem partition has the device's own file (image/qca6750/bdwlan.elf).
# This directive copies it and wraps it into a container at <dest> (the
# loader searches /lib/firmware/updates first): <base> (board-2.bin or
# board-2.bin.zst, every upstream entry kept byte for byte) + one BOARD
# entry named <entry-name> holding the ELF. Verified structurally (ELF
# magic, sane size, the container's own magic), never by a pinned hash:
# calibration data is OEM data and the WLAN firmware checks it itself.
# When <base> already carries <entry-name> (upstream caught up) nothing is
# built and a stale <dest> is removed so the base is used again.
# --refresh re-derives the dest like mbn (a new base after an upgrade).
# rebind: if this fragment's run extracted at least one file, unbind and
# re-probe <device> on <bus> so the consuming driver picks the file up
# in the same boot. Unconditional on purpose: a still-bound consumer may
@ -257,6 +273,62 @@ extract_mbn() { # <partition,...> <dir-in-partition> <name> <dest> <sha256|->
fail "no listed partition ($parts) yields $rname with sha256 $want - $dest NOT installed$kept"
}
# One little-endian u32 as four raw bytes (busybox printf, octal escapes).
le32() { # <value>
printf "\\$(printf %03o $(($1 & 255)))\\$(printf %03o $((($1 >> 8) & 255)))\\$(printf %03o $((($1 >> 16) & 255)))\\$(printf %03o $((($1 >> 24) & 255)))"
}
pad4() { # <length> -> bytes of zero padding to the next multiple of 4, on stdout
n=$(( (4 - $1 % 4) % 4 ))
[ "$n" -gt 0 ] && head -c "$n" /dev/zero
return 0
}
extract_ath11k_bdf() { # <partition,...> <path-in-partition> <entry-name> <base> <dest>
parts=$1 bsrc=$2 bname=$3 bbase=$4 bdest=$5
[ -f "$bbase" ] || fail "ath11k-bdf: base container $bbase missing"
braw="$bdest.fp6-base.$$"
mkdir -p "${bdest%/*}" || fail "cannot create ${bdest%/*}"
case "$bbase" in
*.zst) zstd -dcq "$bbase" > "$braw" 2>/dev/null || { rm -f "$braw"; fail "ath11k-bdf: cannot decompress $bbase"; } ;;
*) cp "$bbase" "$braw" || { rm -f "$braw"; fail "ath11k-bdf: cannot read $bbase"; } ;;
esac
[ "$(head -c 16 "$braw")" = "QCA-ATH11K-BOARD" ] || { rm -f "$braw"; fail "ath11k-bdf: $bbase is not a QCA-ATH11K-BOARD container"; }
if grep -a -q -F "$bname" "$braw"; then
rm -f "$braw"
log "ath11k-bdf: $bbase already carries $bname - no override needed"
[ -e "$bdest" ] && { rm -f "$bdest"; log "removed the redundant $bdest"; }
return 0
fi
for part in $(order_parts "$parts"); do
mount_part "$part" || { log "$part: not mountable, trying next"; continue; }
elf="$MNT/$bsrc"
[ -f "$elf" ] || { log "$part: no $bsrc, trying next"; continue; }
esz=$(fsize "$elf")
[ "$(hex4 "$elf")" = 7f454c46 ] || { log "$part:$bsrc: not an ELF image, trying next"; continue; }
[ "$esz" -ge 4096 ] && [ "$esz" -le $((1024 * 1024)) ] || { log "$part:$bsrc: $esz bytes is not a board data file, trying next"; continue; }
nlen=${#bname}
npad=$(( (nlen + 3) / 4 * 4 ))
dpad=$(( (esz + 3) / 4 * 4 ))
tmp="$bdest.fp6-extract.$$"
# container = base + BOARD IE { NAME IE, DATA IE }, each IE padded to 4
{
cat "$braw"
le32 0; le32 $((8 + npad + 8 + dpad))
le32 0; le32 "$nlen"; printf '%s' "$bname"; pad4 "$nlen"
le32 1; le32 "$esz"; cat "$elf"; pad4 "$esz"
} > "$tmp" 2>/dev/null || { rm -f "$tmp"; fail "ath11k-bdf: writing $tmp failed"; }
want=$(( $(fsize "$braw") + 8 + 8 + npad + 8 + dpad ))
[ "$(fsize "$tmp")" -eq "$want" ] || { rm -f "$tmp" "$braw"; fail "ath11k-bdf: $tmp is $(fsize "$tmp") bytes, expected $want"; }
got=$(sha256sum "$tmp" | awk '{print $1}')
chmod 644 "$tmp" && mv "$tmp" "$bdest" || { rm -f "$tmp" "$braw"; fail "installing $bdest failed"; }
rm -f "$braw"
log "built $bdest = $bbase + $bname from $part:$bsrc ($esz bytes, sha256 $got)"
return 0
done
rm -f "$braw"
kept=
[ -e "$bdest" ] && kept=" (the existing file is left in place)"
fail "no listed partition ($parts) yields a well-formed $bsrc - $bdest NOT installed$kept"
}
extract() { # <partition,...> <path-in-partition> <dest> <sha256>
parts=$1 src=$2 dest=$3 want=$4
for part in $(order_parts "$parts"); do
@ -320,6 +392,7 @@ for f in "$MANIFEST_DIR"/*.manifest; do
case "$kind" in
file) [ -e "$c" ] || missing=1 ;;
mbn) [ -e "$d" ] && [ -z "$REFRESH" ] || missing=1 ;;
ath11k-bdf) [ -e "$e" ] && [ -z "$REFRESH" ] || missing=1 ;;
esac
done < "$f"
done
@ -345,6 +418,12 @@ for f in "$MANIFEST_DIR"/*.manifest; do
extract_mbn "$a" "$b" "$c" "$d" "$e" </dev/null
extracted=1
;;
ath11k-bdf)
[ -n "$e" ] || fail "$f: malformed ath11k-bdf line"
[ -e "$e" ] && [ -z "$REFRESH" ] && continue
extract_ath11k_bdf "$a" "$b" "$c" "$d" "$e" </dev/null
extracted=1
;;
rebind)
[ -n "$b" ] || fail "$f: malformed rebind line"
rebinds="$rebinds $a/$b"

View file

@ -0,0 +1,342 @@
From 1a30e96fb992bfbd50574aa3b0467f48ce1dfd9d Mon Sep 17 00:00:00 2001
From: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
Date: Wed, 14 Oct 2026 18:18:45 +0200
Subject: [PATCH] bearer: quiet the WDS event reports in terse, re-arm them on
resume
The terse operation that runs before a suspend stops the 3GPP registration
and signal indications, but every connected QMI bearer keeps its WDS event
report subscription (data bearer technology, data systems, ...). Each of
those reports wakes a suspended host: on a Fairphone 6 on LTE with 5G NSA
the bearer technology changes every few seconds while the host is idle,
and the report ended a deep suspend cycle within seconds.
Add a terse step for the bearers: MMBaseBearer gets an optional terse()
vfunc, the QMI bearer implements it by dropping the event report of its
IPv4/IPv6 WDS clients, and the quick-resume synchronization (the bearer's
reload_connection_status) re-arms them.
---
src/mm-base-bearer.c | 50 +++++++++++++++++++
src/mm-base-bearer.h | 18 +++++++
src/mm-bearer-qmi.c | 101 +++++++++++++++++++++++++++++++++++++++
src/mm-broadband-modem.c | 49 +++++++++++++++++++
4 files changed, 218 insertions(+)
diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c
index f9b86884..e89843e5 100644
--- a/src/mm-base-bearer.c
+++ b/src/mm-base-bearer.c
@@ -1713,6 +1713,56 @@ mm_base_bearer_sync (MMBaseBearer *self,
#endif
+/*****************************************************************************/
+/* Terse (quiet the modem's unsolicited reports before a suspend) */
+
+#if defined WITH_SUSPEND_RESUME
+
+gboolean
+mm_base_bearer_terse_finish (MMBaseBearer *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+terse_ready (MMBaseBearer *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!MM_BASE_BEARER_GET_CLASS (self)->terse_finish (self, res, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+void
+mm_base_bearer_terse (MMBaseBearer *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ /* Nothing to quiet unless the bearer is connected and its class knows how */
+ if (self->priv->status != MM_BEARER_STATUS_CONNECTED ||
+ !MM_BASE_BEARER_GET_CLASS (self)->terse ||
+ !MM_BASE_BEARER_GET_CLASS (self)->terse_finish) {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ MM_BASE_BEARER_GET_CLASS (self)->terse (self, (GAsyncReadyCallback)terse_ready, task);
+}
+
+#endif
+
/*****************************************************************************/
static gchar *
diff --git a/src/mm-base-bearer.h b/src/mm-base-bearer.h
index 336b4442..12ef3cf7 100644
--- a/src/mm-base-bearer.h
+++ b/src/mm-base-bearer.h
@@ -151,6 +151,16 @@ struct _MMBaseBearerClass {
#if defined WITH_SUSPEND_RESUME
+ /* Terse: stop the unsolicited reports this bearer asked the modem for,
+ * so that they do not wake a suspended host; the quick-resume sync
+ * re-arms them. Optional. */
+ void (* terse) (MMBaseBearer *bearer,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* terse_finish) (MMBaseBearer *bearer,
+ GAsyncResult *res,
+ GError **error);
+
/* Reload connection status:
*
* This method should return the exact connection status of the bearer, and
@@ -236,6 +246,14 @@ gboolean mm_base_bearer_sync_finish (MMBaseBearer *self,
GAsyncResult *res,
GError **error);
+/* Terse Broadband Bearer (async): quiet the modem's reports before a suspend */
+void mm_base_bearer_terse (MMBaseBearer *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_base_bearer_terse_finish (MMBaseBearer *self,
+ GAsyncResult *res,
+ GError **error);
+
#endif
#endif /* MM_BASE_BEARER_H */
diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c
index 64d983eb..d637b993 100644
--- a/src/mm-bearer-qmi.c
+++ b/src/mm-bearer-qmi.c
@@ -61,6 +61,9 @@ struct _MMBearerQmiPrivate {
guint packet_service_status_ipv6_indication_id;
guint event_report_ipv6_indication_id;
guint extended_ipv6_config_change_id;
+#if defined WITH_SUSPEND_RESUME
+ gboolean terse;
+#endif
MMPort *data;
MMPort *link;
@@ -71,6 +74,10 @@ struct _MMBearerQmiPrivate {
GList *pco_list;
};
+#if defined WITH_SUSPEND_RESUME
+static void terse_rearm (MMBearerQmi *self);
+#endif
+
/*****************************************************************************/
/* Stats */
@@ -377,6 +384,11 @@ reload_connection_status (MMBaseBearer *self,
GTask *task;
ConnectionStatusContext *ctx;
+#if defined WITH_SUSPEND_RESUME
+ /* The quick-resume sync lands here: give the modem its reports back */
+ terse_rearm (MM_BEARER_QMI (self));
+#endif
+
ctx = g_new (ConnectionStatusContext, 1);
ctx->step = CONNECTION_STATUS_CONTEXT_STEP_FIRST;
@@ -1565,6 +1577,93 @@ cleanup_event_report_unsolicited_events (MMBearerQmi *self,
qmi_message_wds_set_event_report_input_unref (input);
}
+#if defined WITH_SUSPEND_RESUME
+
+/*****************************************************************************/
+/* Terse: the WDS event reports (data bearer technology, data systems, ...)
+ * are the modem's way of telling us about every bearer change, and each one
+ * wakes a suspended host. Drop them before the sleep; the quick-resume
+ * synchronization re-arms them. */
+
+static gboolean
+terse_finish (MMBaseBearer *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+terse (MMBaseBearer *_self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBearerQmi *self = MM_BEARER_QMI (_self);
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ if (self->priv->client_ipv4 && self->priv->event_report_ipv4_indication_id) {
+ cleanup_event_report_unsolicited_events (self, self->priv->client_ipv4,
+ &self->priv->event_report_ipv4_indication_id);
+ self->priv->terse = TRUE;
+ }
+ if (self->priv->client_ipv6 && self->priv->event_report_ipv6_indication_id) {
+ cleanup_event_report_unsolicited_events (self, self->priv->client_ipv6,
+ &self->priv->event_report_ipv6_indication_id);
+ self->priv->terse = TRUE;
+ }
+ if (self->priv->terse)
+ mm_obj_msg (self, "terse: WDS event reports disabled");
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+terse_rearm_ready (QmiClientWds *client,
+ GAsyncResult *res,
+ MMBearerQmi *self)
+{
+ GError *error = NULL;
+ guint id;
+
+ id = connect_enable_indications_ready (client, res, self, &error);
+ if (!id) {
+ mm_obj_warn (self, "couldn't re-enable WDS event reports after resume: %s",
+ error ? error->message : "unknown error");
+ g_clear_error (&error);
+ } else if (client == self->priv->client_ipv4) {
+ self->priv->event_report_ipv4_indication_id = id;
+ } else if (client == self->priv->client_ipv6) {
+ self->priv->event_report_ipv6_indication_id = id;
+ } else {
+ /* the bearer was disconnected meanwhile: the client is gone */
+ g_signal_handler_disconnect (client, id);
+ }
+ g_object_unref (self);
+}
+
+static void
+terse_rearm (MMBearerQmi *self)
+{
+ if (!self->priv->terse)
+ return;
+ self->priv->terse = FALSE;
+
+ if (self->priv->client_ipv4 && !self->priv->event_report_ipv4_indication_id)
+ setup_event_report_unsolicited_events (self, self->priv->client_ipv4, NULL,
+ (GAsyncReadyCallback)terse_rearm_ready,
+ g_object_ref (self));
+ if (self->priv->client_ipv6 && !self->priv->event_report_ipv6_indication_id)
+ setup_event_report_unsolicited_events (self, self->priv->client_ipv6, NULL,
+ (GAsyncReadyCallback)terse_rearm_ready,
+ g_object_ref (self));
+ mm_obj_msg (self, "terse: WDS event reports re-enabled");
+}
+
+#endif
+
static void
set_ip_family_ready (QmiClientWds *client,
GAsyncResult *res,
@@ -3015,5 +3114,7 @@ mm_bearer_qmi_class_init (MMBearerQmiClass *klass)
#if defined WITH_SUSPEND_RESUME
base_bearer_class->reload_connection_status = reload_connection_status;
base_bearer_class->reload_connection_status_finish = reload_connection_status_finish;
+ base_bearer_class->terse = terse;
+ base_bearer_class->terse_finish = terse_finish;
#endif
}
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 9364a20b..e65e4260 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -13193,11 +13193,13 @@ synchronize (MMBaseModem *self,
typedef enum {
TERSE_STEP_FIRST,
TERSE_STEP_DISABLE_UNSOLICITED_EVENTS_3GPP,
+ TERSE_STEP_BEARERS,
TERSE_STEP_LAST,
} TerseStep;
typedef struct {
TerseStep step;
+ guint pending_bearers;
} TerseContext;
static void terse_step (GTask *task);
@@ -13228,6 +13230,38 @@ iface_modem_3gpp_terse_ready (MMIfaceModem3gpp *self,
terse_step (task);
}
+static void
+bearer_terse_ready (MMBaseBearer *bearer,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModem *self;
+ TerseContext *ctx;
+ g_autoptr(GError) error = NULL;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_base_bearer_terse_finish (bearer, res, &error))
+ mm_obj_warn (self, "bearer terse failed: %s", error->message);
+
+ if (--ctx->pending_bearers == 0) {
+ ctx->step++;
+ terse_step (task);
+ }
+}
+
+static void
+bearer_terse_start (MMBaseBearer *bearer,
+ GTask *task)
+{
+ TerseContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+ ctx->pending_bearers++;
+ mm_base_bearer_terse (bearer, (GAsyncReadyCallback)bearer_terse_ready, task);
+}
+
static void
terse_step (GTask *task)
{
@@ -13253,6 +13287,21 @@ terse_step (GTask *task)
ctx->step++;
/* fall through */
+ case TERSE_STEP_BEARERS: {
+ g_autoptr(MMBearerList) list = NULL;
+
+ g_object_get (self, MM_IFACE_MODEM_BEARER_LIST, &list, NULL);
+ if (list) {
+ mm_obj_msg (self, "terse state (%d/%d): bearers disable unsolicited events",
+ ctx->step, TERSE_STEP_LAST);
+ /* hold the count while iterating: a bearer finishing early must not step on */
+ ctx->pending_bearers = 1;
+ mm_bearer_list_foreach (list, (MMBearerListForeachFunc)bearer_terse_start, task);
+ if (--ctx->pending_bearers > 0)
+ return;
+ }
+ ctx->step++;
+ } /* fall through */
case TERSE_STEP_LAST:
mm_obj_msg (self, "setting terse state (%d/%d): all done",
ctx->step, TERSE_STEP_LAST);
--
2.55.0

View file

@ -8,7 +8,7 @@
maintainer="Achill Gilgenast <achill@achill.org>"
pkgname=modemmanager
pkgver=1.25.95_git20261005
pkgrel=101
pkgrel=102
_commit=7f0bf17ab518cd78925cf7e53cc0d5c42f88b41a
pkgdesc="ModemManager library"
url="https://www.freedesktop.org/wiki/Software/ModemManager"
@ -73,6 +73,7 @@ source="ModemManager-$_commit.tar.gz
0001-intel-XMM7360-fix-big-endian-handling-of-ASN-integer.patch
0002-shared-qmi-unlock-AFW-gated-GNSS-engines-at-LOC-star.patch
0003-shared-qmi-derive-location-from-Position-Report-indi.patch
0004-bearer-quiet-the-WDS-event-reports-in-terse-re-arm-t.patch
"
#builddir="$srcdir"/ModemManager-$pkgver
builddir="$srcdir"/ModemManager-$_commit
@ -125,4 +126,5 @@ fd659330b2ec4e8368807053ec01498241dec153f6f2491bb17c42e2b81c8d9a98ff5f8c153874a6
6fab86c27502b29be0c6610d835a3249a4a81993eb986cff2c3ea9393fadd3f693ba4bb0532ae0e50a83d359559511859dd05f7ea2f0cb52839f535a7e49f8a0 modemmanager.rules
6e234cebcdec6d1afbca164ee5c13c96f7132ef31231d5c043cc5750ebe99e362a384d0463874b3c1c30799b433e0d3286add03af13c97fa406b4b5d2b78880c modemmanager.initd
f06e9b89acab5b61c5965658d62551b0f168066384674f7c4dd56feb6f811c82c640470e634e32d8c4ef62290588cf974aa5f213e5c67e797a06d33e61fa24ec 0001-intel-XMM7360-fix-big-endian-handling-of-ASN-integer.patch
1085a27a7f5dd89c5e4851ae3ddb2d6d970abbb3e2c0c548b4254c2aa13d702bff2234d03fb8c73662050d43508374cb4feb22166298a8dd2a6480bb77579b6f 0004-bearer-quiet-the-WDS-event-reports-in-terse-re-arm-t.patch
"