aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/dispatcher-modem-setup/0000:000025
-rw-r--r--data/dispatcher-modem-setup/meson.build26
-rw-r--r--meson.build1
-rw-r--r--src/meson.build3
-rw-r--r--src/mm-base-manager.c105
-rw-r--r--src/mm-base-modem.c26
-rw-r--r--src/mm-dispatcher-modem-setup.c150
-rw-r--r--src/mm-dispatcher-modem-setup.h50
8 files changed, 359 insertions, 27 deletions
diff --git a/data/dispatcher-modem-setup/0000:0000 b/data/dispatcher-modem-setup/0000:0000
new file mode 100644
index 00000000..6489e9b3
--- /dev/null
+++ b/data/dispatcher-modem-setup/0000:0000
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# SPDX-License-Identifier: CC0-1.0
+# 2024 Nero Sinaro <xu.zhang@fibocom.com>
+#
+# modem setup test script
+#
+# This is the test script:
+# Parameter list: vid pid device_path port_name
+# device_path: Path of the device on the sys file system, it's a string
+# port_name: Port name of the device enumeration, It's an array of strings
+#
+
+logger "[Test] ARGV:$@, ARG count:$#"
+
+count=1
+while [ $count -lt 10 ]; do
+ # will print logger to syslog
+ logger "[Test] (attempt #${i})"
+
+ sleep 0.5
+ count=$((count + 1))
+done
+
+exit $?
diff --git a/data/dispatcher-modem-setup/meson.build b/data/dispatcher-modem-setup/meson.build
new file mode 100644
index 00000000..812152a3
--- /dev/null
+++ b/data/dispatcher-modem-setup/meson.build
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2024 Nero Sinaro <xu.zhang@fibocom.com>
+
+# Shipped but disabled Modem setup tools
+mm_modemsetupdiravailable = mm_pkgdatadir / 'modem-setup.available.d'
+
+# Directory for user-enabled tools
+mm_modemsetupdiruser = mm_pkgsysconfdir / 'modem-setup.d'
+
+# Directory for package-enabled tools
+mm_modemsetupdirpackage = mm_pkglibdir / 'modem-setup.d'
+
+# This is a test file
+examples = files(
+ '0000:0000'
+)
+
+install_data(
+ examples,
+ install_mode: 'rwx------',
+ install_dir: mm_modemsetupdiravailable,
+)
+
+mkdir_cmd = 'mkdir -p ${DESTDIR}@0@'
+meson.add_install_script('sh', '-c', mkdir_cmd.format(mm_prefix / mm_modemsetupdiruser))
+meson.add_install_script('sh', '-c', mkdir_cmd.format(mm_prefix / mm_modemsetupdirpackage))
diff --git a/meson.build b/meson.build
index 1adc5e5d..61efb149 100644
--- a/meson.build
+++ b/meson.build
@@ -404,6 +404,7 @@ subdir('data')
if get_option('examples')
subdir('data/dispatcher-connection')
subdir('data/dispatcher-fcc-unlock')
+ subdir('data/dispatcher-modem-setup')
endif
subdir('introspection')
subdir('include')
diff --git a/src/meson.build b/src/meson.build
index 3052e219..f3a6218f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -269,6 +269,7 @@ sources = files(
'mm-dispatcher.c',
'mm-dispatcher-connection.c',
'mm-dispatcher-fcc-unlock.c',
+ 'mm-dispatcher-modem-setup.c',
'mm-filter.c',
'mm-iface-modem-3gpp.c',
'mm-iface-modem-3gpp-profile-manager.c',
@@ -308,6 +309,8 @@ endif
c_args = [
'-DMM_COMPILATION',
'-DPLUGINDIR="@0@"'.format(mm_prefix / mm_pkglibdir),
+ '-DMODEMSETUPDIRPACKAGE="@0@"'.format(mm_prefix / mm_pkglibdir / 'modem-setup.d'),
+ '-DMODEMSETUPDIRUSER="@0@"'.format(mm_prefix / mm_pkgsysconfdir / 'modem-setup.d'),
'-DFCCUNLOCKDIRPACKAGE="@0@"'.format(mm_prefix / mm_pkglibdir / 'fcc-unlock.d'),
'-DFCCUNLOCKDIRUSER="@0@"'.format(mm_prefix / mm_pkgsysconfdir / 'fcc-unlock.d'),
'-DCONNECTIONDIRPACKAGE="@0@"'.format(mm_prefix / mm_pkglibdir / 'connection.d'),
diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c
index 74e4020d..b2a14b04 100644
--- a/src/mm-base-manager.c
+++ b/src/mm-base-manager.c
@@ -59,6 +59,8 @@
#include "mm-base-modem.h"
#include "mm-iface-modem.h"
+#include "mm-dispatcher-modem-setup.h"
+
static void initable_iface_init (GInitableIface *iface);
static void log_object_iface_init (MMLogObjectInterface *iface);
@@ -201,6 +203,106 @@ find_device_support_context_free (FindDeviceSupportContext *ctx)
g_slice_free (FindDeviceSupportContext, ctx);
}
+/*****************************************************************************/
+static void
+initialize_ready (MMBaseModem *self,
+ GAsyncResult *res)
+{
+ g_autoptr(GError) error = NULL;
+
+ if (!mm_base_modem_initialize_finish (self, res, &error)) {
+ if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED)) {
+ /* FATAL error, won't even be exported in DBus */
+ mm_obj_err (self, "fatal error initializing: %s", error->message);
+ } else {
+ /* non-fatal error */
+ mm_obj_warn (self, "error initializing: %s", error->message);
+ mm_base_modem_set_valid (self, TRUE);
+ }
+ } else {
+ mm_obj_dbg (self, "modem initialized");
+ mm_base_modem_set_valid (self, TRUE);
+ }
+}
+
+static void
+dispatcher_modem_setup_ready (MMDispatcherModemSetup *dispatcher,
+ GAsyncResult *res,
+ FindDeviceSupportContext *ctx)
+{
+ g_autoptr(GError) error = NULL;
+ MMBaseModem *modem;
+
+ if (!mm_dispatcher_modem_setup_run_finish (dispatcher, res, &error)) {
+ if (!g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND)) {
+ mm_obj_err (ctx->self, "couldn't run modem setup: %s", error->message);
+ } else {
+ mm_obj_dbg (ctx->self, "no need to run modem setup");
+ }
+ }
+
+ modem = mm_device_peek_modem (ctx->device);
+ if (modem) {
+ /* As soon as we get the ports organized, we initialize the modem */
+ mm_base_modem_initialize (modem,
+ (GAsyncReadyCallback)initialize_ready,
+ NULL);
+ } else {
+ mm_obj_warn(modem, "no modem found");
+ }
+
+ find_device_support_context_free (ctx);
+}
+
+static void
+modem_setup (FindDeviceSupportContext *ctx)
+{
+ guint n_port_infos = 0;
+ g_auto(GStrv) modem_ports = NULL;
+ MMDispatcherModemSetup *dispatcher;
+ MMModemPortInfo *port_infos;
+ MMBaseModem *modem = NULL;
+ GPtrArray *aux;
+ guint i;
+
+ dispatcher = mm_dispatcher_modem_setup_get ();
+
+ modem = mm_device_peek_modem (ctx->device);
+
+ aux = g_ptr_array_new ();
+ port_infos = mm_base_modem_get_port_infos (modem, &n_port_infos);
+ for (i = 0; i < n_port_infos; i++) {
+ switch (port_infos[i].type) {
+ case MM_MODEM_PORT_TYPE_AT:
+ case MM_MODEM_PORT_TYPE_QMI:
+ case MM_MODEM_PORT_TYPE_MBIM:
+ g_ptr_array_add (aux, g_strdup (port_infos[i].name));
+ break;
+ case MM_MODEM_PORT_TYPE_UNKNOWN:
+ case MM_MODEM_PORT_TYPE_NET:
+ case MM_MODEM_PORT_TYPE_QCDM:
+ case MM_MODEM_PORT_TYPE_GPS:
+ case MM_MODEM_PORT_TYPE_AUDIO:
+ case MM_MODEM_PORT_TYPE_IGNORED:
+ default:
+ break;
+ }
+ }
+
+ mm_modem_port_info_array_free (port_infos, n_port_infos);
+ g_ptr_array_add (aux, NULL);
+ modem_ports = (GStrv) g_ptr_array_free (aux, FALSE);
+
+ mm_dispatcher_modem_setup_run (dispatcher,
+ mm_base_modem_get_vendor_id (modem),
+ mm_base_modem_get_product_id (modem),
+ mm_base_modem_get_device (modem),
+ modem_ports,
+ NULL,
+ (GAsyncReadyCallback)dispatcher_modem_setup_ready,
+ ctx);
+}
+
static void
device_support_check_ready (MMPluginManager *plugin_manager,
GAsyncResult *res,
@@ -238,7 +340,8 @@ device_support_check_ready (MMPluginManager *plugin_manager,
/* Modem now created */
mm_obj_msg (ctx->self, "modem for device '%s' successfully created",
mm_device_get_uid (ctx->device));
- find_device_support_context_free (ctx);
+
+ modem_setup (ctx);
}
static gboolean is_device_inhibited (MMBaseManager *self,
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index 2cb9383d..3ef4905f 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -1284,27 +1284,6 @@ mm_base_modem_get_port (MMBaseModem *self,
return (port ? g_object_ref (port) : NULL);
}
-static void
-initialize_ready (MMBaseModem *self,
- GAsyncResult *res)
-{
- g_autoptr(GError) error = NULL;
-
- if (!mm_base_modem_initialize_finish (self, res, &error)) {
- if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED)) {
- /* FATAL error, won't even be exported in DBus */
- mm_obj_err (self, "fatal error initializing: %s", error->message);
- } else {
- /* non-fatal error */
- mm_obj_warn (self, "error initializing: %s", error->message);
- mm_base_modem_set_valid (self, TRUE);
- }
- } else {
- mm_obj_dbg (self, "modem initialized");
- mm_base_modem_set_valid (self, TRUE);
- }
-}
-
static inline void
log_port (MMBaseModem *self,
MMPort *port,
@@ -1627,11 +1606,6 @@ mm_base_modem_organize_ports (MMBaseModem *self,
}
#endif
- /* As soon as we get the ports organized, we initialize the modem */
- mm_base_modem_initialize (self,
- (GAsyncReadyCallback)initialize_ready,
- NULL);
-
return TRUE;
}
diff --git a/src/mm-dispatcher-modem-setup.c b/src/mm-dispatcher-modem-setup.c
new file mode 100644
index 00000000..5867ecf1
--- /dev/null
+++ b/src/mm-dispatcher-modem-setup.c
@@ -0,0 +1,150 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 2 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:
+ *
+ * Copyright (C) 2023-2024 Nero Sinaro <xu.zhang@fibocom.com>
+ */
+
+#include <config.h>
+#include <sys/stat.h>
+
+#include <ModemManager.h>
+#include "mm-errors-types.h"
+#include "mm-utils.h"
+#include "mm-log-object.h"
+#include "mm-dispatcher-modem-setup.h"
+
+#if !defined MODEMSETUPDIRPACKAGE
+# error MODEMSETUPDIRPACKAGE must be defined at build time
+#endif
+
+#if !defined MODEMSETUPDIRUSER
+# error MODEMSETUPDIRUSER must be defined at build time
+#endif
+
+#define OPERATION_DESCRIPTION "modem setup"
+
+/* Maximum time a Modem Setup command is allowed to run before
+ * us killing it */
+#define MAX_MODEM_SETUP_EXEC_TIME_SECS 5
+
+struct _MMDispatcherModemSetup {
+ MMDispatcher parent;
+};
+
+struct _MMDispatcherModemSetupClass {
+ MMDispatcherClass parent;
+};
+
+G_DEFINE_TYPE (MMDispatcherModemSetup, mm_dispatcher_modem_setup, MM_TYPE_DISPATCHER)
+
+/*****************************************************************************/
+gboolean
+mm_dispatcher_modem_setup_run_finish (MMDispatcherModemSetup *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+dispatcher_run_ready (MMDispatcher *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!mm_dispatcher_run_finish (self, res, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+
+ g_object_unref (task);
+}
+
+void
+mm_dispatcher_modem_setup_run (MMDispatcherModemSetup *self,
+ guint vid,
+ guint pid,
+ const gchar *device_path,
+ const GStrv modem_ports,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autofree gchar *filename = NULL;
+ GTask *task;
+ g_auto(GStrv) argv = NULL;
+ GPtrArray *aux = NULL;
+ guint i;
+ guint j;
+
+ const gchar *enabled_dirs[] = {
+ MODEMSETUPDIRUSER, /* sysconfdir */
+ MODEMSETUPDIRPACKAGE, /* libdir */
+ };
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ filename = g_strdup_printf ("%04x:%04x", vid, pid);
+
+ /* Iterate over all enabled dirs and collect all dispatcher script paths */
+ for (i = 0; i < G_N_ELEMENTS (enabled_dirs); i++) {
+ g_autofree gchar *path = NULL;
+ g_autoptr(GFile) file = NULL;
+
+ path = g_build_path (G_DIR_SEPARATOR_S, enabled_dirs[i], filename, NULL);
+ file = g_file_new_for_path (path);
+
+ /* If file exists, we attempt to use it */
+ if (!g_file_query_exists (file, cancellable)) {
+ continue;
+ }
+
+ aux = g_ptr_array_new ();
+ g_ptr_array_add (aux, g_steal_pointer (&path));
+ g_ptr_array_add (aux, g_strdup (device_path));
+
+ for (j = 0; modem_ports && modem_ports[j]; j++) {
+ g_ptr_array_add (aux, g_strdup (modem_ports[j]));
+ }
+
+ g_ptr_array_add (aux, NULL);
+ argv = (GStrv) g_ptr_array_free (aux, FALSE);
+
+ /* run */
+ mm_dispatcher_run (MM_DISPATCHER (self),
+ argv,
+ MAX_MODEM_SETUP_EXEC_TIME_SECS,
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback) dispatcher_run_ready,
+ task);
+ return;
+ }
+
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
+ OPERATION_DESCRIPTION " operation launch aborted: no valid program found");
+ g_object_unref (task);
+}
+/*****************************************************************************/
+
+static void
+mm_dispatcher_modem_setup_init (MMDispatcherModemSetup *self)
+{
+}
+
+static void
+mm_dispatcher_modem_setup_class_init (MMDispatcherModemSetupClass *class)
+{
+}
+
+MM_DEFINE_SINGLETON_GETTER (MMDispatcherModemSetup, mm_dispatcher_modem_setup_get, MM_TYPE_DISPATCHER_MODEM_SETUP,
+ MM_DISPATCHER_OPERATION_DESCRIPTION, OPERATION_DESCRIPTION)
+
diff --git a/src/mm-dispatcher-modem-setup.h b/src/mm-dispatcher-modem-setup.h
new file mode 100644
index 00000000..8738af86
--- /dev/null
+++ b/src/mm-dispatcher-modem-setup.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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 2 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:
+ *
+ * Copyright (C) 2023-2024 Nero Sinaro <xu.zhang@fibocom.com>
+ */
+
+#ifndef MM_DISPATCHER_MODEM_SETUP_H
+#define MM_DISPATCHER_MODEM_SETUP_H
+
+#include <config.h>
+#include <gio/gio.h>
+
+#include "mm-dispatcher.h"
+
+#define MM_TYPE_DISPATCHER_MODEM_SETUP (mm_dispatcher_modem_setup_get_type ())
+#define MM_DISPATCHER_MODEM_SETUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_DISPATCHER_MODEM_SETUP, MMDispatcherModemSetup))
+#define MM_DISPATCHER_MODEM_SETUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_DISPATCHER_MODEM_SETUP, MMDispatcherModemSetupClass))
+#define MM_IS_DISPATCHER_MODEM_SETUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_DISPATCHER_MODEM_SETUP))
+#define MM_IS_DISPATCHER_MODEM_SETUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_DISPATCHER_MODEM_SETUP))
+#define MM_DISPATCHER_MODEM_SETUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_DISPATCHER_MODEM_SETUP, MMDispatcherModemSetupClass))
+
+typedef struct _MMDispatcherModemSetup MMDispatcherModemSetup;
+typedef struct _MMDispatcherModemSetupClass MMDispatcherModemSetupClass;
+typedef struct _MMDispatcherModemSetupPrivate MMDispatcherModemSetupPrivate;
+
+GType mm_dispatcher_modem_setup_get_type (void);
+MMDispatcherModemSetup *mm_dispatcher_modem_setup_get (void);
+void mm_dispatcher_modem_setup_run (MMDispatcherModemSetup *self,
+ guint vid,
+ guint pid,
+ const gchar *modem_dbus_path,
+ const GStrv ports,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean mm_dispatcher_modem_setup_run_finish (MMDispatcherModemSetup *self,
+ GAsyncResult *res,
+ GError **error);
+
+#endif /* MM_DISPATCHER_MODEM_SETUP_H */