52 Commits

Author SHA1 Message Date
Arnaud Ferraris
c9d89e1736 d/changelog: release version 0.4.3-1 2022-02-19 15:37:12 +01:00
Arnaud Ferraris
a66852d96d d/watch: fix watch file
Our `watch` file was looking at the wrong URL, fix that.
2022-02-19 15:36:49 +01:00
Arnaud Ferraris
8c9941eef6 debian: small cleanups
`salsa-ci.yml` is no longer needed as we now have our own CI pipelines.
Also delete unneeded newlines from `watch` file.
2022-02-19 15:22:40 +01:00
Arnaud Ferraris
d9778e6ecd d/control: build-depend on scdoc
This is required for building the manpages. Also bump Standards-Version,
no other changes needed.
2022-02-19 15:19:13 +01:00
Arnaud Ferraris
7b46f084d9 New upstream version 0.4.3
eg25-manager v0.4.3

IMPORTANT: this release renames the executable to `eg25-manager` (added
dash). Make sure existing scripts are updated to reflect this change.

Changes:
* improve udev monitoring:
  - filter based on vendor/product ID
  - disable udev monitoring for the PinePhone Pro
* add manpages for `eg25-manager` and its configuration files
  - this adds an optional build dependency on `scdoc`
* Fix build when not using ModemManager
* Fix GPIO module initialization for BraveHeart Edition PinePhones
* Various build system improvements (now requires meson >= 0.58.0)
2022-02-19 15:18:21 +01:00
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
15 changed files with 305 additions and 289 deletions

View File

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

122
debian/changelog vendored Normal file
View File

@@ -0,0 +1,122 @@
eg25-manager (0.4.3-1) unstable; urgency=medium
* New upstream version 0.4.3
* d/control: build-depend on `scdoc`
This is required for building the manpages. Also bump Standards-Version,
no other changes needed.
* d/watch: fix watch file
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Sat, 19 Feb 2022 15:20:14 +0100
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

29
debian/control vendored Normal file
View File

@@ -0,0 +1,29 @@
Source: eg25-manager
Section: libs
Priority: optional
Maintainer: Arnaud Ferraris <arnaud.ferraris@gmail.com>
Standards-Version: 4.6.0
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,
scdoc <!nodoc>,
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 $@

1
debian/source/format vendored Normal file
View File

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

3
debian/watch vendored Normal file
View File

@@ -0,0 +1,3 @@
version=4
https://gitlab.com/mobian1/devices/@PACKAGE@/-/tags?sort=updated_desc \
.*/archive/\d\S+/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@

View File

@@ -8,7 +8,7 @@
project ( project (
'eg25-manager', 'eg25-manager',
'c', 'c',
version : '0.5.1', version : '0.4.3',
license : 'GPLv3+', license : 'GPLv3+',
meson_version : '>= 0.58.0', meson_version : '>= 0.58.0',
default_options : default_options :
@@ -59,7 +59,7 @@ mgr_deps = [
dependency('glib-2.0'), dependency('glib-2.0'),
dependency('gio-unix-2.0'), dependency('gio-unix-2.0'),
dependency('gudev-1.0'), dependency('gudev-1.0'),
dependency('libgpiod', version: '>= 2.0'), dependency('libgpiod'),
dependency('libusb-1.0'), dependency('libusb-1.0'),
dependency('libcurl'), dependency('libcurl'),
mmglib_dep, mmglib_dep,

View File

@@ -327,7 +327,7 @@ static void init_assistance_data_upload(struct EG25Manager *manager)
static void upload_assistance_data(struct EG25Manager *manager) static void upload_assistance_data(struct EG25Manager *manager)
{ {
gint error; gint error;
off_t written_total = 0; glong written_total = 0;
gint ret; gint ret;
struct stat sb; struct stat sb;

View File

@@ -8,8 +8,6 @@
#include "gpio.h" #include "gpio.h"
#include <unistd.h> #include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
/* Those defines are used for legacy config files only */ /* Those defines are used for legacy config files only */
#define GPIO_CHIP1_LABEL "1c20800.pinctrl" #define GPIO_CHIP1_LABEL "1c20800.pinctrl"
@@ -42,81 +40,21 @@ static char *gpio_in_names[] = {
"status", "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) int gpio_sequence_poweron(struct EG25Manager *manager)
{ {
/* Disable airplane mode in case it was enabled by other software. The gpiod_line_set_value(manager->gpio_out[GPIO_OUT_PWRKEY], 1);
* W_DISABLE pin is active-low, so we set it to high here. */
gpio_line_set_value(manager, GPIO_OUT_DISABLE, GPIOD_LINE_VALUE_ACTIVE);
/*
* 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
*/
sleep(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/off sequence");
g_message("Executed power-on sequence");
return 0; return 0;
} }
int gpio_sequence_shutdown(struct EG25Manager *manager) int gpio_sequence_shutdown(struct EG25Manager *manager)
{ {
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_ACTIVE); gpiod_line_set_value(manager->gpio_out[GPIO_OUT_DISABLE], 1);
sleep(1); gpio_sequence_poweron(manager);
gpio_line_set_value(manager, GPIO_OUT_PWRKEY, GPIOD_LINE_VALUE_INACTIVE);
g_message("Executed power-off sequence"); g_message("Executed power-off sequence");
@@ -125,7 +63,7 @@ int gpio_sequence_shutdown(struct EG25Manager *manager)
int gpio_sequence_suspend(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"); g_message("Executed suspend sequence");
@@ -134,7 +72,7 @@ int gpio_sequence_suspend(struct EG25Manager *manager)
int gpio_sequence_resume(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"); g_message("Executed resume sequence");
@@ -143,8 +81,8 @@ int gpio_sequence_resume(struct EG25Manager *manager)
int gpio_sequence_wake(struct EG25Manager *manager) int gpio_sequence_wake(struct EG25Manager *manager)
{ {
if (manager->gpio_out_value[GPIO_OUT_DTR]) { if (gpiod_line_get_value(manager->gpio_out[GPIO_OUT_DTR])) {
gpio_line_set_value(manager, GPIO_OUT_DTR, GPIOD_LINE_VALUE_INACTIVE); gpiod_line_set_value(manager->gpio_out[GPIO_OUT_DTR], 0);
/* Give the modem 200ms to wake from soft sleep */ /* Give the modem 200ms to wake from soft sleep */
usleep(200000); usleep(200000);
@@ -157,150 +95,42 @@ int gpio_sequence_wake(struct EG25Manager *manager)
int gpio_sequence_sleep(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"); g_message("Executed soft sleep sequence");
return 0; 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 *gpio_line;
struct gpiod_line_config *line_cfg;
struct gpiod_request_config *req_cfg;
int ret;
settings = gpiod_line_settings_new(); gpio_line = gpiod_chip_get_line(manager->gpiochip[chip], line);
if (!settings) if (!gpio_line)
return NULL; return NULL;
gpiod_line_settings_set_direction(settings, direction); if (gpiod_line_request_output(gpio_line, "eg25manager", 0) < 0) {
gpiod_line_release(gpio_line);
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;
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) {
return chip;
}
clean_chip_open:
gpiod_chip_close(chip);
}
return NULL; return NULL;
} }
unsigned int gpio_chip_num_lines(struct EG25Manager *manager, unsigned int chip_num) { return gpio_line;
struct gpiod_chip *chip = manager->gpiochip[chip_num]; }
struct gpiod_chip_info *info;
unsigned int num_lines;
info = gpiod_chip_get_info(chip); struct gpiod_line *gpio_get_input_line(struct EG25Manager *manager, int chip, int line)
if (!info) {
g_error("gpio: failed to read info: %s", strerror(errno)); struct gpiod_line *gpio_line;
num_lines = gpiod_chip_info_get_num_lines(info); gpio_line = gpiod_chip_get_line(manager->gpiochip[chip], line);
if (!gpio_line)
return NULL;
gpiod_chip_info_free(info); if (gpiod_line_request_input(gpio_line, "eg25manager") < 0) {
gpiod_line_release(gpio_line);
return NULL;
}
return num_lines; return gpio_line;
} }
int gpio_init(struct EG25Manager *manager, toml_table_t *config[]) int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
@@ -339,7 +169,7 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
toml_datum_t data = toml_string_at(chipslist, i); toml_datum_t data = toml_string_at(chipslist, i);
if (!data.ok) if (!data.ok)
continue; 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]) if (!manager->gpiochip[i])
g_error("Unable to find GPIO chip '%s'", data.u.s); g_error("Unable to find GPIO chip '%s'", data.u.s);
} }
@@ -355,10 +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]); g_error("Wrong chip ID for output GPIO '%s'", gpio_out_names[i]);
line = toml_int_in(table, "line"); 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]); 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]) if (!manager->gpio_out[i])
g_error("Unable to get output GPIO %d", i); g_error("Unable to get output GPIO %d", i);
} }
@@ -379,10 +209,10 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
g_error("Wrong chip ID for input GPIO '%s'", gpio_in_names[i]); g_error("Wrong chip ID for input GPIO '%s'", gpio_in_names[i]);
line = toml_int_in(table, "line"); 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]); 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]) if (!manager->gpio_in[i])
g_error("Unable to get input GPIO %d", i); g_error("Unable to get input GPIO %d", i);
} }
@@ -390,11 +220,11 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
guint offset, chipidx, gpio_idx; guint offset, chipidx, gpio_idx;
/* Legacy config file, only used on the OG PinePhone */ /* 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]) if (!manager->gpiochip[0])
g_error("Unable to open GPIO chip " GPIO_CHIP1_LABEL); 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]) if (!manager->gpiochip[1])
g_error("Unable to open GPIO chip " GPIO_CHIP2_LABEL); g_error("Unable to open GPIO chip " GPIO_CHIP2_LABEL);
@@ -410,7 +240,7 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
chipidx = 1; 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]) if (!manager->gpio_out[i])
g_error("Unable to get output GPIO %d", i); g_error("Unable to get output GPIO %d", i);
} }
@@ -427,7 +257,7 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
chipidx = 1; 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]) if (!manager->gpio_in[i])
g_error("Unable to get input GPIO %d", i); g_error("Unable to get input GPIO %d", i);
} }
@@ -436,18 +266,16 @@ int gpio_init(struct EG25Manager *manager, toml_table_t *config[])
return 0; return 0;
} }
void gpio_force_off(struct EG25Manager *manager) gboolean gpio_check_poweroff(struct EG25Manager *manager, gboolean keep_down)
{
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)
{ {
if (manager->gpio_in[GPIO_IN_STATUS] && 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; return TRUE;
} }
@@ -460,12 +288,12 @@ void gpio_destroy(struct EG25Manager *manager)
for (i = 0; i < GPIO_OUT_COUNT; i++) { for (i = 0; i < GPIO_OUT_COUNT; i++) {
if (manager->gpio_out[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++) { for (i = 0; i < GPIO_IN_COUNT; i++) {
if (manager->gpio_in[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]) 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_wake(struct EG25Manager *state);
int gpio_sequence_sleep(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 keep_down);
gboolean gpio_check_poweroff(struct EG25Manager *manager);

View File

@@ -62,17 +62,13 @@ static gboolean quit_app(struct EG25Manager *manager)
gpio_sequence_shutdown(manager); gpio_sequence_shutdown(manager);
manager->modem_state = EG25_STATE_FINISHING; manager->modem_state = EG25_STATE_FINISHING;
for (i = 0; i < 30; i++) { for (i = 0; i < 30; i++) {
if (gpio_check_poweroff(manager)) { if (gpio_check_poweroff(manager, TRUE))
g_message("Modem successfully powered down");
break; break;
}
sleep(1); sleep(1);
} }
} }
gpio_force_off(manager);
g_message("Modem down, quitting..."); g_message("Modem down, quitting...");
g_main_loop_quit(manager->loop); g_main_loop_quit(manager->loop);
return FALSE; return FALSE;
@@ -102,7 +98,7 @@ static gboolean modem_start(struct EG25Manager *manager)
libusb_free_device_list(devices, 1); libusb_free_device_list(devices, 1);
libusb_exit(ctx); libusb_exit(ctx);
} else if (!gpio_check_poweroff(manager)) { } else if (!gpio_check_poweroff(manager, FALSE)) {
g_message("STATUS is low, modem already powered"); g_message("STATUS is low, modem already powered");
should_boot = FALSE; should_boot = FALSE;
} }
@@ -145,35 +141,7 @@ void modem_configure(struct EG25Manager *manager)
at_sequence_configure(manager); at_sequence_configure(manager);
} }
static gboolean modem_gpio_reset_done(struct EG25Manager *manager) static gboolean modem_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)
{ {
manager->modem_state = EG25_STATE_RESUMING; manager->modem_state = EG25_STATE_RESUMING;
manager->complete_reset_timer = 0; manager->complete_reset_timer = 0;
@@ -226,26 +194,24 @@ gboolean modem_reset(struct EG25Manager *manager)
g_warning("Unable to open /sys/bus/usb/drivers/usb/unbind"); g_warning("Unable to open /sys/bus/usb/drivers/usb/unbind");
goto error; goto error;
} }
ret = write(fd, manager->modem_usb_id, len); ret = write(fd, manager->modem_usb_id, len);
close(fd);
if (ret < len) { if (ret < len) {
g_warning("Couldn't unbind modem: wrote %d/%d bytes", ret, len); g_warning("Couldn't unbind modem: wrote %d/%d bytes", ret, len);
goto error; goto error;
} }
close(fd);
fd = open("/sys/bus/usb/drivers/usb/bind", O_WRONLY); fd = open("/sys/bus/usb/drivers/usb/bind", O_WRONLY);
if (fd < 0) { 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; goto error;
} }
ret = write(fd, manager->modem_usb_id, len); ret = write(fd, manager->modem_usb_id, len);
close(fd);
if (ret < len) { if (ret < len) {
g_warning("Couldn't bind modem: wrote %d/%d bytes", ret, len); g_warning("Couldn't bind modem: wrote %d/%d bytes", ret, len);
goto error; goto error;
} }
close(fd);
g_message("Successfully reset modem's USB connection"); g_message("Successfully reset modem's USB connection");
@@ -253,7 +219,7 @@ gboolean modem_reset(struct EG25Manager *manager)
* 3s is long enough to make sure the modem has been bound back and * 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 * 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->complete_reset_timer = g_timeout_add_seconds(3, G_SOURCE_FUNC(modem_reset_done), manager);
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
@@ -271,7 +237,7 @@ error:
at_sequence_reset(manager); at_sequence_reset(manager);
// Setup timer for making sure we don't queue other reset commands // Setup timer for making sure we don't queue other reset commands
manager->complete_reset_timer = g_timeout_add_seconds(30, G_SOURCE_FUNC(modem_at_reset_done), manager); manager->complete_reset_timer = g_timeout_add_seconds(30, G_SOURCE_FUNC(modem_reset_done), manager);
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }

View File

@@ -116,9 +116,8 @@ struct EG25Manager {
GUdevClient *udev; GUdevClient *udev;
struct gpiod_chip *gpiochip[2]; struct gpiod_chip *gpiochip[2];
struct gpiod_line_request *gpio_out[5]; struct gpiod_line *gpio_out[5];
guint gpio_out_value[5]; struct gpiod_line *gpio_in[2];
struct gpiod_line_request *gpio_in[2];
}; };
void modem_configure(struct EG25Manager *data); void modem_configure(struct EG25Manager *data);

View File

@@ -1,18 +1,4 @@
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ENV{DEVTYPE}=="usb_device", GOTO="eg25_start" ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/control}="auto"
GOTO="eg25_end" 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"
# Default attributes values ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="2c7c", ATTRS{idProduct}=="0125", ATTR{power/persist}="0"
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"