mirror of
https://gitlab.com/mobian1/eg25-manager.git
synced 2025-08-29 23:32:14 +02:00
suspend: add boot timer
The EG25 modem needs at least 2 minutes after indicating 'RDY' to be fully operational. If the modem is suspended before that, calls or texts may not be seen by the userspace. This mostly occurs when a full reboot or poweroff/poweron sequence of the phone is performed. :
This commit is contained in:
4
src/at.c
4
src/at.c
@@ -202,8 +202,10 @@ static gboolean modem_response(gint fd,
|
|||||||
|
|
||||||
g_message("Response: [%s]", response);
|
g_message("Response: [%s]", response);
|
||||||
|
|
||||||
if (strcmp(response, "RDY") == 0)
|
if (strcmp(response, "RDY") == 0) {
|
||||||
|
suspend_inhibit(manager, TRUE, TRUE);
|
||||||
manager->modem_state = EG25_STATE_STARTED;
|
manager->modem_state = EG25_STATE_STARTED;
|
||||||
|
}
|
||||||
else if (strstr(response, "ERROR"))
|
else if (strstr(response, "ERROR"))
|
||||||
retry_at_command(manager);
|
retry_at_command(manager);
|
||||||
else if (strstr(response, "OK"))
|
else if (strstr(response, "OK"))
|
||||||
|
@@ -178,7 +178,7 @@ void modem_suspend_post(struct EG25Manager *manager)
|
|||||||
{
|
{
|
||||||
gpio_sequence_suspend(manager);
|
gpio_sequence_suspend(manager);
|
||||||
g_message("suspend sequence is over, drop inhibitor");
|
g_message("suspend sequence is over, drop inhibitor");
|
||||||
suspend_inhibit(manager, FALSE);
|
suspend_inhibit(manager, FALSE, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void modem_resume_pre(struct EG25Manager *manager)
|
void modem_resume_pre(struct EG25Manager *manager)
|
||||||
@@ -205,7 +205,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
memset(&manager, 0, sizeof(manager));
|
memset(&manager, 0, sizeof(manager));
|
||||||
manager.at_fd = -1;
|
manager.at_fd = -1;
|
||||||
manager.suspend_inhibit_fd = -1;
|
manager.delay_inhibit_fd = -1;
|
||||||
|
manager.block_inhibit_fd = -1;
|
||||||
|
|
||||||
opt_context = g_option_context_new ("- Power management for the Quectel EG25 modem");
|
opt_context = g_option_context_new ("- Power management for the Quectel EG25 modem");
|
||||||
g_option_context_add_main_entries (opt_context, options, NULL);
|
g_option_context_add_main_entries (opt_context, options, NULL);
|
||||||
|
@@ -43,8 +43,10 @@ struct EG25Manager {
|
|||||||
MMModem *mm_modem;
|
MMModem *mm_modem;
|
||||||
|
|
||||||
GDBusProxy *suspend_proxy;
|
GDBusProxy *suspend_proxy;
|
||||||
int suspend_inhibit_fd;
|
int delay_inhibit_fd;
|
||||||
|
int block_inhibit_fd;
|
||||||
guint suspend_timer;
|
guint suspend_timer;
|
||||||
|
guint boot_timer;
|
||||||
|
|
||||||
GUdevClient *udev;
|
GUdevClient *udev;
|
||||||
|
|
||||||
|
126
src/suspend.c
126
src/suspend.c
@@ -13,9 +13,10 @@
|
|||||||
|
|
||||||
#include <gio/gunixfdlist.h>
|
#include <gio/gunixfdlist.h>
|
||||||
|
|
||||||
#define SD_NAME "org.freedesktop.login1"
|
#define SD_NAME "org.freedesktop.login1"
|
||||||
#define SD_PATH "/org/freedesktop/login1"
|
#define SD_PATH "/org/freedesktop/login1"
|
||||||
#define SD_INTERFACE "org.freedesktop.login1.Manager"
|
#define SD_INTERFACE "org.freedesktop.login1.Manager"
|
||||||
|
#define FULL_BOOT_DELAY 120
|
||||||
|
|
||||||
static gboolean check_modem_resume(struct EG25Manager *manager)
|
static gboolean check_modem_resume(struct EG25Manager *manager)
|
||||||
{
|
{
|
||||||
@@ -26,18 +27,28 @@ static gboolean check_modem_resume(struct EG25Manager *manager)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean drop_inhibitor(struct EG25Manager *manager)
|
static gboolean drop_inhibitor(struct EG25Manager *manager, gboolean block)
|
||||||
{
|
{
|
||||||
if (manager->suspend_inhibit_fd >= 0) {
|
if (block) {
|
||||||
g_message("dropping systemd sleep inhibitor");
|
if (manager->block_inhibit_fd >= 0) {
|
||||||
close(manager->suspend_inhibit_fd);
|
g_message("dropping systemd sleep block inhibitor");
|
||||||
manager->suspend_inhibit_fd = -1;
|
close(manager->block_inhibit_fd);
|
||||||
return TRUE;
|
manager->block_inhibit_fd = -1;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (manager->delay_inhibit_fd >= 0) {
|
||||||
|
g_message("dropping systemd sleep delay inhibitor");
|
||||||
|
close(manager->delay_inhibit_fd);
|
||||||
|
manager->delay_inhibit_fd = -1;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inhibit_done(GObject *source,
|
static void inhibit_done_delay(GObject *source,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
@@ -54,27 +65,81 @@ static void inhibit_done(GObject *source,
|
|||||||
if (!fd_list || g_unix_fd_list_get_length(fd_list) != 1)
|
if (!fd_list || g_unix_fd_list_get_length(fd_list) != 1)
|
||||||
g_warning("didn't get a single fd back");
|
g_warning("didn't get a single fd back");
|
||||||
|
|
||||||
manager->suspend_inhibit_fd = g_unix_fd_list_get(fd_list, 0, NULL);
|
manager->delay_inhibit_fd = g_unix_fd_list_get(fd_list, 0, NULL);
|
||||||
|
|
||||||
g_message("inhibitor fd is %d", manager->suspend_inhibit_fd);
|
g_message("inhibitor sleep fd is %d", manager->delay_inhibit_fd);
|
||||||
g_object_unref(fd_list);
|
g_object_unref(fd_list);
|
||||||
g_variant_unref(res);
|
g_variant_unref(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void take_inhibitor(struct EG25Manager *manager)
|
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;
|
||||||
|
GVariant *res;
|
||||||
|
GUnixFDList *fd_list;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if (!fd_list || g_unix_fd_list_get_length(fd_list) != 1)
|
||||||
|
g_warning("didn't get a single fd back");
|
||||||
|
|
||||||
|
manager->block_inhibit_fd = g_unix_fd_list_get(fd_list, 0, NULL);
|
||||||
|
|
||||||
|
g_message("inhibitor block fd is %d", manager->block_inhibit_fd);
|
||||||
|
g_object_unref(fd_list);
|
||||||
|
g_variant_unref(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After the EG25 modem sends 'RDY', it takes up to 2 minutes before all
|
||||||
|
* capabilities are operational. If the modem is suspended before that,
|
||||||
|
* calls and texts may be not recognized properly.
|
||||||
|
*/
|
||||||
|
static gboolean modem_fully_booted(struct EG25Manager *manager)
|
||||||
|
{
|
||||||
|
g_message("Modem is up for %d seconds and fully ready", FULL_BOOT_DELAY);
|
||||||
|
manager->boot_timer = 0;
|
||||||
|
drop_inhibitor(manager, TRUE);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void take_inhibitor(struct EG25Manager *manager, gboolean block)
|
||||||
{
|
{
|
||||||
GVariant *variant_arg;
|
GVariant *variant_arg;
|
||||||
|
|
||||||
if(manager->suspend_inhibit_fd != -1)
|
if (block) {
|
||||||
drop_inhibitor(manager);
|
if(manager->block_inhibit_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 prepare modem for sleep", "delay");
|
"eg25manager needs to wait for modem to be fully booted", "block");
|
||||||
|
|
||||||
g_message("taking systemd sleep inhibitor");
|
g_message("taking systemd sleep block inhibitor");
|
||||||
g_dbus_proxy_call_with_unix_fd_list(manager->suspend_proxy, "Inhibit", variant_arg,
|
g_dbus_proxy_call_with_unix_fd_list(manager->suspend_proxy, "Inhibit", variant_arg,
|
||||||
0, G_MAXINT, NULL, NULL, inhibit_done, manager);
|
0, G_MAXINT, NULL, NULL, inhibit_done_block, manager);
|
||||||
|
g_message("scheduling block inhibitor release");
|
||||||
|
manager->boot_timer = g_timeout_add_seconds(FULL_BOOT_DELAY, G_SOURCE_FUNC(modem_fully_booted), manager);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(manager->delay_inhibit_fd != -1)
|
||||||
|
drop_inhibitor(manager, FALSE);
|
||||||
|
|
||||||
|
variant_arg = g_variant_new ("(ssss)", "sleep", "eg25manager",
|
||||||
|
"eg25manager needs to prepare modem for sleep", "delay");
|
||||||
|
|
||||||
|
g_message("taking systemd sleep delay inhibitor");
|
||||||
|
g_dbus_proxy_call_with_unix_fd_list(manager->suspend_proxy, "Inhibit", variant_arg,
|
||||||
|
0, G_MAXINT, NULL, NULL, inhibit_done_delay, manager);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signal_cb(GDBusProxy *proxy,
|
static void signal_cb(GDBusProxy *proxy,
|
||||||
@@ -97,7 +162,7 @@ static void signal_cb(GDBusProxy *proxy,
|
|||||||
modem_suspend_pre(manager);
|
modem_suspend_pre(manager);
|
||||||
} else {
|
} else {
|
||||||
g_message("system is resuming");
|
g_message("system is resuming");
|
||||||
take_inhibitor(manager);
|
take_inhibitor(manager, FALSE);
|
||||||
modem_resume_pre(manager);
|
modem_resume_pre(manager);
|
||||||
if (manager->mm_modem) {
|
if (manager->mm_modem) {
|
||||||
/*
|
/*
|
||||||
@@ -126,10 +191,10 @@ static void name_owner_cb(GObject *object,
|
|||||||
|
|
||||||
owner = g_dbus_proxy_get_name_owner(proxy);
|
owner = g_dbus_proxy_get_name_owner(proxy);
|
||||||
if (owner) {
|
if (owner) {
|
||||||
take_inhibitor(manager);
|
take_inhibitor(manager, FALSE);
|
||||||
g_free(owner);
|
g_free(owner);
|
||||||
} else {
|
} else {
|
||||||
drop_inhibitor(manager);
|
drop_inhibitor(manager, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +216,7 @@ static void on_proxy_acquired(GObject *object,
|
|||||||
|
|
||||||
owner = g_dbus_proxy_get_name_owner(manager->suspend_proxy);
|
owner = g_dbus_proxy_get_name_owner(manager->suspend_proxy);
|
||||||
if (owner) {
|
if (owner) {
|
||||||
take_inhibitor(manager);
|
take_inhibitor(manager, FALSE);
|
||||||
g_free(owner);
|
g_free(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,21 +232,26 @@ void suspend_init(struct EG25Manager *manager)
|
|||||||
|
|
||||||
void suspend_destroy(struct EG25Manager *manager)
|
void suspend_destroy(struct EG25Manager *manager)
|
||||||
{
|
{
|
||||||
drop_inhibitor(manager);
|
drop_inhibitor(manager, FALSE);
|
||||||
|
drop_inhibitor(manager, TRUE);
|
||||||
if (manager->suspend_timer) {
|
if (manager->suspend_timer) {
|
||||||
g_source_remove(manager->suspend_timer);
|
g_source_remove(manager->suspend_timer);
|
||||||
manager->suspend_timer = 0;
|
manager->suspend_timer = 0;
|
||||||
}
|
}
|
||||||
|
if (manager->boot_timer) {
|
||||||
|
g_source_remove(manager->boot_timer);
|
||||||
|
manager->boot_timer = 0;
|
||||||
|
}
|
||||||
if (manager->suspend_proxy) {
|
if (manager->suspend_proxy) {
|
||||||
g_object_unref(manager->suspend_proxy);
|
g_object_unref(manager->suspend_proxy);
|
||||||
manager->suspend_proxy = NULL;
|
manager->suspend_proxy = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void suspend_inhibit(struct EG25Manager *manager, gboolean inhibit)
|
void suspend_inhibit(struct EG25Manager *manager, gboolean inhibit, gboolean block)
|
||||||
{
|
{
|
||||||
if (inhibit)
|
if (inhibit)
|
||||||
take_inhibitor(manager);
|
take_inhibitor(manager, block);
|
||||||
else
|
else
|
||||||
drop_inhibitor(manager);
|
drop_inhibitor(manager, block);
|
||||||
}
|
}
|
||||||
|
@@ -11,4 +11,4 @@
|
|||||||
void suspend_init (struct EG25Manager *data);
|
void suspend_init (struct EG25Manager *data);
|
||||||
void suspend_destroy (struct EG25Manager *data);
|
void suspend_destroy (struct EG25Manager *data);
|
||||||
|
|
||||||
void suspend_inhibit (struct EG25Manager *data, gboolean inhibit);
|
void suspend_inhibit (struct EG25Manager *data, gboolean inhibit, gboolean block);
|
||||||
|
Reference in New Issue
Block a user