From: Sjur Brændeland <[email protected]>
This patch introduces auto discovery of ST-Ericsson modems.
ST-Ericsson modems (M57XX, M7XX, M74XX) are managed by a
Modem Init Daemon responsible for start, power cycles,
flashing etc. This STE plugin monitors the modem state exposed
from the Modem Init Damon's Dbus API. When the modem is in state
"on" the STE modem is created and registered. Muliple modem
instances, and reset handling is supported.
---
Hi Marcel.
I think I have resolved most of your comments on my last patch set,
including the massive confusion caused by calling this MID ;-)
The only remark left is "ResendState". I have done this as simple as
possible where you just re-send all state information for all modem
instances and implicit get the object-path (serial-id) for each modem
when the StateChange signal is received.
I really don't think resending the state information should be of much
concern as this only happens once - when oFono starts. The extra cost
of waking the other two STE daemons should be negligible, as they most
likely are initializing and preparing for communicating with the STE-modem
anyway.
Regards,
Sjur
Makefile.am | 3 +
plugins/stemgr.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 313 insertions(+), 0 deletions(-)
create mode 100644 plugins/stemgr.c
diff --git a/Makefile.am b/Makefile.am
index 12b3c33..d9c0505 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -221,6 +221,9 @@ builtin_sources += drivers/atmodem/atutil.h \
drivers/ifxmodem/gprs-context.c \
drivers/ifxmodem/stk.c
+builtin_modules += stemgr
+builtin_sources += plugins/stemgr.c
+
builtin_modules += stemodem
builtin_sources += drivers/atmodem/atutil.h \
drivers/stemodem/stemodem.h \
diff --git a/plugins/stemgr.c b/plugins/stemgr.c
new file mode 100644
index 0000000..6317516
--- /dev/null
+++ b/plugins/stemgr.c
@@ -0,0 +1,309 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 ST-Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <net/if.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/dbus.h>
+
+/*
+ * ST-Ericsson's Modem Init Daemon is used for controling the modem power
+ * cycles and provides a dbus API for modem state and properties.
+ */
+#define MGR_SERVICE "com.stericsson.modeminit"
+#define MGR_INTERFACE MGR_SERVICE ".Modem"
+
+/* The signal StateChange sends the modem state.*/
+#define STATUS_CHANGED "StateChange"
+
+#define MGR_ACTION_ON "on" /* Modem is on */
+#define MGR_ACTION_RESET "dumping" /* Modem is resetting */
+
+/*
+ * ResendState requests resending of StateChange. This method is only
+ * called at startup, in order to retrieve the modem's serial id,
+ * (object path) and state.
+ */
+#define MGR_RESEND_STATE "ResendState"
+
+/* GetCaifIfName requests the CAIF Interface Name. */
+#define MGR_GET_CAIFIF "GetCaifIfName"
+
+#define TIMEOUT 5000
+
+enum ste_state {
+ STE_PENDING, /* Waiting for caifif and "on" notification */
+ STE_PENDING_IF, /* Waiting for caifif, already got "on" */
+ STE_REGISTERED, /* Modem is registered */
+ STE_RESETTING /* Modem is resetting */
+};
+
+struct ste_modem {
+ char *path;
+ struct ofono_modem *modem;
+ enum ste_state state;
+ gboolean got_caifif;
+ gboolean pending_call;
+};
+
+static GHashTable *modem_list;
+static guint mgr_api_watch;
+static guint mgr_state_watch;
+static DBusConnection *connection;
+
+static void get_caifif_reply(DBusPendingCall *call, void *user_data)
+{
+ DBusMessage *reply;
+ char *ifname;
+ struct ste_modem *stemodem = user_data;
+
+ stemodem->pending_call = FALSE;
+ stemodem->got_caifif = TRUE;
+ reply = dbus_pending_call_steal_reply(call);
+
+ if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
+ ofono_error("STE Modem Init Daemon: unavailable");
+ goto error;
+ }
+
+ if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &ifname,
+ DBUS_TYPE_INVALID) == FALSE) {
+ ofono_error("STE Modem Init Daemon: bad signature for %s",
+ MGR_GET_CAIFIF);
+ goto error;
+ }
+
+ if (strlen(ifname) > IF_NAMESIZE) {
+ ofono_error("STE Modem Init Daemon: %s bad response %s\n",
+ MGR_GET_CAIFIF, ifname);
+ goto error;
+ }
+
+ if (ifname != NULL) {
+ DBG("STE Modem '%s' uses CAIF interface '%s'\n", stemodem->path,
+ ifname);
+ ofono_modem_set_string(stemodem->modem, "Interface",
+ ifname);
+ }
+
+error:
+ if (stemodem->state == STE_PENDING_IF) {
+ DBG("Register STE modem %s", stemodem->path);
+ ofono_modem_register(stemodem->modem);
+ stemodem->state = STE_REGISTERED;
+ }
+
+ dbus_message_unref(reply);
+}
+
+static void get_caif_interface(const char *path, struct ste_modem *stemodem)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ stemodem->pending_call = TRUE;
+ message = dbus_message_new_method_call(MGR_SERVICE, path,
+ MGR_INTERFACE, MGR_GET_CAIFIF);
+
+ if (!message) {
+ ofono_error("Unable to allocate new D-Bus message");
+ goto error;
+ }
+
+ dbus_message_set_auto_start(message, FALSE);
+
+ if (dbus_connection_send_with_reply(connection, message,
+ &call, TIMEOUT) == FALSE) {
+ ofono_error("Sending D-Bus message failed");
+ stemodem->got_caifif = TRUE;
+ goto error;
+ }
+
+ if (call == NULL) {
+ DBG("D-Bus connection not available");
+ stemodem->got_caifif = TRUE;
+ goto error;
+ }
+
+ dbus_pending_call_set_notify(call, get_caifif_reply, stemodem, NULL);
+ dbus_pending_call_unref(call);
+
+error:
+ dbus_message_unref(message);
+}
+
+static void handle_stemodem(const char *action, const char *path)
+{
+ struct ste_modem *stemodem = g_hash_table_lookup(modem_list, path);
+
+ if (stemodem == NULL) {
+ DBG("created STE modem %s", path);
+ stemodem = g_try_new0(struct ste_modem, 1);
+ if (stemodem == NULL)
+ return;
+
+ /* remove '/' from path to create a leagal modem name */
+ stemodem->modem = ofono_modem_create(path+1, "ste");
+ if (stemodem->modem == NULL) {
+ ofono_error("STE Modem Init: Bad path: '%s'\n", path);
+ g_free(stemodem);
+ return;
+ }
+
+ stemodem->path = g_strdup(path);
+ stemodem->state = STE_PENDING;
+ g_hash_table_insert(modem_list, stemodem->path, stemodem);
+ }
+
+ if (!stemodem->got_caifif) {
+ DBG("request caif interface %s", path);
+ get_caif_interface(path, stemodem);
+ stemodem->state = STE_PENDING;
+ }
+
+ switch (stemodem->state) {
+ case STE_PENDING:
+ if (g_strcmp0(action, MGR_ACTION_ON) != 0)
+ break;
+ if (stemodem->got_caifif) {
+ DBG("register STE modem %s", path);
+ ofono_modem_register(stemodem->modem);
+ stemodem->state = STE_REGISTERED;
+ } else
+ stemodem->state = STE_PENDING_IF;
+ break;
+ case STE_PENDING_IF:
+ break;
+ case STE_REGISTERED:
+ if (g_strcmp0(action, MGR_ACTION_RESET) == 0) {
+ DBG("reset ongoing %s", path);
+ /* NOTE: Should we set powered = FALSE here? */
+ stemodem->state = STE_RESETTING;
+ } else if (g_strcmp0(action, MGR_ACTION_ON) != 0) {
+ DBG("STE modem unregistering %s %s", path, action);
+ g_hash_table_remove(modem_list, path);
+ }
+
+ break;
+ case STE_RESETTING:
+ if (g_strcmp0(action, MGR_ACTION_ON) == 0) {
+ DBG("STE modem reset complete %s", path);
+ if (ofono_modem_get_powered(stemodem->modem))
+ ofono_modem_reset(stemodem->modem);
+ } else if (g_strcmp0(action, MGR_ACTION_RESET) != 0) {
+ DBG("STE modem unregistering %s %s", path, action);
+ g_hash_table_remove(modem_list, path);
+ }
+
+ break;
+ }
+}
+
+static gboolean mgr_signal_status_change(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ const char *state;
+ const char *path = dbus_message_get_path(message);
+
+ if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &state,
+ DBUS_TYPE_INVALID) == FALSE) {
+ ofono_error("STE Modem Init Daemon: invalid signal signature");
+ return FALSE;
+ }
+
+ if (g_strcmp0(path, "/") == 0)
+ return TRUE;
+
+ handle_stemodem(state, path);
+ return TRUE;
+}
+
+static void mgr_connect(DBusConnection *connection, void *user_data)
+{
+ DBusMessage *message;
+
+ mgr_state_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ MGR_INTERFACE,
+ STATUS_CHANGED,
+ mgr_signal_status_change,
+ NULL, NULL);
+
+ message = dbus_message_new_method_call(MGR_SERVICE, "/",
+ MGR_INTERFACE, MGR_RESEND_STATE);
+ if (!message) {
+ ofono_error("Unable to allocate new D-Bus message");
+ goto error;
+ }
+
+ if (dbus_connection_send(connection, message, NULL) == FALSE)
+ ofono_error("Sending D-Bus message failed");
+
+error:
+ dbus_message_unref(message);
+}
+
+static void mgr_disconnect(DBusConnection *connection, void *user_data)
+{
+ g_hash_table_remove_all(modem_list);
+ g_dbus_remove_watch(connection, mgr_state_watch);
+}
+
+static void destroy_stemodem(gpointer data)
+{
+ struct ste_modem *stemodem = data;
+
+ ofono_modem_remove(stemodem->modem);
+ g_free(stemodem->path);
+ g_free(stemodem);
+}
+
+static int stemgr_init()
+{
+ connection = ofono_dbus_get_connection();
+
+ modem_list = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, destroy_stemodem);
+ mgr_api_watch = g_dbus_add_service_watch(connection, MGR_SERVICE,
+ mgr_connect, mgr_disconnect, NULL, NULL);
+ return 0;
+}
+
+static void stemgr_exit()
+{
+ g_hash_table_destroy(modem_list);
+ g_dbus_remove_watch(connection, mgr_api_watch);
+}
+
+OFONO_PLUGIN_DEFINE(stemgr, "oFono client of ST-Ericsson Modem Init Daemon",
+ VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
+ stemgr_init, stemgr_exit)
--
1.7.0.4
_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono