47 Commits

Author SHA1 Message Date
Arnaud Ferraris
9c05776843 d/changelog: release version 0.4.2-1 2021-12-08 18:27:34 +01:00
Arnaud Ferraris
08a7039ca0 Update upstream source from tag '0.4.2'
Update to upstream version '0.4.2'
with Debian dir ad2c13f51c
2021-12-08 18:23:57 +01:00
Arnaud Ferraris
929b3942c0 d/gbp.conf: update for current Mobian workflow 2021-12-08 18:23:44 +01:00
Arnaud Ferraris
f8430eb16f d/changelog: release version 0.4.1-1 2021-10-08 11:03:27 +02:00
Arnaud Ferraris
1b69252cbe d/copyright: add missing entries 2021-10-08 11:02:21 +02:00
Arnaud Ferraris
c17f947249 debian: drop distro-specific systemd service
It is now provided by upstream
2021-10-08 11:02:05 +02:00
Arnaud Ferraris
e96aec8390 New upstream version 0.4.1 2021-10-08 10:56:18 +02:00
Arnaud Ferraris
e4ae8d6382 d/changelog: release version 0.4.0-1 2021-09-01 00:46:28 +02:00
Arnaud Ferraris
da8a008268 d/control: add libcurl as build dependency 2021-09-01 00:43:54 +02:00
Arnaud Ferraris
30ce2bb3e2 New upstream version 0.4.0 2021-09-01 00:42:37 +02:00
Arnaud Ferraris
162fcf6fca d/eg25-manager.service: be less restrictive
Additional security options in kernel config make it more picky, 
removing problematic directives (`DeviceAllow` and `ProtectClock`) from 
the service file helps getting things straight.

Other options aren't recognized by our systemd version 
(`ProtectKernelModules`, `ProtectProc`, `ProtectDevices` and 
`ProtectKernelLog`), so we can just as well remove those.
2021-09-01 00:26:21 +02:00
undef
24dbcf464c d/salsa-ci: Add Mobian's CI 2021-07-29 08:45:11 +00:00
Arnaud Ferraris
b62b155875 Merge branch 'debian/latest' into 'debian/latest'
d/service: Use systemd to sandbox eg25-manager

See merge request mobian1/devices/eg25-manager!16
2021-07-26 23:34:32 +00:00
undef
67195a8e58 d/service: Use systemd to sandbox eg25-manager
With eg25-manager directly interfacing with the untrusted modem and
potentially (MR !15) including libcurl for HTTP, sandboxing the daemon
significantly reduces the any post-exploit attack surface.
2021-07-26 23:24:08 +00:00
Arnaud Ferraris
c7e8d9171c d/changelog: release version 0.3.0-1 2021-05-28 13:59:53 +02:00
Arnaud Ferraris
5db68722ec New upstream version 0.3.0 2021-05-28 13:58:11 +02:00
Arnaud Ferraris
432bd454bb d/changelog: release version 0.2.1-1 2021-02-21 16:42:15 +01:00
Arnaud Ferraris
986e7f08c4 New upstream version 0.2.1 2021-02-21 16:41:22 +01:00
Arnaud Ferraris
4089f2ea6b d/changelog: release version 0.2.0-1 2021-02-20 22:27:18 +01:00
Arnaud Ferraris
c77c58df49 d/eg25-manager.service: remove deprecated -g option 2021-02-20 22:26:13 +01:00
Arnaud Ferraris
5cc5ff5c0e d/gbp.conf: enable multimaint-merge 2021-02-20 17:21:37 +01:00
Arnaud Ferraris
6a81955086 New upstream version 0.2.0 2021-02-20 17:18:46 +01:00
Arnaud Ferraris
af3a2b25bc d/changelog: release version 0.1.2-1 2021-01-14 00:10:04 +01:00
Arnaud Ferraris
70db05fc62 d/eg25-manager.service: enable GNSS management 2021-01-14 00:09:17 +01:00
Arnaud Ferraris
705a454882 New upstream release 0.1.2 2021-01-14 00:08:27 +01:00
Arnaud Ferraris
2469757af4 d/changelog: release version 0.1.1-1 2020-12-18 01:42:39 +01:00
Arnaud Ferraris
514b00cc9c d/control: build-depend on gudev 2020-12-18 01:42:01 +01:00
Arnaud Ferraris
e078b8bc09 New upstream release 0.1.1 2020-12-18 01:41:39 +01:00
Arnaud Ferraris
d976c75fa2 d/changelog: release version 0.1.0-1 2020-12-14 16:46:02 +01:00
Arnaud Ferraris
f86d0ef062 New upstream release 0.1.0 2020-12-14 16:44:51 +01:00
Arnaud Ferraris
276c71f223 d/changelog: release version 0.0.6-1 2020-12-11 15:12:08 +01:00
Arnaud Ferraris
1423021f97 d/patches: drop upstreamed patches 2020-12-11 15:11:22 +01:00
Arnaud Ferraris
fc915f570d New upstream release 0.0.6 2020-12-11 15:10:40 +01:00
Arnaud Ferraris
c77490a2ac d/changelog: release version 0.0.5-2 2020-12-11 14:33:40 +01:00
Arnaud Ferraris
fbd5c0cb86 d/patches: fix crash on modem recovery 2020-12-11 14:33:09 +01:00
Arnaud Ferraris
5bcefbeab0 d/changelog: release version 0.0.5-1 2020-12-11 13:39:22 +01:00
Arnaud Ferraris
f85e8f70c7 New upstream release 0.0.5 2020-12-11 13:38:19 +01:00
Arnaud Ferraris
2da2c9dfe2 d/changelog: release version 0.0.4-1 2020-12-11 12:52:27 +01:00
Arnaud Ferraris
dfaac39162 d/control: build-depend on libusb-1.0 2020-12-11 12:51:36 +01:00
Arnaud Ferraris
7dc0d1678c New upstream release 0.0.4 2020-12-11 12:50:26 +01:00
Arnaud Ferraris
397a16a9e3 d/service: restart daemon on failure 2020-12-11 10:49:02 +01:00
Arnaud Ferraris
59219fbd20 d/control: build only on arm64
This package is PinePhone-specific, no need to build on other 
architectures.
2020-12-10 21:42:49 +01:00
Arnaud Ferraris
c953d41436 d/changelog: release version 0.0.3-1 2020-12-10 21:35:11 +01:00
Arnaud Ferraris
82bf80c5f4 New upstream release 0.0.3 2020-12-10 21:33:58 +01:00
Arnaud Ferraris
339faa46dc d/changelog: release version 0.0.2-1 2020-12-10 19:51:42 +01:00
Arnaud Ferraris
cdf92755cb New upstream release 0.0.2 2020-12-10 19:50:32 +01:00
Arnaud Ferraris
7c04c1998f Initial Debian packaging 2020-12-10 15:19:25 +01:00
40 changed files with 2525 additions and 2997 deletions

View File

@@ -1,48 +0,0 @@
BasedOnStyle: LLVM
ColumnLimit: 100
IndentWidth: 4
IndentGotoLabels: false
AlignArrayOfStructures: Left
AlignConsecutiveAssignments: None
AlignConsecutiveMacros: AcrossEmptyLines
AlignConsecutiveDeclarations:
Enabled: true
# Available only with clang-format 20+
# AlignFunctionDeclarations: true
AlignFunctionPointers: true
# Ensure we either have all args/params on a single line,
# or only one per line
BinPackArguments: false
BinPackParameters: false
# To be changed for clang-format 20+
# BinPackParameters: OnePerLine
# Avoid single-line enums/functions/ifs/loops/etc
AllowShortBlocksOnASingleLine: Never
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortCaseExpressionOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
BreakBeforeBinaryOperators: None
# Ensure function opening brackets are on their own line
BreakBeforeBraces: Linux
# Available only with clang-format 20+
# BreakBinaryOperations: OnePerLine
InsertNewlineAtEOF: true
# Don't be too strict on line lengths
PenaltyExcessCharacter: 10
# Prefer breaking arguments list over putting a function call
# on its own line after an assignment
PenaltyBreakAssignment: 200
PenaltyBreakBeforeFirstCallParameter: 200
# Ensure we never ever have the return type on a single line
PenaltyReturnTypeOnItsOwnLine: 1000

View File

@@ -1,4 +0,0 @@
# DeprecatedOrUnsafeBufferHandling requests that we use safe versions
# of mem{cpy,set} for example, but this would affect portability
Checks: 'clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling'
WarningsAsErrors: 'clang-diagnostic-*,clang-analyzer-*'

View File

@@ -1,49 +0,0 @@
stages:
- build
- check
variables:
CLANG_VERSION: 19
BUILD_DEPS_NO_MM: "build-essential libcurl4-openssl-dev libgpiod-dev libgudev-1.0-dev libusb-1.0-0-dev meson scdoc"
BUILD_DEPS: "${BUILD_DEPS_NO_MM} libmm-glib-dev"
image: debian:unstable-slim
build:
stage: build
script:
- apt-get update
- apt-get -y install ${BUILD_DEPS}
- meson build
- meson compile -C build
artifacts:
paths:
- build
# ModemManager is an optional dependency, let's ensure eg25-manager still builds fine without it
build-no-mm:
stage: build
script:
- apt-get update
- apt-get -y install ${BUILD_DEPS_NO_MM}
- meson build
- meson compile -C build
format:
stage: check
dependencies:
- build
script:
- apt-get update
- apt-get -y install ${BUILD_DEPS} clang-format-${CLANG_VERSION}
- ninja -C build clang-format-check
check:
stage: check
dependencies:
- build
script:
- apt-get update
# clang-tidy needs all dependencies to be installed so it can inspect their headers
- apt-get -y install ${BUILD_DEPS} clang-tidy-${CLANG_VERSION}
- ninja -C build clang-tidy

View File

@@ -15,7 +15,7 @@ It implements the following features:
`eg25-manager` requires the following development libraries:
- libglib2.0-dev
- libgpiod-dev (>= 2.0)
- libgpiod-dev
- libmm-glib-dev
## Building

View File

@@ -4,7 +4,7 @@ Before=ModemManager.service
[Service]
Type=simple
ExecStart=@bindir@/eg25-manager
ExecStart=@bindir@/eg25manager
Restart=on-failure
ProtectControlGroups=true
ProtectHome=true

View File

@@ -1,5 +1,4 @@
[manager]
monitor_udev = true
need_libusb = true
usb_vid = 0x2c7c
usb_pid = 0x0125

View File

@@ -1,5 +1,4 @@
[manager]
monitor_udev = true
need_libusb = true
usb_vid = 0x2c7c
usb_pid = 0x0125

View File

@@ -1,7 +1,4 @@
[manager]
monitor_udev = true
usb_vid = 0x2c7c
usb_pid = 0x0125
# Delay between setting GPIO and PWRKEY sequence, set in microseconds
poweron_delay = 100000

View File

@@ -1,7 +1,4 @@
[manager]
monitor_udev = false
usb_vid = 0x2c7c
usb_pid = 0x0125
# Delay between setting GPIO and PWRKEY sequence, set in microseconds
poweron_delay = 100000
@@ -38,7 +35,7 @@ configure = [
# Print software version
{ cmd = "QGMR" },
# Configure audio
{ cmd = "QDAI", expect = "3,0,0,4,0,1,1,1" },
{ cmd = "QDAI", expect = "3,0,0,4,0,0,1,1" },
# RI signaling using physical RI pin
{ cmd = "QCFG", subcmd = "risignaltype", expect = "\"physical\"" },
# Enable VoLTE support

112
debian/changelog vendored Normal file
View File

@@ -0,0 +1,112 @@
eg25-manager (0.4.2-1) unstable; urgency=medium
* d/gbp.conf: update for current Mobian workflow
* New upstream version 0.4.2
-- Arnaud Ferraris <arnaud.ferraris@collabora.com> Wed, 08 Dec 2021 18:24:38 +0100
eg25-manager (0.4.1-1) unstable; urgency=medium
* New upstream version 0.4.1
* debian: drop distro-specific systemd service.
* d/copyright: add missing entries
-- Arnaud Ferraris <arnaud.ferraris@collabora.com> Fri, 08 Oct 2021 11:02:27 +0200
eg25-manager (0.4.0-1) unstable; urgency=medium
[ undef ]
* d/service: Use systemd to sandbox eg25-manager.
* d/salsa-ci: Add Mobian's CI
[ Arnaud Ferraris ]
* New upstream version 0.4.0
* d/eg25-manager.service: be less restrictive.
* d/control: add libcurl as build dependency
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Wed, 01 Sep 2021 00:44:04 +0200
eg25-manager (0.3.0-1) unstable; urgency=medium
* New upstream version 0.3.0
-- Arnaud Ferraris <arnaud.ferraris@collabora.com> Fri, 28 May 2021 13:58:33 +0200
eg25-manager (0.2.1-1) unstable; urgency=medium
* New upstream version 0.2.1
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Sun, 21 Feb 2021 16:41:31 +0100
eg25-manager (0.2.0-1) unstable; urgency=medium
* New upstream version 0.2.0
* d/gbp.conf: enable multimaint-merge
* d/eg25-manager.service: remove deprecated -g option
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Sat, 20 Feb 2021 22:26:19 +0100
eg25-manager (0.1.2-1) unstable; urgency=medium
* New upstream release 0.1.2
* d/eg25-manager.service: enable GNSS management
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Thu, 14 Jan 2021 00:09:23 +0100
eg25-manager (0.1.1-1) unstable; urgency=medium
* d/control: build-depend on gudev
* New upstream release 0.1.1
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Fri, 18 Dec 2020 01:42:06 +0100
eg25-manager (0.1.0-1) unstable; urgency=medium
* New upstream release 0.1.0
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Mon, 14 Dec 2020 16:45:20 +0100
eg25-manager (0.0.6-1) unstable; urgency=medium
* New upstream release 0.0.6
* d/patches: drop upstreamed patches
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Fri, 11 Dec 2020 15:11:26 +0100
eg25-manager (0.0.5-2) unstable; urgency=medium
* d/patches: fix crash on modem recovery
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Fri, 11 Dec 2020 14:33:14 +0100
eg25-manager (0.0.5-1) unstable; urgency=medium
* New upstream release 0.0.5
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Fri, 11 Dec 2020 13:38:41 +0100
eg25-manager (0.0.4-1) unstable; urgency=medium
* d/control: build only on arm64.
* d/service: restart daemon on failure
* d/control: build-depend on libusb-1.0
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Fri, 11 Dec 2020 12:51:41 +0100
eg25-manager (0.0.3-1) unstable; urgency=medium
* New upstream release 0.0.3
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Thu, 10 Dec 2020 21:34:26 +0100
eg25-manager (0.0.2-1) unstable; urgency=medium
* New upstream release 0.0.2
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Thu, 10 Dec 2020 19:50:50 +0100
eg25-manager (0.0.1-1) unstable; urgency=medium
* Initial Debian packaging
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Thu, 10 Dec 2020 15:19:15 +0100

28
debian/control vendored Normal file
View File

@@ -0,0 +1,28 @@
Source: eg25-manager
Section: libs
Priority: optional
Maintainer: Arnaud Ferraris <arnaud.ferraris@gmail.com>
Standards-Version: 4.5.1
Rules-Requires-Root: no
Build-Depends: debhelper-compat (= 13),
libcurl-dev,
libglib2.0-dev,
libgpiod-dev,
libgudev-1.0-dev,
libmm-glib-dev,
libusb-1.0-0-dev,
meson,
Homepage: https://gitlab.com/mobian1/devices/eg25-manager
Vcs-Git: https://gitlab.com/mobian1/devices/eg25-manager.git
Vcs-Browser: https://gitlab.com/mobian1/devices/eg25-manager
Package: eg25-manager
Architecture: arm64
Depends: ${misc:Depends},
${shlibs:Depends},
modemmanager,
Conflicts: pinephone-modem-scripts,
Replaces: pinephone-modem-scripts,
Description: Manager daemon for the Quectel EG25 mobile broadband modem
A set of scripts for the PinePhone modem, allowing to power on/off the modem,
and configure its audio interface to work properly with the A64 audio codec.

67
debian/copyright vendored Normal file
View File

@@ -0,0 +1,67 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: eg25-manager
Upstream-Contact: Arnaud Ferraris <arnaud.ferraris@gmail.com>
Source: https://gitlab.com/mobian1/devices/eg25-manager
Files: *
Copyright: 2020 Arnaud Ferraris <arnaud.ferraris@gmail.com>
License: GPL-3.0-or-later
Files: src/gnss.*
Copyright: 2021 Dylan Van Assche <me@dylanvanassche.be>
License: GPL-3.0-or-later
Files: src/mm-iface.c
Copyright: 2019 Purism SPC
2020 Arnaud Ferraris <arnaud.ferraris@gmail.com>
License: GPL-3.0-or-later
Files: src/ofono-iface.c
Copyright: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
2021 Bhushan Shah <bshah@kde.org>
License: GPL-3.0-or-later
Files: src/suspend.c
Copyright: 2012 Red Hat, Inc
2020 Arnaud Ferraris <arnaud.ferraris@gmail.com>
License: GPL-3.0-or-later
Files: src/toml.*
Copyright: 2017-2019 CK Tan
License: MIT
License: GPL-3.0-or-later
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
.
On Debian systems, the full text of the GNU General Public License
version 3 can be found in the file `/usr/share/common-licenses/GPL-3'.
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

10
debian/gbp.conf vendored Normal file
View File

@@ -0,0 +1,10 @@
[DEFAULT]
debian-branch = mobian
debian-tag = mobian/%(version)s
upstream-branch = upstream/latest
upstream-tag = %(version)s
pristine-tar = True
multimaint-merge = True
[tag]
sign-tags = True

6
debian/rules vendored Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@

2
debian/salsa-ci.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
include:
- https://gitlab.com/mobian1/packaging-tools/-/raw/master/mobian-ci.yml

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (quilt)

5
debian/watch vendored Normal file
View File

@@ -0,0 +1,5 @@
version=4
opts=filenamemangle=s/.*\/archive\/(\d\S+)\/eg25-manager.*\.tar\.gz/eg25-manager-$1\.tar\.gz/g \
https://gitlab.com/mobian1/eg25-manager/tags?sort=updated_desc .*/archive/(\d\S+)/.*\.tar\.gz.*

View File

@@ -1,106 +0,0 @@
eg25-manager(5)
# NAME
eg25-manager configuration file format
# SYNOPSIS
eg25-manager uses toml formatted files for configuration.
Configurations are loaded from:
- *@eg25_confdir@/<compatible>.toml*: User-provided overrides (optional)
- *@eg25_datadir@/<compatible>.toml*: Default configuration (required)
# SECTION: manager
General settings for eg25-manager.
*poweron_delay* int (microseconds)
Delay between de-asserting RESET and starting the PWRKEY sequence.
# SECTION: suspend
Settings for how to handle suspend on the system where eg25-manager is running.
*boot_timeout* int (seconds)
Prevent the system from suspending for boot_timeout seconds to allow the
modem to fully boot.
Default: 120 if unset or zero.
*recovery_timeout* int (seconds)
Amount of time to wait for the modem to reappear after suspend. If the
timeout is reached the modem's USB connection will be reset.
Default: 9 if unset or zero.
# SECTION: at
AT commands to send when different events happen, and where to send them to.
Each command has 4 possible elements:
- *cmd*: the AT command itself, which will be translated to "AT+`cmd`"
- *subcmd*: the subcommand in case a single AT command can be used to
change multiple parameters, such as QCFG
- *value*: the command's argument(s), usually used to set the value of a
specific parameter
- *expect*: the expected return value; the command is first executed
without any value in order to query the current state. This state is
then compared to the *expect* string; if they don't match, the command
is then executed with value *expect* in order to set the parameter to
the expected value
A command can have *expect* OR *value* configured, but it shouldn't have both
*NOTE:* If a command sequence is configured in an override file, the default
commands won't be loaded from the system configuration. The default commands
should be copied into the override file when changing them.
*uart* string
The serial port to use for sending AT commands to the modem.
*configure* List of commands
AT commands to send to the modem when it is first started.
*suspend* List of commands
AT commands to send to the modem before the system suspends.
*resume* List of commands
AT commands to send to the modem after the system resumes from suspend.
*reset* List of commands
AT commands to send to the modem if resetting the usb port fails.
# SECTION: gnss
Settings for uploading AGPS assistance data to the modem.
*enabled* boolean
Enable or disable uploading AGPS data to the modem
*url* string
The directory on the server that contains the assistance files
Example: https://xtrapath4.izatcloud.net
*file* string
The name of the assistance file on the server.
Example: xtra2.bin
# SECTION: gpio
The *gpio* section defines the GPIO pins to use for different modem functions.
These settings should only be changed when porting eg25-manager to a new device;
for this reason they aren't documented here.
# EXAMPLES
Print the firmware version every time the phone wakes from suspend:
```
[at]
resume = [
{ cmd = "QGMR" },
]
```
Disable uploading AGPS data to the modem:
```
[gnss]
enabled = false
```
# SEE AlSO
*eg25-manager*(8)

View File

@@ -1,37 +0,0 @@
eg25-manager(8)
# NAME
eg25-manager - a daemon for managing the Quectel EG25 modem found on the
Pine64 PinePhone.
# SYNOPSIS
*eg25-manager* [-v] [-c config_file]
# OPTIONS
*-v*
Show the version number and quit.
*-c*
User configuration file, defaults to the device configuration file in
/etc/eg25-manager.
# FILES
Configurations are loaded from:
- *@eg25_confdir@/<compatible>.toml*: User-provided overrides (optional)
- *@eg25_datadir@/<compatible>.toml*: Default configuration (required)
eg25-manager will search these folders for files named after the value of the
compatible device-tree property (with the .toml file extension) and use the
first matching file in each directory. If no matching default configuration is
found, eg25-manager will exit with an error message.
Values from the user-provided overrides will take priority over values stored in
the default configuration. Only changed values must be stored as user overrides,
so eg25-manager can fall back to the default configuration as often as possible.
The file names eg25-manager will check can be listed using:
```
xargs -0 printf '%s.toml\\n' < /proc/device-tree/compatible
```
# SEE ALSO
*eg25-manager*(5) *ModemManager*(8) *ofono*(8)

View File

@@ -1,33 +0,0 @@
#
# Copyright (C) 2020 Arnaud Ferraris <arnaud.ferraris@gmail.com>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
scdoc = dependency('scdoc', native: true, required: false)
if scdoc.found()
scdoc_prog = find_program(scdoc.get_variable('scdoc'), native: true)
foreach section: [5, 8]
name = 'eg25-manager'
out = '@0@.@1@'.format(name, section)
preprocessed = configure_file(
input: '@0@.scd'.format(out),
output: '@BASENAME@.preprocessed',
configuration: {
'eg25_confdir': eg25_confdir,
'eg25_datadir': eg25_datadir,
}
)
custom_target(
out,
output: out,
input: preprocessed,
command: ['sh', '-c', '@0@ < @INPUT@'.format(scdoc_prog.full_path())],
capture: true,
install: true,
install_dir: join_paths(get_option('mandir'), 'man@0@'.format(section)))
endforeach
endif

View File

@@ -8,9 +8,9 @@
project (
'eg25-manager',
'c',
version : '0.5.2',
version : '0.4.2',
license : 'GPLv3+',
meson_version : '>= 0.58.0',
meson_version : '>= 0.50.0',
default_options :
[
'warning_level=1',
@@ -59,13 +59,12 @@ mgr_deps = [
dependency('glib-2.0'),
dependency('gio-unix-2.0'),
dependency('gudev-1.0'),
dependency('libgpiod', version: '>= 2.0'),
dependency('libgpiod'),
dependency('libusb-1.0'),
dependency('libcurl'),
mmglib_dep,
]
subdir('data')
subdir('doc')
subdir('src')
subdir('udev')

View File

@@ -6,9 +6,9 @@
#include "at.h"
#include "config.h"
#include "gnss.h"
#include "gpio.h"
#include "suspend.h"
#include "gpio.h"
#include "gnss.h"
#include <errno.h>
#include <fcntl.h>
@@ -56,14 +56,14 @@ static void at_free_command(gpointer cmd, gpointer data)
if (!at_cmd)
return;
if (manager && manager->at_cmds)
manager->at_cmds = g_list_remove(manager->at_cmds, at_cmd);
g_free(at_cmd->cmd);
g_free(at_cmd->subcmd);
g_free(at_cmd->value);
g_free(at_cmd->expected);
g_free(at_cmd);
if (manager && manager->at_cmds)
manager->at_cmds = g_list_remove(manager->at_cmds, at_cmd);
}
gboolean at_send_command(struct EG25Manager *manager)
@@ -82,26 +82,20 @@ gboolean at_send_command(struct EG25Manager *manager)
else if (at_cmd->subcmd == NULL && at_cmd->value == NULL)
len = snprintf(command, sizeof(command), "AT+%s?\r\n", at_cmd->cmd);
else if (at_cmd->subcmd == NULL && at_cmd->value)
len = snprintf(command, sizeof(command), "AT+%s=%s\r\n", at_cmd->cmd, at_cmd->value);
len = snprintf(command, sizeof(command),"AT+%s=%s\r\n", at_cmd->cmd, at_cmd->value);
else if (at_cmd->subcmd && at_cmd->value == NULL)
len = snprintf(command, sizeof(command), "AT+%s=\"%s\"\r\n", at_cmd->cmd, at_cmd->subcmd);
else if (at_cmd->subcmd && at_cmd->value)
len = snprintf(command,
sizeof(command),
"AT+%s=\"%s\",%s\r\n",
at_cmd->cmd,
at_cmd->subcmd,
at_cmd->value);
len = snprintf(command, sizeof(command), "AT+%s=\"%s\",%s\r\n", at_cmd->cmd, at_cmd->subcmd, at_cmd->value);
if (len < 0) {
g_warning("snprintf(3) failed");
at_next_command(manager);
return FALSE;
} else if (len >= sizeof(command)) {
}
else if (len >= sizeof(command)) {
g_warning("AT command does not fit into buffer "
"(%d bytes required, %zu available)",
len,
sizeof(command));
"(%d bytes required, %zu available)", len, sizeof(command));
at_next_command(manager);
return FALSE;
}
@@ -123,7 +117,8 @@ gboolean at_send_command(struct EG25Manager *manager)
at_next_command(manager);
return FALSE;
}
} else {
}
else {
len -= ret;
pos += ret;
}
@@ -151,6 +146,8 @@ gboolean at_send_command(struct EG25Manager *manager)
}
} else if (manager->modem_state == EG25_STATE_SUSPENDING) {
modem_suspend_post(manager);
} else if (manager->modem_state == EG25_STATE_RESETTING) {
manager->modem_state = EG25_STATE_POWERED;
}
}
@@ -181,7 +178,8 @@ static void retry_at_command(struct EG25Manager *manager)
}
}
void at_process_result(struct EG25Manager *manager, const char *response)
void at_process_result(struct EG25Manager *manager,
const char *response)
{
struct AtCommand *at_cmd = manager->at_cmds ? g_list_nth_data(manager->at_cmds, 0) : NULL;
@@ -205,7 +203,9 @@ int at_append_command(struct EG25Manager *manager,
const char *subcmd,
const char *value,
const char *expected,
void (*callback)(struct EG25Manager *manager, const char *response))
void (*callback)
(struct EG25Manager *manager,
const char *response))
{
struct AtCommand *at_cmd = calloc(1, sizeof(struct AtCommand));
@@ -229,10 +229,12 @@ int at_append_command(struct EG25Manager *manager,
#define READ_BUFFER_SIZE 256
static gboolean modem_response(gint fd, GIOCondition event, gpointer data)
static gboolean modem_response(gint fd,
GIOCondition event,
gpointer data)
{
struct EG25Manager *manager = data;
char response[READ_BUFFER_SIZE * 4 + 1];
char response[READ_BUFFER_SIZE*4+1];
char tmp[READ_BUFFER_SIZE];
ssize_t ret, pos = 0;

View File

@@ -20,7 +20,8 @@ typedef struct AtCommand {
int at_init(struct EG25Manager *manager, toml_table_t *config[]);
void at_destroy(struct EG25Manager *manager);
void at_process_result(struct EG25Manager *manager, const char *response);
void at_process_result(struct EG25Manager *manager,
const char *response);
void at_next_command(struct EG25Manager *manager);
gboolean at_send_command(struct EG25Manager *manager);
int at_append_command(struct EG25Manager *manager,
@@ -28,7 +29,9 @@ int at_append_command(struct EG25Manager *manager,
const char *subcmd,
const char *value,
const char *expected,
void (*callback)(struct EG25Manager *manager, const char *response));
void (*callback)
(struct EG25Manager *manager,
const char *response));
void at_sequence_configure(struct EG25Manager *manager);
void at_sequence_suspend(struct EG25Manager *manager);

View File

@@ -9,7 +9,7 @@
gboolean config_get_bool(toml_table_t **config, const gchar *key, gboolean *result)
{
toml_datum_t value = {.ok = 0};
toml_datum_t value = { .ok = 0 };
if (config[EG25_CONFIG_USER])
value = toml_bool_in(config[EG25_CONFIG_USER], key);
@@ -23,7 +23,7 @@ gboolean config_get_bool(toml_table_t **config, const gchar *key, gboolean *resu
gboolean config_get_int(toml_table_t **config, const gchar *key, gint *result)
{
toml_datum_t value = {.ok = 0};
toml_datum_t value = { .ok = 0 };
if (config[EG25_CONFIG_USER])
value = toml_int_in(config[EG25_CONFIG_USER], key);
@@ -49,14 +49,14 @@ gboolean config_get_uint(toml_table_t **config, const gchar *key, guint *result)
}
if (found && result)
*result = (guint)value;
*result = (guint) value;
return found;
}
gboolean config_get_string(toml_table_t **config, const gchar *key, gchar **result)
{
toml_datum_t value = {.ok = 0};
toml_datum_t value = { .ok = 0 };
if (config[EG25_CONFIG_USER])
value = toml_string_in(config[EG25_CONFIG_USER], key);

View File

@@ -4,14 +4,14 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "gnss.h"
#include "at.h"
#include "config.h"
#include "gnss.h"
#include "manager.h"
#include "at.h"
#include <errno.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <errno.h>
#define BUFFER_SIZE 256
#define UPLOAD_DELAY_US 25000
@@ -29,24 +29,25 @@ gboolean gnss_upload_assistance_data(struct EG25Manager *manager)
if (manager->gnss_assistance_step < EG25_GNSS_STEP_LAST) {
g_warning("GNSS assistance data upload already in process (%d/%d)",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
return FALSE;
}
/* data upload isn't necessary to bring the modem onine, so we should wait
* until we've finished the rest of our configuration */
if (!manager->modem_iface || manager->modem_state < EG25_STATE_CONFIGURED ||
if (!manager->modem_iface ||
manager->modem_state < EG25_STATE_CONFIGURED ||
manager->modem_state > EG25_STATE_CONNECTED) {
g_message("Rescheduling upload since modem isn't online yet, in %ds", RESCHEDULE_IN_SECS);
g_message ("Rescheduling upload since modem isn't online yet, in %ds",
RESCHEDULE_IN_SECS);
manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
return TRUE;
}
#ifdef HAVE_MMGLIB
/* ModemManager's Location is only available after unlocking */
if (manager->modem_iface == MODEM_IFACE_MODEMMANAGER && !manager->mm_location) {
g_message("Rescheduling upload since Location interface is not available, in %ds",
if(manager->modem_iface == MODEM_IFACE_MODEMMANAGER && !manager->mm_location) {
g_message ("Rescheduling upload since Location interface is not available, in %ds",
RESCHEDULE_IN_SECS);
manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
return TRUE;
@@ -61,7 +62,7 @@ gboolean gnss_upload_assistance_data(struct EG25Manager *manager)
void gnss_init(struct EG25Manager *manager, toml_table_t *config[])
{
toml_table_t *gnss_config[EG25_CONFIG_COUNT];
g_autoptr(GError) error = NULL;
g_autoptr (GError) error = NULL;
for (int i = 0; i < EG25_CONFIG_COUNT; i++)
gnss_config[i] = config[i] ? toml_table_in(config[i], "gnss") : NULL;
@@ -91,11 +92,12 @@ void gnss_init(struct EG25Manager *manager, toml_table_t *config[])
/* Create temporary file to store assistance data */
manager->gnss_assistance_fd = g_file_open_tmp(NULL, NULL, &error);
if (error != NULL)
g_error("Unable to create temporary file: %s", error->message);
g_error ("Unable to create temporary file: %s", error->message);
/* Initialize state and schedule upload */
manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
g_timeout_add_seconds(RESCHEDULE_IN_SECS, G_SOURCE_FUNC(gnss_upload_assistance_data), manager);
g_timeout_add_seconds(RESCHEDULE_IN_SECS,
G_SOURCE_FUNC(gnss_upload_assistance_data), manager);
}
void gnss_destroy(struct EG25Manager *manager)
@@ -112,7 +114,7 @@ static void disable_mm_gnss(struct EG25Manager *manager)
{
MMModemLocationSource sources;
gboolean signals_location;
g_autoptr(GError) error = NULL;
g_autoptr (GError) error = NULL;
sources = mm_modem_location_get_enabled(manager->mm_location);
signals_location = mm_modem_location_signals_location(manager->mm_location);
@@ -138,14 +140,17 @@ static void disable_mm_gnss(struct EG25Manager *manager)
sources &= ~MM_MODEM_LOCATION_SOURCE_GPS_RAW;
sources &= ~MM_MODEM_LOCATION_SOURCE_GPS_NMEA;
sources &= ~MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED;
mm_modem_location_setup_sync(manager->mm_location, sources, signals_location, NULL, &error);
mm_modem_location_setup_sync(manager->mm_location, sources,
signals_location, NULL, &error);
if (error != NULL) {
g_warning("Unable to disable GNSS engine through ModemManager: %s", error->message);
g_warning("Unable to disable GNSS engine through ModemManager: %s",
error->message);
}
}
#endif
static void disable_at_gnss_cb(struct EG25Manager *manager, const char *response)
static void disable_at_gnss_cb(struct EG25Manager *manager,
const char *response)
{
/* Clear QGPSEND AT command and process next */
at_next_command(manager);
@@ -205,14 +210,16 @@ static void fetch_assistance_data(struct EG25Manager *manager)
/* Fetch assistance data with curl */
tmp_file = fdopen(manager->gnss_assistance_fd, "wb+");
if (tmp_file == NULL) {
g_critical("Unable to open file to save assistance data: %s", g_strerror(errno));
g_critical("Unable to open file to save assistance data: %s",
g_strerror(errno));
goto bail;
}
lseek(manager->gnss_assistance_fd, 0, SEEK_SET);
if (ftruncate(manager->gnss_assistance_fd, 0) < 0)
g_warning("Unable to truncate file, assistance data might be invalid!");
url = g_strconcat(manager->gnss_assistance_url, "/", manager->gnss_assistance_file, NULL);
url = g_strconcat(manager->gnss_assistance_url, "/",
manager->gnss_assistance_file, NULL);
curl = curl_easy_init();
if (!curl) {
@@ -230,8 +237,7 @@ static void fetch_assistance_data(struct EG25Manager *manager)
response = curl_easy_perform(curl);
if (response != CURLE_OK) {
g_warning("Unable to fetch GNSS assistance data from %s: %s",
url,
strlen(errbuf) ? errbuf : curl_easy_strerror(response));
url, strlen(errbuf) ? errbuf : curl_easy_strerror(response));
goto bail;
}
@@ -246,24 +252,24 @@ static void fetch_assistance_data(struct EG25Manager *manager)
g_message("Fetching GNSS assistance data from %s was successful", url);
fflush(tmp_file);
curl_easy_cleanup(curl);
/* Go to the next step */
manager->gnss_assistance_step++;
gnss_step(manager);
goto cleanup;
return;
bail:
manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
cleanup:
fflush(tmp_file);
fclose(tmp_file);
if (curl != NULL)
curl_easy_cleanup(curl);
manager->gnss_assistance_step = EG25_GNSS_STEP_LAST;
}
/******************************************************************************/
static void init_assistance_data_upload_ready(struct EG25Manager *manager, const char *response)
static void init_assistance_data_upload_ready(struct EG25Manager *manager,
const char *response)
{
/* Search for 'CONNECT' in response to start upload */
if (strstr(response, "CONNECT")) {
@@ -279,7 +285,8 @@ static void init_assistance_data_upload_ready(struct EG25Manager *manager, const
}
}
static void init_assistance_data_upload_start(struct EG25Manager *manager, const char *response)
static void init_assistance_data_upload_start(struct EG25Manager *manager,
const char *response)
{
gchar value[BUFFER_SIZE];
off_t size;
@@ -298,14 +305,11 @@ static void init_assistance_data_upload_start(struct EG25Manager *manager, const
lseek(manager->gnss_assistance_fd, 0, SEEK_SET);
/* Start upload */
g_snprintf(value,
BUFFER_SIZE,
"\"RAM:%s\",%ld,%d",
manager->gnss_assistance_file,
size,
UPLOAD_TIMEOUT_S);
g_snprintf(value, BUFFER_SIZE, "\"RAM:%s\",%ld,%d",
manager->gnss_assistance_file, size, UPLOAD_TIMEOUT_S);
g_message("Initiate GNSS assistance data upload: %s", value);
at_append_command(manager, "QFUPL", NULL, value, NULL, init_assistance_data_upload_ready);
at_append_command(manager, "QFUPL", NULL, value, NULL,
init_assistance_data_upload_ready);
at_send_command(manager);
}
@@ -315,14 +319,15 @@ static void init_assistance_data_upload(struct EG25Manager *manager)
* Delete all previous GNSS assistance data files in RAM
* and start uploading the latest one to RAM.
*/
at_append_command(manager, "QFDEL", NULL, "\"RAM:*\"\r\n", NULL, init_assistance_data_upload_start);
at_append_command(manager, "QFDEL", NULL, "\"RAM:*\"\r\n",
NULL, init_assistance_data_upload_start);
at_send_command(manager);
}
static void upload_assistance_data(struct EG25Manager *manager)
{
gint error;
off_t written_total = 0;
glong written_total = 0;
gint ret;
struct stat sb;
@@ -352,7 +357,8 @@ static void upload_assistance_data(struct EG25Manager *manager)
}
}
static void finish_assistance_data_upload_cb(struct EG25Manager *manager, const char *response)
static void finish_assistance_data_upload_cb(struct EG25Manager *manager,
const char *response)
{
/* Process response */
at_process_result(manager, response);
@@ -373,12 +379,15 @@ static void finish_assistance_data_upload(struct EG25Manager *manager)
datetime = g_date_time_new_now_utc();
timestring = g_date_time_format(datetime, "0,\"%Y/%m/%d,%H:%M:%S\"");
g_message("Setting GNSS assistance UTC clock to: %s", timestring);
at_append_command(manager, "QGPSXTRATIME", NULL, timestring, NULL, at_process_result);
at_append_command(manager, "QGPSXTRATIME", NULL, timestring, NULL,
at_process_result);
/* Configure GNSS engine to use uploaded GNSS assistance data */
g_snprintf(value, BUFFER_SIZE, "\"RAM:%s\"", manager->gnss_assistance_file);
g_snprintf(value, BUFFER_SIZE, "\"RAM:%s\"",
manager->gnss_assistance_file);
g_message("Setting GNSS assistance file to: %s", value);
at_append_command(manager, "QGPSXTRADATA", NULL, value, NULL, finish_assistance_data_upload_cb);
at_append_command(manager, "QGPSXTRADATA", NULL, value, NULL,
finish_assistance_data_upload_cb);
at_send_command(manager);
}
@@ -387,7 +396,7 @@ static void finish_assistance_data_upload(struct EG25Manager *manager)
#ifdef HAVE_MMGLIB
static void enable_mm_gnss(struct EG25Manager *manager)
{
g_autoptr(GError) error = NULL;
g_autoptr (GError) error = NULL;
MMModemLocationSource sources = mm_modem_location_get_enabled(manager->mm_location);
gboolean signal_location = mm_modem_location_signals_location(manager->mm_location);
@@ -398,9 +407,11 @@ static void enable_mm_gnss(struct EG25Manager *manager)
if (manager->gnss_sources & EG25_GNSS_SOURCE_RAW)
sources |= MM_MODEM_LOCATION_SOURCE_GPS_RAW;
mm_modem_location_setup_sync(manager->mm_location, sources, signal_location, NULL, &error);
mm_modem_location_setup_sync(manager->mm_location, sources,
signal_location, NULL, &error);
if (error != NULL)
g_warning("Unable to enable GNSS engine through ModemManager: %s", error->message);
g_warning("Unable to enable GNSS engine through ModemManager: %s",
error->message);
}
#endif
@@ -413,7 +424,8 @@ static void enable_at_gnss_cb(struct EG25Manager *manager, const char *response)
static void enable_at_gnss(struct EG25Manager *manager)
{
if (manager->gnss_sources & EG25_GNSS_SOURCE_QGPS) {
at_append_command(manager, "QGPS", NULL, "1", NULL, enable_at_gnss_cb);
at_append_command(manager, "QGPS", NULL, "1", NULL,
enable_at_gnss_cb);
at_send_command(manager);
return;
}
@@ -425,7 +437,7 @@ static void enable_at_gnss(struct EG25Manager *manager)
void gnss_step(struct EG25Manager *manager)
{
switch (manager->gnss_assistance_step) {
switch(manager->gnss_assistance_step) {
case EG25_GNSS_STEP_FIRST:
manager->gnss_assistance_step++;
g_message("GNSS assistance upload started...");
@@ -434,8 +446,7 @@ void gnss_step(struct EG25Manager *manager)
case EG25_GNSS_STEP_FETCH_ASSISTANCE_DATA:
g_message("GNSS assistance upload step (%d/%d): "
"fetching assistance data",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
fetch_assistance_data(manager);
break;
@@ -444,8 +455,7 @@ void gnss_step(struct EG25Manager *manager)
if (manager->modem_iface == MODEM_IFACE_MODEMMANAGER) {
g_message("GNSS assistance upload step (%d/%d): "
"disabling GNSS engine through ModemManager",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
disable_mm_gnss(manager);
}
manager->gnss_assistance_step++;
@@ -455,30 +465,26 @@ void gnss_step(struct EG25Manager *manager)
case EG25_GNSS_STEP_AT_GNSS_DISABLE:
g_message("GNSS assistance upload step (%d/%d): "
"disabling GNSS engine through AT+QGPS",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
state_at_gnss(manager);
break;
case EG25_GNSS_STEP_INIT_UPLOAD:
g_message("GNSS assistance upload step (%d/%d): initiating upload",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
init_assistance_data_upload(manager);
break;
case EG25_GNSS_STEP_UPLOAD:
g_message("GNSS assistance upload step (%d/%d): "
"uploading assistance data",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
upload_assistance_data(manager);
break;
case EG25_GNSS_STEP_FINISH_UPLOAD:
g_message("GNSS assistance upload step (%d/%d): finishing upload",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
finish_assistance_data_upload(manager);
break;
@@ -487,8 +493,7 @@ void gnss_step(struct EG25Manager *manager)
if (manager->modem_iface == MODEM_IFACE_MODEMMANAGER) {
g_message("GNSS assistance upload step (%d/%d): "
"re-enabling GNSS through ModemManager",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
enable_mm_gnss(manager);
}
manager->gnss_assistance_step++;
@@ -498,15 +503,13 @@ void gnss_step(struct EG25Manager *manager)
case EG25_GNSS_STEP_AT_QGPS_ENABLE:
g_message("GNSS assistance upload step (%d/%d): "
"re-enabling GNSS through AT+QGPS",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
enable_at_gnss(manager);
break;
case EG25_GNSS_STEP_LAST:
g_message("GNSS assistance upload step (%d/%d): finished",
manager->gnss_assistance_step,
EG25_GNSS_STEP_LAST);
manager->gnss_assistance_step, EG25_GNSS_STEP_LAST);
break;
}
}

View File

@@ -6,9 +6,9 @@
#pragma once
#include <curl/curl.h>
#include <time.h>
#include <unistd.h>
#include <curl/curl.h>
#include "manager.h"

View File

@@ -4,11 +4,9 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "gpio.h"
#include "config.h"
#include "gpio.h"
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
/* Those defines are used for legacy config files only */
@@ -42,78 +40,21 @@ static char *gpio_in_names[] = {
"status",
};
enum gpiod_line_value gpio_line_get_value(struct EG25Manager *manager, int line)
{
enum gpiod_line_value value;
unsigned int offset;
gpiod_line_request_get_requested_offsets(manager->gpio_in[line], &offset, 1);
value = gpiod_line_request_get_value(manager->gpio_in[line], offset);
if (value == GPIOD_LINE_VALUE_ERROR) {
g_warning("gpio: couldn't get value on line %d", line);
}
return value;
}
int gpio_line_set_value(struct EG25Manager *manager, int line, enum gpiod_line_value value)
{
unsigned int offset;
int ret;
gpiod_line_request_get_requested_offsets(manager->gpio_out[line], &offset, 1);
ret = gpiod_line_request_set_value(manager->gpio_out[line], offset, value);
if (ret) {
g_warning("gpio: couldn't set value %d on line %d", value, line);
return -1;
} else {
manager->gpio_out_value[line] = value;
return 0;
}
}
int gpio_sequence_poweron(struct EG25Manager *manager)
{
/*
* Force the modem to poweroff using the RESET_N pin before attempting to
* boot in case the it got into a bad state.
*
* If the modem was on, this will cause it to start booting, so press the
* power button while in reset to avoid a (probably only theoretical) race
* condition where it starts booting after reset, and then powers off from
* the power key.
*/
gpio_line_set_value(manager, GPIO_OUT_RESET, GPIOD_LINE_VALUE_ACTIVE);
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_ACTIVE);
/*
* The datasheet says to pull the pin low for between 150 and 460 ms. usleep
* should always sleep for at least the specified amount of time, so use
* 200ms because it's closer to the bottom of that range.
*/
usleep(200000);
gpio_line_set_value(manager, GPIO_OUT_RESET, GPIOD_LINE_VALUE_INACTIVE);
/*
* The modem has finished it's reset, now we wait to allow it a chance to
* react to the power key
*/
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_PWRKEY], 1);
sleep(1);
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_PWRKEY], 0);
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_INACTIVE);
g_message("Executed power-on sequence");
g_message("Executed power-on/off sequence");
return 0;
}
int gpio_sequence_shutdown(struct EG25Manager *manager)
{
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_ACTIVE);
sleep(1);
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_INACTIVE);
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_DISABLE], 1);
gpio_sequence_poweron(manager);
g_message("Executed power-off sequence");
@@ -122,7 +63,7 @@ int gpio_sequence_shutdown(struct EG25Manager *manager)
int gpio_sequence_suspend(struct EG25Manager *manager)
{
gpio_line_set_value(manager, GPIO_OUT_APREADY, GPIOD_LINE_VALUE_ACTIVE);
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_APREADY], 1);
g_message("Executed suspend sequence");
@@ -131,7 +72,7 @@ int gpio_sequence_suspend(struct EG25Manager *manager)
int gpio_sequence_resume(struct EG25Manager *manager)
{
gpio_line_set_value(manager, GPIO_OUT_APREADY, GPIOD_LINE_VALUE_INACTIVE);
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_APREADY], 0);
g_message("Executed resume sequence");
@@ -140,8 +81,8 @@ int gpio_sequence_resume(struct EG25Manager *manager)
int gpio_sequence_wake(struct EG25Manager *manager)
{
if (manager->gpio_out_value[GPIO_OUT_DTR]) {
gpio_line_set_value(manager, GPIO_OUT_DTR, GPIOD_LINE_VALUE_INACTIVE);
if (gpiod_line_get_value(manager->gpio_out[GPIO_OUT_DTR])) {
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_DTR], 0);
/* Give the modem 200ms to wake from soft sleep */
usleep(200000);
@@ -154,158 +95,42 @@ int gpio_sequence_wake(struct EG25Manager *manager)
int gpio_sequence_sleep(struct EG25Manager *manager)
{
gpio_line_set_value(manager, GPIO_OUT_DTR, GPIOD_LINE_VALUE_ACTIVE);
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_DTR], 1);
g_message("Executed soft sleep sequence");
return 0;
}
struct gpiod_line_request *gpio_request_line(struct EG25Manager *manager,
int chip,
unsigned int line,
enum gpiod_line_direction direction)
struct gpiod_line *gpio_get_output_line(struct EG25Manager *manager, int chip, int line)
{
struct gpiod_line_request *request = NULL;
struct gpiod_line_settings *settings;
struct gpiod_line_config *line_cfg;
struct gpiod_request_config *req_cfg;
int ret;
struct gpiod_line *gpio_line;
settings = gpiod_line_settings_new();
if (!settings)
gpio_line = gpiod_chip_get_line(manager->gpiochip[chip], line);
if (!gpio_line)
return NULL;
gpiod_line_settings_set_direction(settings, direction);
line_cfg = gpiod_line_config_new();
if (!line_cfg)
goto free_settings;
ret = gpiod_line_config_add_line_settings(line_cfg, &line, 1, settings);
if (ret)
goto free_line_config;
req_cfg = gpiod_request_config_new();
if (!req_cfg)
goto free_line_config;
gpiod_request_config_set_consumer(req_cfg, "eg25-manager");
request = gpiod_chip_request_lines(manager->gpiochip[chip], req_cfg, line_cfg);
gpiod_request_config_free(req_cfg);
free_line_config:
gpiod_line_config_free(line_cfg);
free_settings:
gpiod_line_settings_free(settings);
return request;
}
static int gpio_chip_dir_filter(const struct dirent *entry)
{
struct stat sb;
int ret = 0;
char *path;
if (asprintf(&path, "/dev/%s", entry->d_name) < 0)
return 0;
if ((lstat(path, &sb) == 0) && (!S_ISLNK(sb.st_mode)) && gpiod_is_gpiochip_device(path))
ret = 1;
free(path);
return ret;
}
int gpio_all_chip_paths(char ***paths_ptr)
{
int i, j, num_chips, ret = 0;
struct dirent **entries;
char **paths;
num_chips = scandir("/dev/", &entries, gpio_chip_dir_filter, alphasort);
if (num_chips < 0)
g_error("gpio: unable to scan /dev: %s", g_strerror(errno));
paths = calloc(num_chips, sizeof(*paths));
if (paths == NULL)
g_error("gpio: out of memory");
for (i = 0; i < num_chips; i++) {
if (asprintf(&paths[i], "/dev/%s", entries[i]->d_name) < 0) {
for (j = 0; j < i; j++)
free(paths[j]);
free(paths);
return 0;
}
}
*paths_ptr = paths;
ret = num_chips;
for (i = 0; i < num_chips; i++)
free(entries[i]);
free(entries);
return ret;
}
struct gpiod_chip *gpio_chip_open_by_label(const char *label)
{
int num_chips, i;
char **paths = NULL;
const char *clabel;
struct gpiod_chip *chip;
struct gpiod_chip_info *cinfo;
num_chips = gpio_all_chip_paths(&paths);
for (i = 0; i < num_chips; i++) {
chip = gpiod_chip_open(paths[i]);
if (!chip)
continue;
cinfo = gpiod_chip_get_info(chip);
if (!cinfo)
goto clean_chip_open;
clabel = gpiod_chip_info_get_label(cinfo);
if (strcmp(label, clabel) == 0) {
free(paths);
return chip;
}
clean_chip_open:
gpiod_chip_close(chip);
}
if (paths)
free(paths);
if (gpiod_line_request_output(gpio_line, "eg25manager", 0) < 0) {
gpiod_line_release(gpio_line);
return NULL;
}
return gpio_line;
}
unsigned int gpio_chip_num_lines(struct EG25Manager *manager, unsigned int chip_num)
struct gpiod_line *gpio_get_input_line(struct EG25Manager *manager, int chip, int line)
{
struct gpiod_chip *chip = manager->gpiochip[chip_num];
struct gpiod_chip_info *info;
unsigned int num_lines;
struct gpiod_line *gpio_line;
info = gpiod_chip_get_info(chip);
if (!info)
g_error("gpio: failed to read info: %s", strerror(errno));
gpio_line = gpiod_chip_get_line(manager->gpiochip[chip], line);
if (!gpio_line)
return NULL;
num_lines = gpiod_chip_info_get_num_lines(info);
if (gpiod_line_request_input(gpio_line, "eg25manager") < 0) {
gpiod_line_release(gpio_line);
return NULL;
}
gpiod_chip_info_free(info);
return num_lines;
return gpio_line;
}
int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
@@ -330,7 +155,8 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
* format, but error out if user config overrides gpios using the
* old format
*/
if (!gpio_config[EG25_CONFIG_USER] || toml_array_in(gpio_config[EG25_CONFIG_USER], "chips")) {
if (!gpio_config[EG25_CONFIG_USER] || toml_array_in(gpio_config[EG25_CONFIG_USER], "chips"))
{
int numchips;
toml_array_t *chipslist = NULL;
@@ -343,7 +169,7 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
toml_datum_t data = toml_string_at(chipslist, i);
if (!data.ok)
continue;
manager->gpiochip[i] = gpio_chip_open_by_label(data.u.s);
manager->gpiochip[i] = gpiod_chip_open_by_label(data.u.s);
if (!manager->gpiochip[i])
g_error("Unable to find GPIO chip '%s'", data.u.s);
}
@@ -359,13 +185,10 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
g_error("Wrong chip ID for output GPIO '%s'", gpio_out_names[i]);
line = toml_int_in(table, "line");
if (!line.ok || line.u.i < 0 || line.u.i > gpio_chip_num_lines(manager, chip.u.i))
if (!line.ok || line.u.i < 0 || line.u.i > gpiod_chip_num_lines(manager->gpiochip[chip.u.i]))
g_error("Wrong line ID for output GPIO '%s'", gpio_out_names[i]);
manager->gpio_out[i] = gpio_request_line(manager,
chip.u.i,
line.u.i,
GPIOD_LINE_DIRECTION_OUTPUT);
manager->gpio_out[i] = gpio_get_output_line(manager, chip.u.i, line.u.i);
if (!manager->gpio_out[i])
g_error("Unable to get output GPIO %d", i);
}
@@ -373,26 +196,18 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
for (i = 0; i < GPIO_IN_COUNT; i++) {
toml_table_t *table;
toml_datum_t chip, line;
if (!config_get_table(gpio_config, gpio_in_names[i], &table)) {
// BH edition don't have the STATUS line connected, ignore it
if (manager->use_libusb && g_strcmp0(gpio_in_names[i], "status") == 0)
continue;
if (!config_get_table(gpio_config, gpio_in_names[i], &table))
g_error("Unable to get config for input GPIO '%s'", gpio_in_names[i]);
}
chip = toml_int_in(table, "chip");
if (!chip.ok || chip.u.i < 0 || chip.u.i > 2)
g_error("Wrong chip ID for input GPIO '%s'", gpio_in_names[i]);
line = toml_int_in(table, "line");
if (!line.ok || line.u.i < 0 || line.u.i > gpio_chip_num_lines(manager, chip.u.i))
if (!line.ok || line.u.i < 0 || line.u.i > gpiod_chip_num_lines(manager->gpiochip[chip.u.i]))
g_error("Wrong line ID for input GPIO '%s'", gpio_in_names[i]);
manager->gpio_in[i] = gpio_request_line(manager,
chip.u.i,
line.u.i,
GPIOD_LINE_DIRECTION_INPUT);
manager->gpio_in[i] = gpio_get_input_line(manager, chip.u.i, line.u.i);
if (!manager->gpio_in[i])
g_error("Unable to get input GPIO %d", i);
}
@@ -400,11 +215,11 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
guint offset, chipidx, gpio_idx;
/* Legacy config file, only used on the OG PinePhone */
manager->gpiochip[0] = gpio_chip_open_by_label(GPIO_CHIP1_LABEL);
manager->gpiochip[0] = gpiod_chip_open_by_label(GPIO_CHIP1_LABEL);
if (!manager->gpiochip[0])
g_error("Unable to open GPIO chip " GPIO_CHIP1_LABEL);
manager->gpiochip[1] = gpio_chip_open_by_label(GPIO_CHIP2_LABEL);
manager->gpiochip[1] = gpiod_chip_open_by_label(GPIO_CHIP2_LABEL);
if (!manager->gpiochip[1])
g_error("Unable to open GPIO chip " GPIO_CHIP2_LABEL);
@@ -420,10 +235,7 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
chipidx = 1;
}
manager->gpio_out[i] = gpio_request_line(manager,
chipidx,
offset,
GPIOD_LINE_DIRECTION_OUTPUT);
manager->gpio_out[i] = gpio_get_input_line(manager, chipidx, offset);
if (!manager->gpio_out[i])
g_error("Unable to get output GPIO %d", i);
}
@@ -440,10 +252,7 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
chipidx = 1;
}
manager->gpio_in[i] = gpio_request_line(manager,
chipidx,
offset,
GPIOD_LINE_DIRECTION_INPUT);
manager->gpio_in[i] = gpio_get_input_line(manager, chipidx, offset);
if (!manager->gpio_in[i])
g_error("Unable to get input GPIO %d", i);
}
@@ -452,18 +261,16 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
return 0;
}
void gpio_force_off(struct EG25Manager *manager)
{
if (manager->gpio_out[GPIO_OUT_RESET]) {
g_message("Setting the reset pin to ensure the modem stays off");
gpio_line_set_value(manager, GPIO_OUT_RESET, GPIOD_LINE_VALUE_ACTIVE);
}
}
gboolean gpio_check_poweroff(struct EG25Manager *manager)
gboolean gpio_check_poweroff(struct EG25Manager *manager, gboolean keep_down)
{
if (manager->gpio_in[GPIO_IN_STATUS] &&
gpio_line_get_value(manager, GPIO_IN_STATUS) == GPIOD_LINE_VALUE_ACTIVE) {
gpiod_line_get_value(manager->gpio_in[GPIO_IN_STATUS]) == 1) {
if (keep_down && manager->gpio_out[GPIO_OUT_RESET]) {
// Asserting RESET line to prevent modem from rebooting
gpiod_line_set_value(manager->gpio_out[GPIO_OUT_RESET], 1);
}
return TRUE;
}
@@ -476,12 +283,12 @@ void gpio_destroy(struct EG25Manager *manager)
for (i = 0; i < GPIO_OUT_COUNT; i++) {
if (manager->gpio_out[i])
gpiod_line_request_release(manager->gpio_out[i]);
gpiod_line_release(manager->gpio_out[i]);
}
for (i = 0; i < GPIO_IN_COUNT; i++) {
if (manager->gpio_in[i])
gpiod_line_request_release(manager->gpio_in[i]);
gpiod_line_release(manager->gpio_in[i]);
}
if (manager->gpiochip[0])

View File

@@ -18,5 +18,4 @@ int gpio_sequence_resume(struct EG25Manager *state);
int gpio_sequence_wake(struct EG25Manager *state);
int gpio_sequence_sleep(struct EG25Manager *state);
void gpio_force_off(struct EG25Manager *manager);
gboolean gpio_check_poweroff(struct EG25Manager *manager);
gboolean gpio_check_poweroff(struct EG25Manager *manager, gboolean keep_down);

View File

@@ -4,19 +4,19 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "manager.h"
#include "at.h"
#include "config.h"
#include "gpio.h"
#include "manager.h"
#ifdef HAVE_MMGLIB
#include "mm-iface.h"
#endif
#include "gnss.h"
#include "ofono-iface.h"
#include "suspend.h"
#include "udev.h"
#include "gnss.h"
#include <fcntl.h>
#include <signal.h>
@@ -38,9 +38,6 @@
#define EG25_VERSION "0.0.0"
#endif
#define EG25_DEFAULT_VENDOR_ID 0x2c7c
#define EG25_DEFAULT_PRODUCT_ID 0x0125
#define POWERON_DELAY_US 100000UL
static gboolean quit_app(struct EG25Manager *manager)
@@ -62,17 +59,13 @@ static gboolean quit_app(struct EG25Manager *manager)
gpio_sequence_shutdown(manager);
manager->modem_state = EG25_STATE_FINISHING;
for (i = 0; i < 30; i++) {
if (gpio_check_poweroff(manager)) {
g_message("Modem successfully powered down");
if (gpio_check_poweroff(manager, TRUE))
break;
}
sleep(1);
}
}
gpio_force_off(manager);
g_message("Modem down, quitting...");
g_main_loop_quit(manager->loop);
return FALSE;
@@ -102,7 +95,7 @@ static gboolean modem_start(struct EG25Manager *manager)
libusb_free_device_list(devices, 1);
libusb_exit(ctx);
} else if (!gpio_check_poweroff(manager)) {
} else if (!gpio_check_poweroff(manager, FALSE)) {
g_message("STATUS is low, modem already powered");
should_boot = FALSE;
}
@@ -145,40 +138,10 @@ void modem_configure(struct EG25Manager *manager)
at_sequence_configure(manager);
}
static gboolean modem_gpio_reset_done(struct EG25Manager *manager)
{
gpio_sequence_poweron(manager);
manager->modem_state = EG25_STATE_POWERED;
manager->complete_reset_timer = 0;
return G_SOURCE_REMOVE;
}
static gboolean modem_at_reset_done(struct EG25Manager *manager)
{
/*
* If the modem was successfully rebooted, then we should have received
* "RDY" by now which will transition the state to started.
*/
if (manager->modem_state != EG25_STATE_RESETTING) {
manager->complete_reset_timer = 0;
return G_SOURCE_REMOVE;
}
g_message("AT reset failed, falling back to GPIO reset");
gpio_sequence_shutdown(manager);
manager->complete_reset_timer = g_timeout_add_seconds(30,
G_SOURCE_FUNC(modem_gpio_reset_done),
manager);
return G_SOURCE_REMOVE;
}
static gboolean modem_rebind_done(struct EG25Manager *manager)
static gboolean modem_reset_done(struct EG25Manager* manager)
{
manager->modem_state = EG25_STATE_RESUMING;
manager->complete_reset_timer = 0;
manager->reset_timer = 0;
return FALSE;
}
@@ -186,18 +149,7 @@ gboolean modem_reset(struct EG25Manager *manager)
{
int fd, ret, len;
/* reset sequence started, cannot be canceled anymore */
if (manager->schedule_reset_timer) {
g_source_remove(manager->schedule_reset_timer);
manager->schedule_reset_timer = 0;
}
if (manager->modem_recovery_timer) {
g_source_remove(manager->modem_recovery_timer);
manager->modem_recovery_timer = 0;
}
if (manager->complete_reset_timer) {
if (manager->reset_timer) {
g_message("modem_reset: timer already setup, skipping...");
return G_SOURCE_REMOVE;
}
@@ -212,6 +164,11 @@ gboolean modem_reset(struct EG25Manager *manager)
return G_SOURCE_REMOVE;
}
if (manager->modem_recovery_timer) {
g_source_remove(manager->modem_recovery_timer);
manager->modem_recovery_timer = 0;
}
if (!manager->modem_usb_id) {
g_warning("Empty modem USB ID");
goto error;
@@ -228,26 +185,24 @@ gboolean modem_reset(struct EG25Manager *manager)
g_warning("Unable to open /sys/bus/usb/drivers/usb/unbind");
goto error;
}
ret = write(fd, manager->modem_usb_id, len);
close(fd);
if (ret < len) {
g_warning("Couldn't unbind modem: wrote %d/%d bytes", ret, len);
goto error;
}
close(fd);
fd = open("/sys/bus/usb/drivers/usb/bind", O_WRONLY);
if (fd < 0) {
g_warning("Unable to open /sys/bus/usb/drivers/usb/bind");
g_warning("Unable to open /sys/bus/usb/drivers/usb/unbind");
goto error;
}
ret = write(fd, manager->modem_usb_id, len);
close(fd);
if (ret < len) {
g_warning("Couldn't bind modem: wrote %d/%d bytes", ret, len);
goto error;
}
close(fd);
g_message("Successfully reset modem's USB connection");
@@ -255,7 +210,7 @@ gboolean modem_reset(struct EG25Manager *manager)
* 3s is long enough to make sure the modem has been bound back and
* short enough to ensure it hasn't been acquired by ModemManager
*/
manager->complete_reset_timer = g_timeout_add_seconds(3, G_SOURCE_FUNC(modem_rebind_done), manager);
manager->reset_timer = g_timeout_add_seconds(3, G_SOURCE_FUNC(modem_reset_done), manager);
return G_SOURCE_REMOVE;
@@ -273,9 +228,7 @@ error:
at_sequence_reset(manager);
// Setup timer for making sure we don't queue other reset commands
manager->complete_reset_timer = g_timeout_add_seconds(45,
G_SOURCE_FUNC(modem_at_reset_done),
manager);
manager->reset_timer = g_timeout_add_seconds(30, G_SOURCE_FUNC(modem_reset_done), manager);
return G_SOURCE_REMOVE;
}
@@ -313,7 +266,7 @@ static toml_table_t *parse_config_file(char *config_file, gboolean force_default
if (config_file) {
f = fopen(config_file, "r");
} else if (g_file_get_contents("/proc/device-tree/compatible", &compatible, &len, NULL)) {
g_autoptr(GPtrArray) compat = g_ptr_array_new();
g_autoptr (GPtrArray) compat = g_ptr_array_new();
gsize pos = 0;
/*
@@ -328,11 +281,9 @@ static toml_table_t *parse_config_file(char *config_file, gboolean force_default
for (pos = 0; pos < compat->len; pos++) {
g_autofree gchar *filename = NULL;
if (force_default)
filename = g_strdup_printf(EG25_DATADIR "/%s.toml",
(gchar *)g_ptr_array_index(compat, pos));
filename = g_strdup_printf(EG25_DATADIR "/%s.toml", (gchar *)g_ptr_array_index(compat, pos));
else
filename = g_strdup_printf(EG25_CONFDIR "/%s.toml",
(gchar *)g_ptr_array_index(compat, pos));
filename = g_strdup_printf(EG25_CONFDIR "/%s.toml", (gchar *)g_ptr_array_index(compat, pos));
if (access(filename, F_OK) == 0) {
g_message("Opening config file: %s", filename);
@@ -363,13 +314,12 @@ int main(int argc, char *argv[])
struct EG25Manager manager;
gchar *config_file = NULL;
gboolean show_version = FALSE;
gboolean monitor_udev = TRUE;
toml_table_t *toml_config[EG25_CONFIG_COUNT];
toml_table_t *manager_config[EG25_CONFIG_COUNT];
const GOptionEntry options[] = {
{"config", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Config file to use.", NULL},
{"version", 'v', 0, G_OPTION_ARG_NONE, &show_version, "Display version information and exit.", NULL},
{NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}
{ "config", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Config file to use.", NULL },
{ "version", 'v', 0, G_OPTION_ARG_NONE, &show_version, "Display version information and exit.", NULL },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
};
memset(&manager, 0, sizeof(manager));
@@ -378,10 +328,10 @@ int main(int argc, char *argv[])
manager.suspend_delay_fd = -1;
manager.suspend_block_fd = -1;
opt_context = g_option_context_new("- Power management for the Quectel EG25 modem");
g_option_context_add_main_entries(opt_context, options, NULL);
if (!g_option_context_parse(opt_context, &argc, &argv, &err)) {
g_warning("%s", err->message);
opt_context = g_option_context_new ("- Power management for the Quectel EG25 modem");
g_option_context_add_main_entries (opt_context, options, NULL);
if (!g_option_context_parse (opt_context, &argc, &argv, &err)) {
g_warning ("%s", err->message);
return 1;
}
@@ -413,13 +363,10 @@ int main(int argc, char *argv[])
if (!manager_config[EG25_CONFIG_SYS])
g_error("Default config file lacks the 'manager' section!");
config_get_bool(manager_config, "monitor_udev", &monitor_udev);
config_get_bool(manager_config, "need_libusb", &manager.use_libusb);
config_get_uint(manager_config, "usb_vid", &manager.usb_vid);
config_get_uint(manager_config, "usb_pid", &manager.usb_pid);
config_get_uint(manager_config, "poweron_delay", &manager.poweron_delay);
if (!config_get_uint(manager_config, "usb_vid", &manager.usb_vid))
manager.usb_vid = EG25_DEFAULT_VENDOR_ID;
if (!config_get_uint(manager_config, "usb_pid", &manager.usb_pid))
manager.usb_pid = EG25_DEFAULT_PRODUCT_ID;
at_init(&manager, toml_config);
gpio_init(&manager, toml_config);
@@ -428,7 +375,6 @@ int main(int argc, char *argv[])
#endif
ofono_iface_init(&manager, toml_config);
suspend_init(&manager, toml_config);
if (monitor_udev)
udev_init(&manager, toml_config);
gnss_init(&manager, toml_config);

View File

@@ -41,6 +41,7 @@ typedef enum {
EG25_GNSS_SOURCE_QGPS = 1 << 3,
} EG25GNSSSource;
enum EG25State {
EG25_STATE_INIT = 0,
EG25_STATE_POWERED, // Power-on sequence has been executed, but the modem isn't on yet
@@ -52,7 +53,6 @@ enum EG25State {
EG25_STATE_SUSPENDING, // System is going into suspend
EG25_STATE_RESUMING, // System is being resumed, waiting for modem to come back
EG25_STATE_RESETTING, // Something went wrong, we're restarting the modem
EG25_STATE_UPDATING, // Modem is present but being updated
EG25_STATE_FINISHING
};
@@ -70,8 +70,7 @@ enum EG25Config {
struct EG25Manager {
GMainLoop *loop;
guint complete_reset_timer;
guint schedule_reset_timer;
guint reset_timer;
gboolean use_libusb;
guint usb_vid;
guint usb_pid;
@@ -115,9 +114,8 @@ struct EG25Manager {
GUdevClient *udev;
struct gpiod_chip *gpiochip[2];
struct gpiod_line_request *gpio_out[5];
guint gpio_out_value[5];
struct gpiod_line_request *gpio_in[2];
struct gpiod_line *gpio_out[5];
struct gpiod_line *gpio_in[2];
};
void modem_configure(struct EG25Manager *data);

View File

@@ -25,7 +25,7 @@ if mmglib_dep.found()
endif
executable (
'eg25-manager',
'eg25manager',
src,
dependencies : mgr_deps,
link_with: gdbofono_lib,

View File

@@ -30,7 +30,7 @@ static void add_modem(struct EG25Manager *manager, GDBusObject *object)
path = g_dbus_object_get_object_path(object);
g_message("Adding new modem `%s'", path);
g_assert(MM_IS_OBJECT(object));
g_assert(MM_IS_OBJECT (object));
manager->mm_modem = mm_object_get_modem(MM_OBJECT(object));
g_assert_nonnull(manager->mm_modem);
@@ -70,7 +70,7 @@ static void add_modem_location(struct EG25Manager *manager, GDBusObject *object)
g_assert_nonnull(manager->mm_location);
}
static void interface_added_cb(struct EG25Manager *manager,
static void interface_added_cb (struct EG25Manager *manager,
GDBusObject *object,
GDBusInterface *interface)
{
@@ -78,8 +78,7 @@ static void interface_added_cb(struct EG25Manager *manager,
info = g_dbus_interface_get_info(interface);
g_message("ModemManager interface `%s' found on object `%s'",
info->name,
g_dbus_object_get_object_path(object));
info->name, g_dbus_object_get_object_path(object));
if (g_strcmp0(info->name, MM_DBUS_INTERFACE_MODEM) == 0)
add_modem(manager, object);
@@ -88,6 +87,7 @@ static void interface_added_cb(struct EG25Manager *manager,
add_modem_location(manager, object);
}
static void interface_removed_cb(struct EG25Manager *manager,
GDBusObject *object,
GDBusInterface *interface)
@@ -104,6 +104,7 @@ static void interface_removed_cb(struct EG25Manager *manager,
manager->mm_modem = NULL;
}
static void add_mm_object(struct EG25Manager *manager, GDBusObject *object)
{
GList *ifaces, *node;
@@ -115,6 +116,7 @@ static void add_mm_object(struct EG25Manager *manager, GDBusObject *object)
g_list_free_full(ifaces, g_object_unref);
}
static void add_mm_objects(struct EG25Manager *manager)
{
GList *objects, *node;
@@ -126,12 +128,14 @@ static void add_mm_objects(struct EG25Manager *manager)
g_list_free_full(objects, g_object_unref);
}
static void object_added_cb(struct EG25Manager *manager, GDBusObject *object)
{
g_message("ModemManager object `%s' added", g_dbus_object_get_object_path(object));
add_mm_object(manager, object);
}
static void object_removed_cb(struct EG25Manager *manager, GDBusObject *object)
{
const gchar *path;
@@ -142,32 +146,25 @@ static void object_removed_cb(struct EG25Manager *manager, GDBusObject *object)
manager->mm_modem = NULL;
}
static void mm_manager_new_cb(GDBusConnection *connection,
GAsyncResult *res,
struct EG25Manager *manager)
{
g_autoptr(GError) error = NULL;
g_autoptr (GError) error = NULL;
manager->mm_manager = mm_manager_new_finish(res, &error);
if (!manager->mm_manager)
g_critical("Error creating ModemManager Manager: %s", error->message);
g_signal_connect_swapped(G_DBUS_OBJECT_MANAGER(manager->mm_manager),
"interface-added",
G_CALLBACK(interface_added_cb),
manager);
"interface-added", G_CALLBACK(interface_added_cb), manager);
g_signal_connect_swapped(G_DBUS_OBJECT_MANAGER(manager->mm_manager),
"interface-removed",
G_CALLBACK(interface_removed_cb),
manager);
"interface-removed", G_CALLBACK(interface_removed_cb), manager);
g_signal_connect_swapped(G_DBUS_OBJECT_MANAGER(manager->mm_manager),
"object-added",
G_CALLBACK(object_added_cb),
manager);
"object-added", G_CALLBACK(object_added_cb), manager);
g_signal_connect_swapped(G_DBUS_OBJECT_MANAGER(manager->mm_manager),
"object-removed",
G_CALLBACK(object_removed_cb),
manager);
"object-removed", G_CALLBACK(object_removed_cb), manager);
add_mm_objects(manager);
}
@@ -180,18 +177,13 @@ static void mm_appeared_cb(GDBusConnection *connection,
g_message("ModemManager appeared on D-Bus");
if (manager->modem_iface != MODEM_IFACE_NONE) {
g_critical("Modem interface already found! Make sure to only run either of "
"ModemManager or "
"oFono.");
g_critical("Modem interface already found! Make sure to only run either of ModemManager or oFono.");
return;
}
manager->modem_iface = MODEM_IFACE_MODEMMANAGER;
mm_manager_new(connection,
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
NULL,
(GAsyncReadyCallback)mm_manager_new_cb,
manager);
mm_manager_new(connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
NULL, (GAsyncReadyCallback)mm_manager_new_cb, manager);
}
static void mm_iface_clean(struct EG25Manager *manager)
@@ -209,7 +201,9 @@ static void mm_iface_clean(struct EG25Manager *manager)
}
}
static void mm_vanished_cb(GDBusConnection *connection, const gchar *name, struct EG25Manager *manager)
static void mm_vanished_cb(GDBusConnection *connection,
const gchar *name,
struct EG25Manager *manager)
{
g_message("ModemManager vanished from D-Bus");
mm_iface_clean(manager);
@@ -217,13 +211,11 @@ static void mm_vanished_cb(GDBusConnection *connection, const gchar *name, struc
void mm_iface_init(struct EG25Manager *manager, toml_table_t *config[])
{
manager->mm_watch = g_bus_watch_name(G_BUS_TYPE_SYSTEM,
MM_DBUS_SERVICE,
manager->mm_watch = g_bus_watch_name(G_BUS_TYPE_SYSTEM, MM_DBUS_SERVICE,
G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
(GBusNameAppearedCallback)mm_appeared_cb,
(GBusNameVanishedCallback)mm_vanished_cb,
manager,
NULL);
manager, NULL);
}
void mm_iface_destroy(struct EG25Manager *manager)

View File

@@ -43,11 +43,15 @@ static void modem_added_cb(GDBOManager *manager_proxy,
manager->modem_usb_id = g_strdup(strrchr(g_variant_dup_string(modem_path, NULL), '/') + 1);
}
static void modem_removed_cb(GDBOManager *manager_proxy, const gchar *path, struct EG25Manager *manager)
static void modem_removed_cb(GDBOManager *manager_proxy,
const gchar *path,
struct EG25Manager *manager)
{
}
static void get_modems_cb(GDBOManager *manager_proxy, GAsyncResult *res, struct EG25Manager *manager)
static void get_modems_cb(GDBOManager *manager_proxy,
GAsyncResult *res,
struct EG25Manager *manager)
{
gboolean ok;
GVariant *modems;
@@ -57,14 +61,15 @@ static void get_modems_cb(GDBOManager *manager_proxy, GAsyncResult *res, struct
const gchar *path;
GVariant *properties;
ok = gdbo_manager_call_get_modems_finish(manager_proxy, &modems, res, &error);
ok = gdbo_manager_call_get_modems_finish(manager_proxy, &modems,
res, &error);
if (!ok) {
g_warning("Error getting modems from ofono manager: %s", error->message);
return;
}
g_variant_get(modems, "a(oa{sv})", &modems_iter);
while (g_variant_iter_loop(modems_iter, "(&o@a{sv})", &path, &properties)) {
while(g_variant_iter_loop(modems_iter, "(&o@a{sv})", &path, &properties)) {
g_debug("Got modem object path '%s'", path);
modem_added_cb(manager_proxy, path, properties, manager);
}
@@ -82,9 +87,7 @@ static void ofono_appeared_cb(GDBusConnection *connection,
g_message("oFono appeared on D-Bus");
if (manager->modem_iface != MODEM_IFACE_NONE) {
g_critical("Modem interface already found! Make sure to only run either of "
"ModemManager or "
"oFono.");
g_critical("Modem interface already found! Make sure to only run either of ModemManager or oFono.");
return;
}
/* now connect to oFono! */
@@ -102,12 +105,14 @@ static void ofono_appeared_cb(GDBusConnection *connection,
manager->modem_iface = MODEM_IFACE_OFONO;
g_signal_connect(manager->ofono_manager, "modem-added", G_CALLBACK(modem_added_cb), manager);
g_signal_connect(manager->ofono_manager, "modem-removed", G_CALLBACK(modem_removed_cb), manager);
g_signal_connect(manager->ofono_manager, "modem-added",
G_CALLBACK(modem_added_cb), manager);
g_signal_connect(manager->ofono_manager, "modem-removed",
G_CALLBACK(modem_removed_cb), manager);
gdbo_manager_call_get_modems(manager->ofono_manager,
NULL,
(GAsyncReadyCallback)get_modems_cb,
(GAsyncReadyCallback) get_modems_cb,
manager);
}
@@ -125,13 +130,11 @@ static void ofono_vanished_cb(GDBusConnection *connection,
void ofono_iface_init(struct EG25Manager *manager, toml_table_t *config[])
{
manager->ofono_watch = g_bus_watch_name(G_BUS_TYPE_SYSTEM,
OFONO_SERVICE,
manager->ofono_watch = g_bus_watch_name(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
(GBusNameAppearedCallback)ofono_appeared_cb,
(GBusNameVanishedCallback)ofono_vanished_cb,
manager,
NULL);
manager, NULL);
}
void ofono_iface_destroy(struct EG25Manager *manager)

View File

@@ -18,24 +18,10 @@
#define SD_PATH "/org/freedesktop/login1"
#define SD_INTERFACE "org.freedesktop.login1.Manager"
static void resume_ok(struct EG25Manager *manager)
{
manager->modem_state = EG25_STATE_CONFIGURED;
modem_resume_post(manager);
}
static gboolean check_modem_resume(struct EG25Manager *manager)
{
manager->modem_recovery_timer = 0;
#ifdef HAVE_MMGLIB
if (manager->mm_modem) {
resume_ok(manager);
return FALSE;
}
#endif
g_message("Modem wasn't probed in time, restart it!");
manager->modem_recovery_timer = 0;
modem_reset(manager);
return FALSE;
@@ -50,7 +36,8 @@ static gboolean drop_inhibitor(struct EG25Manager *manager, gboolean block)
manager->suspend_block_fd = -1;
return TRUE;
}
} else {
}
else {
if (manager->suspend_delay_fd >= 0) {
g_message("dropping systemd sleep delay inhibitor");
close(manager->suspend_delay_fd);
@@ -61,15 +48,18 @@ static gboolean drop_inhibitor(struct EG25Manager *manager, gboolean block)
return FALSE;
}
static void inhibit_done_delay(GObject *source, GAsyncResult *result, gpointer user_data)
static void inhibit_done_delay(GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GDBusProxy *suspend_proxy = G_DBUS_PROXY(source);
struct EG25Manager *manager = user_data;
g_autoptr(GError) error = NULL;
g_autoptr (GError) error = NULL;
GVariant *res;
GUnixFDList *fd_list;
res = g_dbus_proxy_call_with_unix_fd_list_finish(suspend_proxy, &fd_list, result, &error);
res = g_dbus_proxy_call_with_unix_fd_list_finish(suspend_proxy, &fd_list,
result, &error);
if (!res) {
g_warning("inhibit failed: %s", error->message);
} else {
@@ -84,15 +74,18 @@ static void inhibit_done_delay(GObject *source, GAsyncResult *result, gpointer u
}
}
static void inhibit_done_block(GObject *source, GAsyncResult *result, gpointer user_data)
static void inhibit_done_block(GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GDBusProxy *suspend_proxy = G_DBUS_PROXY(source);
struct EG25Manager *manager = user_data;
g_autoptr(GError) error = NULL;
g_autoptr (GError) error = NULL;
GVariant *res;
GUnixFDList *fd_list;
res = g_dbus_proxy_call_with_unix_fd_list_finish(suspend_proxy, &fd_list, result, &error);
res = g_dbus_proxy_call_with_unix_fd_list_finish(suspend_proxy, &fd_list,
result, &error);
if (!res) {
g_warning("inhibit failed: %s", error->message);
} else {
@@ -126,48 +119,33 @@ static void take_inhibitor(struct EG25Manager *manager, gboolean block)
GVariant *variant_arg;
if (block) {
if (manager->suspend_block_fd != -1)
if(manager->suspend_block_fd != -1)
drop_inhibitor(manager, TRUE);
variant_arg = g_variant_new("(ssss)",
"sleep",
"eg25manager",
variant_arg = g_variant_new ("(ssss)", "sleep", "eg25manager",
"eg25manager needs to wait for modem to be fully booted",
"block");
g_message("taking systemd sleep inhibitor (blocking)");
g_dbus_proxy_call_with_unix_fd_list(manager->suspend_proxy,
"Inhibit",
variant_arg,
0,
G_MAXINT,
NULL,
NULL,
inhibit_done_block,
manager);
g_dbus_proxy_call_with_unix_fd_list(manager->suspend_proxy, "Inhibit",
variant_arg, 0, G_MAXINT, NULL, NULL,
inhibit_done_block, manager);
manager->modem_boot_timer = g_timeout_add_seconds(manager->modem_boot_timeout,
G_SOURCE_FUNC(modem_fully_booted),
manager);
} else {
if (manager->suspend_delay_fd != -1)
}
else {
if(manager->suspend_delay_fd != -1)
drop_inhibitor(manager, FALSE);
variant_arg = g_variant_new("(ssss)",
"sleep",
"eg25manager",
variant_arg = g_variant_new ("(ssss)", "sleep", "eg25manager",
"eg25manager needs to prepare modem for sleep",
"delay");
g_message("taking systemd sleep inhibitor");
g_dbus_proxy_call_with_unix_fd_list(manager->suspend_proxy,
"Inhibit",
variant_arg,
0,
G_MAXINT,
NULL,
NULL,
inhibit_done_delay,
manager);
g_dbus_proxy_call_with_unix_fd_list(manager->suspend_proxy, "Inhibit",
variant_arg, 0, G_MAXINT, NULL, NULL,
inhibit_done_delay, manager);
}
}
@@ -206,7 +184,8 @@ static void signal_cb(GDBusProxy *proxy,
* If modem is managed by ofono, we also do resume sequence immediately
* as ofono handles resuming from sleep itself.
*/
resume_ok(manager);
manager->modem_state = EG25_STATE_CONFIGURED;
modem_resume_post(manager);
} else {
manager->modem_state = EG25_STATE_RESUMING;
manager->modem_recovery_timer = g_timeout_add_seconds(manager->modem_recovery_timeout,
@@ -216,7 +195,9 @@ static void signal_cb(GDBusProxy *proxy,
}
}
static void name_owner_cb(GObject *object, GParamSpec *pspec, gpointer user_data)
static void name_owner_cb(GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
GDBusProxy *proxy = G_DBUS_PROXY(object);
struct EG25Manager *manager = user_data;
@@ -233,9 +214,11 @@ static void name_owner_cb(GObject *object, GParamSpec *pspec, gpointer user_data
}
}
static void on_proxy_acquired(GObject *object, GAsyncResult *res, struct EG25Manager *manager)
static void on_proxy_acquired(GObject *object,
GAsyncResult *res,
struct EG25Manager *manager)
{
g_autoptr(GError) error = NULL;
g_autoptr (GError) error = NULL;
char *owner;
manager->suspend_proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
@@ -244,8 +227,10 @@ static void on_proxy_acquired(GObject *object, GAsyncResult *res, struct EG25Man
return;
}
g_signal_connect(manager->suspend_proxy, "notify::g-name-owner", G_CALLBACK(name_owner_cb), manager);
g_signal_connect(manager->suspend_proxy, "g-signal", G_CALLBACK(signal_cb), manager);
g_signal_connect(manager->suspend_proxy, "notify::g-name-owner",
G_CALLBACK(name_owner_cb), manager);
g_signal_connect(manager->suspend_proxy, "g-signal",
G_CALLBACK(signal_cb), manager);
owner = g_dbus_proxy_get_name_owner(manager->suspend_proxy);
if (owner) {
@@ -282,16 +267,10 @@ void suspend_init(struct EG25Manager *manager, toml_table_t *config[])
manager->modem_recovery_timeout = 9;
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM,
// NOLINTNEXTLINE Flags combination is valid even if not matching an enum entry
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL,
SD_NAME,
SD_PATH,
SD_INTERFACE,
NULL,
(GAsyncReadyCallback)on_proxy_acquired,
manager);
NULL, SD_NAME, SD_PATH, SD_INTERFACE, NULL,
(GAsyncReadyCallback)on_proxy_acquired, manager);
}
void suspend_destroy(struct EG25Manager *manager)

View File

@@ -8,7 +8,7 @@
#include "manager.h"
void suspend_init(struct EG25Manager *data, toml_table_t *config[]);
void suspend_destroy(struct EG25Manager *data);
void suspend_init (struct EG25Manager *data, toml_table_t *config[]);
void suspend_destroy (struct EG25Manager *data);
void suspend_inhibit(struct EG25Manager *data, gboolean inhibit, gboolean block);
void suspend_inhibit (struct EG25Manager *data, gboolean inhibit, gboolean block);

1124
src/toml.c

File diff suppressed because it is too large Load Diff

View File

@@ -25,8 +25,10 @@
#ifndef TOML_H
#define TOML_H
#include <stdint.h>
#include <stdio.h>
#include <stdint.h>
#ifdef __cplusplus
#define TOML_EXTERN extern "C"
@@ -42,21 +44,24 @@ typedef struct toml_datum_t toml_datum_t;
/* Parse a file. Return a table on success, or 0 otherwise.
* Caller must toml_free(the-return-value) after use.
*/
TOML_EXTERN toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz);
TOML_EXTERN toml_table_t* toml_parse_file(FILE* fp,
char* errbuf,
int errbufsz);
/* Parse a string containing the full config.
* Return a table on success, or 0 otherwise.
* Caller must toml_free(the-return-value) after use.
*/
TOML_EXTERN toml_table_t *toml_parse(char *conf, /* NUL terminated, please. */
char *errbuf,
TOML_EXTERN toml_table_t* toml_parse(char* conf, /* NUL terminated, please. */
char* errbuf,
int errbufsz);
/* Free the table returned by toml_parse() or toml_parse_file(). Once
* this function is called, any handles accessed through this tab
* directly or indirectly are no longer valid.
*/
TOML_EXTERN void toml_free(toml_table_t *tab);
TOML_EXTERN void toml_free(toml_table_t* tab);
/* Timestamp types. The year, month, day, hour, minute, second, z
* fields may be NULL if they are not relevant. e.g. In a DATE
@@ -70,17 +75,18 @@ struct toml_timestamp_t {
} __buffer;
int *year, *month, *day;
int *hour, *minute, *second, *millisec;
char *z;
char* z;
};
/*-----------------------------------------------------------------
* Enhanced access methods
*/
struct toml_datum_t {
int ok;
union {
toml_timestamp_t *ts; /* ts must be freed after use */
char *s; /* string value. s must be freed after use */
toml_timestamp_t* ts; /* ts must be freed after use */
char* s; /* string value. s must be freed after use */
int b; /* bool value */
int64_t i; /* int value */
double d; /* double value */
@@ -89,76 +95,81 @@ struct toml_datum_t {
/* on arrays: */
/* ... retrieve size of array. */
TOML_EXTERN int toml_array_nelem(const toml_array_t *arr);
TOML_EXTERN int toml_array_nelem(const toml_array_t* arr);
/* ... retrieve values using index. */
TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t* arr, int idx);
/* ... retrieve array or table using index. */
TOML_EXTERN toml_array_t *toml_array_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_table_t *toml_table_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_array_t* toml_array_at(const toml_array_t* arr, int idx);
TOML_EXTERN toml_table_t* toml_table_at(const toml_array_t* arr, int idx);
/* on tables: */
/* ... retrieve the key in table at keyidx. Return 0 if out of range. */
TOML_EXTERN const char *toml_key_in(const toml_table_t *tab, int keyidx);
TOML_EXTERN const char* toml_key_in(const toml_table_t* tab, int keyidx);
/* ... retrieve values using key. */
TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t *arr, const char *key);
TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key);
TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t *arr, const char *key);
TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t *arr, const char *key);
TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t *arr, const char *key);
TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t* arr, const char* key);
TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t* arr, const char* key);
TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t* arr, const char* key);
TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t* arr, const char* key);
TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t* arr, const char* key);
/* .. retrieve array or table using key. */
TOML_EXTERN toml_array_t *toml_array_in(const toml_table_t *tab, const char *key);
TOML_EXTERN toml_table_t *toml_table_in(const toml_table_t *tab, const char *key);
TOML_EXTERN toml_array_t* toml_array_in(const toml_table_t* tab,
const char* key);
TOML_EXTERN toml_table_t* toml_table_in(const toml_table_t* tab,
const char* key);
/*-----------------------------------------------------------------
* lesser used
*/
/* Return the array kind: 't'able, 'a'rray, 'v'alue */
TOML_EXTERN char toml_array_kind(const toml_array_t *arr);
TOML_EXTERN char toml_array_kind(const toml_array_t* arr);
/* For array kind 'v'alue, return the type of values
i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp
0 if unknown
*/
TOML_EXTERN char toml_array_type(const toml_array_t *arr);
TOML_EXTERN char toml_array_type(const toml_array_t* arr);
/* Return the key of an array */
TOML_EXTERN const char *toml_array_key(const toml_array_t *arr);
TOML_EXTERN const char* toml_array_key(const toml_array_t* arr);
/* Return the number of key-values in a table */
TOML_EXTERN int toml_table_nkval(const toml_table_t *tab);
TOML_EXTERN int toml_table_nkval(const toml_table_t* tab);
/* Return the number of arrays in a table */
TOML_EXTERN int toml_table_narr(const toml_table_t *tab);
TOML_EXTERN int toml_table_narr(const toml_table_t* tab);
/* Return the number of sub-tables in a table */
TOML_EXTERN int toml_table_ntab(const toml_table_t *tab);
TOML_EXTERN int toml_table_ntab(const toml_table_t* tab);
/* Return the key of a table*/
TOML_EXTERN const char *toml_table_key(const toml_table_t *tab);
TOML_EXTERN const char* toml_table_key(const toml_table_t* tab);
/*--------------------------------------------------------------
* misc
*/
TOML_EXTERN int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret);
TOML_EXTERN int toml_utf8_to_ucs(const char* orig, int len, int64_t* ret);
TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]);
TOML_EXTERN void toml_set_memutil(void *(*xxmalloc)(size_t), void (*xxfree)(void *));
TOML_EXTERN void toml_set_memutil(void* (*xxmalloc)(size_t),
void (*xxfree)(void*));
/*--------------------------------------------------------------
* deprecated
*/
/* A raw value, must be processed by toml_rto* before using. */
typedef const char *toml_raw_t;
TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key);
TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t *arr, int idx);
TOML_EXTERN int toml_rtos(toml_raw_t s, char **ret);
TOML_EXTERN int toml_rtob(toml_raw_t s, int *ret);
TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t *ret);
TOML_EXTERN int toml_rtod(toml_raw_t s, double *ret);
TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double *ret, char *buf, int buflen);
TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t *ret);
typedef const char* toml_raw_t;
TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t* tab, const char* key);
TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t* arr, int idx);
TOML_EXTERN int toml_rtos(toml_raw_t s, char** ret);
TOML_EXTERN int toml_rtob(toml_raw_t s, int* ret);
TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t* ret);
TOML_EXTERN int toml_rtod(toml_raw_t s, double* ret);
TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double* ret, char* buf, int buflen);
TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t* ret);
#endif /* TOML_H */

View File

@@ -11,49 +11,23 @@
static void udev_event_cb(GUdevClient *client, gchar *action, GUdevDevice *device, gpointer data)
{
struct EG25Manager *manager = data;
const gchar *prop;
long vid = 0, pid = 0;
/*
* Act only if the device is the one identified as a modem by MM/ofono
*/
if (!manager->modem_usb_id || strcmp(g_udev_device_get_name(device), manager->modem_usb_id) != 0) {
return;
}
prop = g_udev_device_get_property(device, "ID_VENDOR_ID");
if (prop)
vid = strtol(prop, NULL, 16);
prop = g_udev_device_get_property(device, "ID_MODEL_ID");
if (prop)
pid = strtol(prop, NULL, 16);
if (strcmp(action, "bind") == 0 && vid != manager->usb_vid && pid != manager->usb_pid) {
/*
* Modem is probably executing a FW upgrade, make sure we don't interrupt it
*/
if (manager->schedule_reset_timer != 0) {
g_message("Modem re-appeared with different VID/PID, cancel reset.");
g_source_remove(manager->schedule_reset_timer);
manager->schedule_reset_timer = 0;
}
manager->modem_state = EG25_STATE_UPDATING;
}
if (strcmp(action, "unbind") != 0 || manager->modem_state == EG25_STATE_UPDATING ||
manager->modem_state == EG25_STATE_RESETTING || manager->complete_reset_timer != 0 ||
manager->schedule_reset_timer != 0) {
if (strcmp(action, "unbind") != 0 ||
manager->modem_state == EG25_STATE_RESETTING ||
!manager->modem_usb_id) {
return;
}
if (strcmp(g_udev_device_get_name(device), manager->modem_usb_id) == 0 &&
manager->reset_timer == 0) {
g_message("Lost modem, resetting...");
manager->schedule_reset_timer = g_timeout_add_seconds(3, G_SOURCE_FUNC(modem_reset), manager);
g_timeout_add_seconds(2, G_SOURCE_FUNC(modem_reset), manager);
}
}
void udev_init(struct EG25Manager *manager, toml_table_t *config[])
void udev_init (struct EG25Manager *manager, toml_table_t *config[])
{
const char *const subsystems[] = {"usb", NULL};
const char * const subsystems[] = { "usb", NULL };
manager->udev = g_udev_client_new(subsystems);
g_signal_connect(manager->udev, "uevent", G_CALLBACK(udev_event_cb), manager);
@@ -61,7 +35,7 @@ void udev_init(struct EG25Manager *manager, toml_table_t *config[])
return;
}
void udev_destroy(struct EG25Manager *manager)
void udev_destroy (struct EG25Manager *manager)
{
if (manager->udev) {
g_object_unref(manager->udev);

View File

@@ -8,5 +8,5 @@
#include "manager.h"
void udev_init(struct EG25Manager *data, toml_table_t *config[]);
void udev_destroy(struct EG25Manager *data);
void udev_init (struct EG25Manager *data, toml_table_t *config[]);
void udev_destroy (struct EG25Manager *data);

View File

@@ -1,18 +1,4 @@
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ENV{DEVTYPE}=="usb_device", GOTO="eg25_start"
GOTO="eg25_end"
# Default attributes values
LABEL="eg25_start"
ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/control}="auto"
ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/autosuspend_delay_ms}="3000"
ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/wakeup}="enabled"
ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/persist}="0"
# power/control needs to be "on" for the community-maintained firmware
ATTRS{serial}=="community_fw", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/control}="on"
# Special trick for the PinePhone Pro: set power/persist to 1 *only* with the community FW
# We can identify the PPP by looking for the string "pinephone-pro" in the device tree "compatible" property
ATTRS{serial}=="community_fw", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", PROGRAM=="/bin/grep pine64,pinephone-pro /proc/device-tree/compatible", ATTR{power/persist}="1"
LABEL="eg25_end"
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/control}="auto"
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/autosuspend_delay_ms}="3000"
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/wakeup}="enabled"
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/persist}="0"