mirror of
https://gitlab.com/mobian1/eg25-manager.git
synced 2025-08-30 15:52:11 +02:00
Compare commits
52 Commits
0.5.1
...
mobian/0.4
Author | SHA1 | Date | |
---|---|---|---|
|
c9d89e1736 | ||
|
a66852d96d | ||
|
8c9941eef6 | ||
|
d9778e6ecd | ||
|
7b46f084d9 | ||
|
9c05776843 | ||
|
08a7039ca0 | ||
|
929b3942c0 | ||
|
f8430eb16f | ||
|
1b69252cbe | ||
|
c17f947249 | ||
|
e96aec8390 | ||
|
e4ae8d6382 | ||
|
da8a008268 | ||
|
30ce2bb3e2 | ||
|
162fcf6fca | ||
|
24dbcf464c | ||
|
b62b155875 | ||
|
67195a8e58 | ||
|
c7e8d9171c | ||
|
5db68722ec | ||
|
432bd454bb | ||
|
986e7f08c4 | ||
|
4089f2ea6b | ||
|
c77c58df49 | ||
|
5cc5ff5c0e | ||
|
6a81955086 | ||
|
af3a2b25bc | ||
|
70db05fc62 | ||
|
705a454882 | ||
|
2469757af4 | ||
|
514b00cc9c | ||
|
e078b8bc09 | ||
|
d976c75fa2 | ||
|
f86d0ef062 | ||
|
276c71f223 | ||
|
1423021f97 | ||
|
fc915f570d | ||
|
c77490a2ac | ||
|
fbd5c0cb86 | ||
|
5bcefbeab0 | ||
|
f85e8f70c7 | ||
|
2da2c9dfe2 | ||
|
dfaac39162 | ||
|
7dc0d1678c | ||
|
397a16a9e3 | ||
|
59219fbd20 | ||
|
c953d41436 | ||
|
82bf80c5f4 | ||
|
339faa46dc | ||
|
cdf92755cb | ||
|
7c04c1998f |
@@ -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
122
debian/changelog
vendored
Normal 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
29
debian/control
vendored
Normal 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
67
debian/copyright
vendored
Normal 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
10
debian/gbp.conf
vendored
Normal 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
6
debian/rules
vendored
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.0 (quilt)
|
3
debian/watch
vendored
Normal file
3
debian/watch
vendored
Normal 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@
|
@@ -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,
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
270
src/gpio.c
270
src/gpio.c
@@ -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])
|
||||||
|
@@ -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);
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
@@ -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"
|
|
||||||
|
Reference in New Issue
Block a user