Skip to contentSkip to conversation

plugin/ste: Use D-Bus API from Modem Init Daemon for autoconfig.

RFC In review Sjur Brændeland 3 participants 7 messages Nov 4, 2010 – Nov 17, 2010

lore
Share & tools
lore
#0 lore raw

RFC 1/1 plugin/ste: Use D-Bus API from Modem Init Daemon for autoconfig.

From: Sjur Brændeland <[email protected]>

This patch introduces auto discovery of ST-Ericsson modems. ST-Ericsson modems are managed by a Modem Init Daemon which is responsible for start/stop/restart flashing etc. The STE plugin monitors the modem state exposed from the Modem Init Damon Dbus API. When the modem is in state "on" the STE modem is created and registered.

The reason for not using the standard udev paradigm is that the CAIF device is up before the modem is ready to setup AT channels. For flashless modems CAIF is used as part of the boot. The Modem Init Daemon is managing the flashless boot procedure and sets the State to "on" when the modem is available.

---
 plugins/ste.c |  146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 145 insertions(+), 1 deletions(-)
plugins/ste.c +145 -1
index 508ad58..3e6b895 100644
@@ -32,6 +32,7 @@
 #include <unistd.h>
 #include <net/if.h>
 
+#include <gdbus.h>
 #include <glib.h>
 #include <gatchat.h>
 
@@ -73,6 +74,144 @@ struct ste_data {
 	gboolean have_sim;
 };
 
+/*
+ * ST-Ericsson's modem init daemon defines the signal StateChange
+ * and the method GetState. When state is "on" the STE modem is
+ * created and registered.
+ */
+#define STATUS_CHANGED	"StateChange"
+#define MID_SERVICE	"com.stericsson.mid"
+#define MID_INTERFACE	MID_SERVICE ".Modem"
+#define GET_STATE	"GetState"
+#define MID_STATE_ON	"on"
+#define MID_STATE_DISCONNECT	"disconnect"
+#define TIMEOUT	5000
+
+static struct ofono_modem *ste_modem;
+static guint mid_api_watch;
+static guint mid_state_watch;
+
+static void handle_stemodem(const char *state)
+{
+
+	if (strcmp(state, MID_STATE_ON) == 0) {
+		int err;
+
+		if (ste_modem != NULL)
+			return;
+
+		ste_modem = ofono_modem_create("ste", "ste");
+		DBG("register STE modem");
+		err = ofono_modem_register(ste_modem);
+	} else {
+		if (ste_modem == NULL)
+			return;
+		ofono_modem_remove(ste_modem);
+		ste_modem = NULL;
+	}
+}
+
+static void mid_getstate_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusMessage *reply;
+	char *state;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	if (dbus_message_is_error(reply, DBUS_ERROR_SERVICE_UNKNOWN)) {
+		ofono_error("STE Modem Init Daemon is unavailable");
+		goto error;
+	}
+
+	if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &state,
+					DBUS_TYPE_INVALID) == FALSE) {
+		ofono_error("STE Modem Init Damon: bad signature for GetState");
+		goto error;
+	}
+
+	handle_stemodem(state);
+error:
+	dbus_message_unref(reply);
+}
+
+static gboolean mid_signal_status_change(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	const char *state = NULL;
+
+	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;
+	}
+
+	handle_stemodem(state);
+	return TRUE;
+}
+
+static void mid_connect(DBusConnection *connection, void *user_data)
+{
+	DBusMessage *message;
+	DBusPendingCall *call;
+
+	message = dbus_message_new_method_call(MID_SERVICE, "/",
+					MID_INTERFACE, "GetState");
+	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");
+		goto error;
+	}
+
+	if (call == NULL) {
+		DBG("D-Bus connection not available");
+		goto error;
+	}
+
+	dbus_pending_call_set_notify(call, mid_getstate_reply, NULL, NULL);
+	dbus_pending_call_unref(call);
+error:
+	dbus_message_unref(message);
+}
+
+static void mid_disconnect(DBusConnection *connection, void *user_data)
+{
+	handle_stemodem(MID_STATE_DISCONNECT);
+}
+
+static int modem_initd_setup()
+{
+	DBusConnection *connection;
+
+	connection = ofono_dbus_get_connection();
+	if (connection == NULL)
+		return -EIO;
+
+	mid_api_watch = g_dbus_add_service_watch(connection, MID_SERVICE,
+				mid_connect, mid_disconnect, NULL, NULL);
+
+	mid_state_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+						MID_INTERFACE,
+						STATUS_CHANGED,
+						mid_signal_status_change,
+						NULL, NULL);
+
+	return 0;
+}
+
+static void modem_initd_teardown()
+{
+	DBusConnection *connection = ofono_dbus_get_connection();
+	g_dbus_remove_watch(connection, mid_state_watch);
+	g_dbus_remove_watch(connection, mid_api_watch);
+}
+
 static int ste_probe(struct ofono_modem *modem)
 {
 	struct ste_data *data;
@@ -382,12 +521,17 @@ static struct ofono_modem_driver ste_driver = {
 
 static int ste_init(void)
 {
-	return ofono_modem_driver_register(&ste_driver);
+	int err;
+	err = ofono_modem_driver_register(&ste_driver);
+	if (err < 0)
+		return err;
+	return modem_initd_setup();
 }
 
 static void ste_exit(void)
 {
 	ofono_modem_driver_unregister(&ste_driver);
+	modem_initd_teardown();
 }
 
 OFONO_PLUGIN_DEFINE(ste, "ST-Ericsson modem driver", VERSION,
Signature · 1 line
1.6.3.3
#1 lore raw

Hi Sjur,

Quoted 7 lines

This patch introduces auto discovery of ST-Ericsson modems. ST-Ericsson modems are managed by a Modem Init Daemon which is responsible for start/stop/restart flashing etc. The STE plugin monitors the modem state exposed from the Modem Init Damon Dbus API. When the modem is in state "on" the STE modem is created and registered.

Quoted 5 lines

The reason for not using the standard udev paradigm is that the CAIF device is up before the modem is ready to setup AT channels. For flashless modems CAIF is used as part of the boot. The Modem Init Daemon is managing the flashless boot procedure and sets the State to "on" when the modem is available.

so I don't like this at all. This looks pretty nasty and like an ugly hack to get something working.

Please show us what Modem Init Daemon is actually doing.

Regards

Marcel

#2 lore raw

Hi Marcel,

Quoted 13 lines
Quoted 7 lines

This patch introduces auto discovery of ST-Ericsson modems. ST-Ericsson modems are managed by a Modem Init Daemon which is responsible for start/stop/restart flashing etc. The STE plugin monitors the modem state exposed from the Modem Init Damon Dbus API. When the modem is in state "on" the STE modem is created and registered.

Quoted 5 lines

The reason for not using the standard udev paradigm is that the CAIF device is up before the modem is ready to setup AT channels. For flashless modems CAIF is used as part of the boot. The Modem Init Daemon is managing the flashless boot procedure and sets the State to "on" when the modem is available.

Quoted 4 lines

so I don't like this at all. This looks pretty nasty and like an ugly hack to get something working.

Please show us what Modem Init Daemon is actually doing.

As mentioned above the Modem Init Daemon is responsible for:
- Toggling the different GPIOs, powering the modem on/off.
- Boot the modem and upload the firmware in several stages.
a) Initial Z-Protocol, for handshaking the modem
b) PROTROM boot protocol to upload modem firmware.
c) CAIF Remote File System protocol for further firmware loading (modules)
d) CAIF Remote File System protocol for serving modem file system.
- Monitoring the GPIOs for modem restart and act upon this.
- Enabling/Disabling the CAIF Link Layer Interface according to the modem state (GPIO).
- Monitoring Thermal and Battery Warnings URC over AT
and acting upon this.
- In case of modem crash, the crash-dump from the modem must be downloaded to host. This needs to be synchronized so that the reboot of the modem is not started before the dump is complete.
- Modem Init daemon has to expose an API in for:
o triggering restart
o signal modem status
o initiate upgrade

The Modem Init Daemon will be available in product quality under Apache License, and will be in use for several platforms (not just MeeGo) and modem versions.

The issue we have is that when the CAIF Link Layer Interface is up it does not necessarily mean that the Modem is fully started.
So we need to have a way to synchronize other services and modem clients when the modem is ready. The other services that needs this ready notification
are: oFono, Remote File Manager, Logging Daemon. On other platforms than MeeGo there are AT based clients such as Audio, AGPS, RIL as well.

We definitely need a synchronization mechanism between Modem Init Daemon and the other services, so we decided to use a D-Bus API for the Modem Init Daemon to expose the modem state and an API for initiating power-off, upgrade and reboot.

Regards,
Sjur

#3 lore raw

Hi Sjur,

Quoted 50 lines
Quoted 13 lines
Quoted 7 lines

This patch introduces auto discovery of ST-Ericsson modems. ST-Ericsson modems are managed by a Modem Init Daemon which is responsible for start/stop/restart flashing etc. The STE plugin monitors the modem state exposed from the Modem Init Damon Dbus API. When the modem is in state "on" the STE modem is created and registered.

Quoted 5 lines

The reason for not using the standard udev paradigm is that the CAIF device is up before the modem is ready to setup AT channels. For flashless modems CAIF is used as part of the boot. The Modem Init Daemon is managing the flashless boot procedure and sets the State to "on" when the modem is available.

Quoted 4 lines

so I don't like this at all. This looks pretty nasty and like an ugly hack to get something working.

Please show us what Modem Init Daemon is actually doing.

As mentioned above the Modem Init Daemon is responsible for:
- Toggling the different GPIOs, powering the modem on/off.
- Boot the modem and upload the firmware in several stages.
a) Initial Z-Protocol, for handshaking the modem
b) PROTROM boot protocol to upload modem firmware.
c) CAIF Remote File System protocol for further firmware loading (modules)
d) CAIF Remote File System protocol for serving modem file system.
- Monitoring the GPIOs for modem restart and act upon this.
- Enabling/Disabling the CAIF Link Layer Interface according to the modem state (GPIO).
- Monitoring Thermal and Battery Warnings URC over AT
and acting upon this.
- In case of modem crash, the crash-dump from the modem must be downloaded to host. This needs to be synchronized so that the reboot of the modem is not started before the dump is complete.
- Modem Init daemon has to expose an API in for:
o triggering restart
o signal modem status
o initiate upgrade

The Modem Init Daemon will be available in product quality under Apache License, and will be in use for several platforms (not just MeeGo) and modem versions.

The issue we have is that when the CAIF Link Layer Interface is up it does not necessarily mean that the Modem is fully started.
So we need to have a way to synchronize other services and modem clients when the modem is ready. The other services that needs this ready notification
are: oFono, Remote File Manager, Logging Daemon. On other platforms than MeeGo there are AT based clients such as Audio, AGPS, RIL as well.

Quoted 4 lines

We definitely need a synchronization mechanism between Modem Init Daemon and the other services, so we decided to use a D-Bus API for the Modem Init Daemon to expose the modem state and an API for initiating power-off, upgrade and reboot.

do you have a link to the D-Bus of this daemon? I would prefer if you publish it first or at least the part of it used here.

Also you can not squeeze this into plugins/ste.c as you have done. You need to have a separate plugin that does modem detection. Like we do with udev for other modems.

I am also not sure that we do need this kind of D-Bus API. For example using the differentiation between IFF_UP, IFF_RUNNING and IFF_LOWER_UP could be easily used to define which parts of an interface are up and initialized.

We do something similar with wpa_supplicant and WiFi in Linux. Have you looked at doing this properly with kernel available flags instead of just forcing another D-Bus API and daemon?

Regards

Marcel

#4 lore raw

Hi Marcel.

Quoted 7 lines
Quoted 4 lines

We definitely need a synchronization mechanism between Modem Init Daemon and the other services, so we decided to use a D-Bus API for the Modem Init Daemon to expose the modem state and an API for initiating power-off, upgrade and reboot.

do you have a link to the D-Bus of this daemon? I would prefer if you publish it first or at least the part of it used here.

This is an extract of the Modem Init Daemon D-Bus API. Should I could put this the git for reference e.g. in drivers/stemodem/?

Modem Init Deamon
================

Service com.stericsson.modeminit
Interface com.stericsson.modeminit.Modem
Object path /

Methods

string GetState()

Return the current state of the modem.

Signals StateChange(string status)

The modems state sent from Modem Init Daemon when a modem state change occurs.

"booting" Modem is powered up (flashed version)
or Modem is powered up and firmware upload is completed. (flashless version)
"upgrading" Firmware upgrade on going
or Flashing manager under execution - modem in service mode.
"on" Modem has booted and is ready for use.
This implies that all AT channels are available, the modem might be in e.g. flight mode.
"dumping" Modem has crashed and dump is ongoing
"off" Modem is powered off.

Quoted 3 lines

Also you can not squeeze this into plugins/ste.c as you have done. You need to have a separate plugin that does modem detection. Like we do with udev for other modems.

Sure, I'll move this to another file.

Quoted 8 lines

I am also not sure that we do need this kind of D-Bus API. For example using the differentiation between IFF_UP, IFF_RUNNING and IFF_LOWER_UP could be easily used to define which parts of an interface are up and initialized.

We do something similar with wpa_supplicant and WiFi in Linux. Have you looked at doing this properly with kernel available flags instead of just forcing another D-Bus API and daemon?

I have played around with this quite a few hours, and this is what I have found:
If you set the operstate to DORMANT and do UP on the device,
the device will be IFF_UP and IFF_RUNNING not set. In this state the device can still transmit and receive packets.

However as far as I can gather udev does not inform about operstate changes. Instead the operstate changes would have to be monitored using RTNL. In oFono we would then have to monitor link state event in order to catch operstate changes similar to what is done in gisi/netlink. Based on the operstate the CAIF Link Layer interface could then trigger registration and start of the ste driver in oFono. The ModemInitDaemon would have to use RTNL to set the CAIF Link Layer operstate.

To me this seems like a more complex solution involving more code lines, than the suggested D-BUS API solution. I don't know if it is just me, but architecturally I think is cleaner to communicate directly to the Modem Init Daemon using D-Bus, rather than having ModemInitDaemon setting the operstate on the CAIF device using RTNL, and then having oFono taking information from both udev and RTNL in order know the state set by the Modem Init Daemon.

Regards,
Sjur

#5 lore raw

Hi Sjur,

Quoted 11 lines
Quoted 7 lines
Quoted 4 lines

We definitely need a synchronization mechanism between Modem Init Daemon and the other services, so we decided to use a D-Bus API for the Modem Init Daemon to expose the modem state and an API for initiating power-off, upgrade and reboot.

do you have a link to the D-Bus of this daemon? I would prefer if you publish it first or at least the part of it used here.

This is an extract of the Modem Init Daemon D-Bus API. Should I could put this the git for reference e.g. in drivers/stemodem/?

Quoted 6 lines

Modem Init Deamon
================

Service com.stericsson.modeminit
Interface com.stericsson.modeminit.Modem
Object path /

so how to you handle the case if you have two or more CAIF based modems in the system? oFono does not impose a limit here.

Regards

Marcel

#6 lore raw

Hi Marcel.

Quoted 2 lines

so how to you handle the case if you have two or more CAIF based modems in the system? oFono does not impose a limit here.

I guess there are at least two different scenarios here:

a) DualSim - In this case the Modem Init Daemon is working with one piece of HW, and will expose one instance in the Dbus API. We would have only one CAIF Link Layer interface.
The concept of two virtual modems should probably be handled by the STE plugin that would have to register two modem instances with two sets of AT channels to the different virtual modem instances.

b) Testing - In some test setups it might be interesting having two or more STE modems. In this scenario we should probably be able to support multiple instances of modems and multiple CAIF Link Layer instances. oFono would then need to know the CAIF Link Layer instance to bind to.

There might be other scenarios I haven't thought of. Did you have anything particular in mind Marcel?

I would really prefer if we could get the basics implemented with one modem instance, and then look at the scenario with multiple modem instances as the next step. For now I think we should only update the Dbus-API so that more than one object path can be handled. Would this be acceptable to you Marcel?

Regards,
Sjur