diff --git a/src/at.c b/src/at.c index 4b5cd62..32138d0 100644 --- a/src/at.c +++ b/src/at.c @@ -76,12 +76,16 @@ static gboolean send_at_command(struct EG25Manager *manager) g_message("Sending command: %s", g_strstrip(command)); } else if (manager->modem_state < EG25_STATE_CONFIGURED) { - MMModemState modem_state = mm_modem_get_state(manager->mm_modem); + if (manager->modem_iface == MODEM_IFACE_MODEMMANAGER) { + MMModemState modem_state = mm_modem_get_state(manager->mm_modem); - if (manager->mm_modem && modem_state >= MM_MODEM_STATE_REGISTERED) - modem_update_state(manager, modem_state); - else + if (manager->mm_modem && modem_state >= MM_MODEM_STATE_REGISTERED) + modem_update_state(manager, modem_state); + else + manager->modem_state = EG25_STATE_CONFIGURED; + } else { manager->modem_state = EG25_STATE_CONFIGURED; + } } else if (manager->modem_state == EG25_STATE_SUSPENDING) { modem_suspend_post(manager); } else if (manager->modem_state == EG25_STATE_RESETTING) { diff --git a/src/libgdbofono/dbus-introspect.sh b/src/libgdbofono/dbus-introspect.sh new file mode 100755 index 0000000..5a851ad --- /dev/null +++ b/src/libgdbofono/dbus-introspect.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +DEST="$1" +OBJ_PATH="$2" +METHOD="$3" +shift 3 + +dbus-send "$@" --print-reply --dest="$DEST" "$OBJ_PATH" "$METHOD" | \ + grep -v '^method return' | \ + sed -e 's/^[[:space:]]\+string ""__' diff --git a/src/libgdbofono/manager.xml b/src/libgdbofono/manager.xml new file mode 100644 index 0000000..13e9d56 --- /dev/null +++ b/src/libgdbofono/manager.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/src/libgdbofono/meson.build b/src/libgdbofono/meson.build new file mode 100644 index 0000000..98eb9a3 --- /dev/null +++ b/src/libgdbofono/meson.build @@ -0,0 +1,50 @@ +# +# Copyright (C) 2018 Purism SPC +# +# This file is part of Calls. +# +# Calls 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. +# +# Calls 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 Calls. If not, see . +# +# Author: Bob Ham +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + + +gnome = import('gnome') +dbus_interfaces = ['manager', 'modem'] + +gdbofono_src = [] +gdbofono_headers = [] +foreach iface: dbus_interfaces + src = gnome.gdbus_codegen( + 'gdbo-' + iface, + iface + '.xml', + interface_prefix: 'org.ofono.', + namespace: 'GDBO' + ) + gdbofono_src += src + gdbofono_headers += src[1] +endforeach + +gdbofono_deps = [ + dependency('gio-2.0'), + dependency('gio-unix-2.0'), +] + +gdbofono_lib = static_library( + 'gdbofono', + gdbofono_src, + dependencies: gdbofono_deps +) diff --git a/src/libgdbofono/modem-full.xml b/src/libgdbofono/modem-full.xml new file mode 100644 index 0000000..5319672 --- /dev/null +++ b/src/libgdbofono/modem-full.xml @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libgdbofono/modem.xml b/src/libgdbofono/modem.xml new file mode 100644 index 0000000..c02d250 --- /dev/null +++ b/src/libgdbofono/modem.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/manager.c b/src/manager.c index aaa3905..7c55cd9 100644 --- a/src/manager.c +++ b/src/manager.c @@ -8,6 +8,7 @@ #include "gpio.h" #include "manager.h" #include "mm-iface.h" +#include "ofono-iface.h" #include "suspend.h" #include "udev.h" @@ -35,6 +36,7 @@ static gboolean quit_app(struct EG25Manager *manager) at_destroy(manager); mm_iface_destroy(manager); + ofono_iface_destroy(manager); suspend_destroy(manager); udev_destroy(manager); @@ -131,6 +133,14 @@ void modem_reset(struct EG25Manager *manager) if (manager->reset_timer) return; + /* + * If we are managing the modem through lets say ofono, we should not + * reset the modem based on the availability of USB ID + * TODO: Improve ofono plugin and add support for fetching USB ID + */ + if (manager->modem_iface != MODEM_IFACE_MODEMMANAGER) + return; + if (manager->modem_recovery_timer) { g_source_remove(manager->modem_recovery_timer); manager->modem_recovery_timer = 0; @@ -305,6 +315,7 @@ int main(int argc, char *argv[]) at_init(&manager, toml_table_in(toml_config, "at")); gpio_init(&manager, toml_table_in(toml_config, "gpio")); mm_iface_init(&manager, toml_table_in(toml_config, "mm-iface")); + ofono_iface_init(&manager); suspend_init(&manager, toml_table_in(toml_config, "suspend")); udev_init(&manager, toml_table_in(toml_config, "udev")); diff --git a/src/manager.h b/src/manager.h index 48ff237..ec5550b 100644 --- a/src/manager.h +++ b/src/manager.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "toml.h" @@ -27,6 +28,12 @@ enum EG25State { EG25_STATE_FINISHING }; +enum ModemIface { + MODEM_IFACE_NONE = 0, + MODEM_IFACE_MODEMMANAGER, + MODEM_IFACE_OFONO +}; + struct EG25Manager { GMainLoop *loop; guint reset_timer; @@ -41,10 +48,15 @@ struct EG25Manager { enum EG25State modem_state; gchar *modem_usb_id; + enum ModemIface modem_iface; guint mm_watch; MMManager *mm_manager; MMModem *mm_modem; + guint ofono_watch; + GDBOManager *ofono_manager; + GDBusConnection *ofono_connection; + GDBusProxy *suspend_proxy; int suspend_delay_fd; int suspend_block_fd; diff --git a/src/meson.build b/src/meson.build index 0d10362..6a9f52d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,6 +4,9 @@ # SPDX-License-Identifier: GPL-3.0-or-later # + +subdir('libgdbofono') + executable ( 'eg25manager', [ @@ -11,10 +14,12 @@ executable ( 'gpio.c', 'gpio.h', 'manager.c', 'manager.h', 'mm-iface.c', 'mm-iface.h', + 'ofono-iface.c', 'ofono-iface.h', 'suspend.c', 'suspend.h', 'toml.c', 'toml.h', 'udev.c', 'udev.h', ], dependencies : mgr_deps, + link_with: gdbofono_lib, install : true ) diff --git a/src/mm-iface.c b/src/mm-iface.c index 8afe2ea..d6a74f8 100644 --- a/src/mm-iface.c +++ b/src/mm-iface.c @@ -163,6 +163,12 @@ 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."); + 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); } diff --git a/src/ofono-iface.c b/src/ofono-iface.c new file mode 100644 index 0000000..bc37f38 --- /dev/null +++ b/src/ofono-iface.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2020 Oliver Smith + * Copyright (C) 2021 Bhushan Shah + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "ofono-iface.h" + +#include + +#include +#include + +#define OFONO_SERVICE "org.ofono" + +static void modem_added_cb(GDBOManager *manager_proxy, + const gchar *path, + GVariant *properties, + struct EG25Manager *manager) +{ + GVariant *modem_path; + g_debug("Adding ofono modem '%s'", path); + + if (manager->modem_state == EG25_STATE_RESUMING) { + if (manager->modem_recovery_timer) { + g_source_remove(manager->modem_recovery_timer); + manager->modem_recovery_timer = 0; + } + modem_resume_post(manager); + manager->modem_state = EG25_STATE_CONFIGURED; + } + + if (manager->modem_state < EG25_STATE_ACQUIRED) + manager->modem_state = EG25_STATE_ACQUIRED; + + if (manager->modem_state < EG25_STATE_CONFIGURED) + modem_configure(manager); + + modem_path = g_variant_lookup_value(properties, "SystemPath", G_VARIANT_TYPE_STRING); + if (manager->modem_usb_id) + g_free(manager->modem_usb_id); + 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 get_modems_cb(GDBOManager *manager_proxy, + GAsyncResult *res, + struct EG25Manager *manager) +{ + gboolean ok; + GVariant *modems; + GVariantIter *modems_iter = NULL; + g_autoptr(GError) error = NULL; + + const gchar *path; + GVariant *properties; + + 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)) { + g_debug("Got modem object path '%s'", path); + modem_added_cb(manager_proxy, path, properties, manager); + } + g_variant_iter_free(modems_iter); + g_variant_unref(modems); +} + +static void ofono_appeared_cb(GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + struct EG25Manager *manager) +{ + GError *error = NULL; + + 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."); + return; + } + /* now connect to oFono! */ + manager->ofono_connection = connection; + manager->ofono_manager = gdbo_manager_proxy_new_sync(connection, + G_DBUS_PROXY_FLAGS_NONE, + OFONO_SERVICE, + "/", + NULL, + &error); + if (!manager->ofono_manager) { + g_critical("Error creating ofono object manager proxy: %s", error->message); + return; + } + + 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); + + gdbo_manager_call_get_modems(manager->ofono_manager, + NULL, + (GAsyncReadyCallback) get_modems_cb, + manager); +} + +static void ofono_vanished_cb(GDBusConnection *connection, + const gchar *name, + struct EG25Manager *manager) +{ + g_message("oFono vanished from D-Bus"); + + if (manager->modem_iface == MODEM_IFACE_OFONO) { + manager->modem_iface = MODEM_IFACE_NONE; + ofono_iface_destroy(manager); + } +} + +void ofono_iface_init(struct EG25Manager *manager) +{ + 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); +} + +void ofono_iface_destroy(struct EG25Manager *manager) +{ + if (manager->modem_usb_id) { + g_free(manager->modem_usb_id); + manager->modem_usb_id = NULL; + } + if (manager->ofono_watch != 0) { + g_bus_unwatch_name(manager->ofono_watch); + manager->ofono_watch = 0; + } +} diff --git a/src/ofono-iface.h b/src/ofono-iface.h new file mode 100644 index 0000000..fd3766e --- /dev/null +++ b/src/ofono-iface.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2020 Oliver Smith + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "manager.h" + +void ofono_iface_init(struct EG25Manager *data); +void ofono_iface_destroy(struct EG25Manager *data); diff --git a/src/suspend.c b/src/suspend.c index 256636e..b82ca7e 100644 --- a/src/suspend.c +++ b/src/suspend.c @@ -170,11 +170,14 @@ static void signal_cb(GDBusProxy *proxy, g_message("system is resuming"); take_inhibitor(manager, FALSE); modem_resume_pre(manager); - if (manager->mm_modem) { + if (manager->mm_modem || manager->modem_iface == MODEM_IFACE_OFONO) { /* * On some systems ModemManager doesn't handle suspend/resume, so * we still have a valid/managed modem when resuming. In this case, * do the whole resume sequence immediately. + * + * If modem is managed by ofono, we also do resume sequence immediately + * as ofono handles resuming from sleep itself. */ manager->modem_state = EG25_STATE_CONFIGURED; modem_resume_post(manager);