All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jessica Nilsson <jessica.j.nilsson@stericsson.com>
To: ofono@ofono.org
Subject: [PATCH v2 1/3] u8500: add plugin for u8500
Date: Tue, 01 Feb 2011 15:13:17 +0100	[thread overview]
Message-ID: <fabc1533cadfaf5d418d3d27833e7fe8d05a8739.1296569048.git.jessica.j.nilsson@stericsson.com> (raw)
In-Reply-To: <cover.1296569048.git.jessica.j.nilsson@stericsson.com>

[-- Attachment #1: Type: text/plain, Size: 14786 bytes --]

---
 Makefile.am         |    4 +
 plugins/ofono.rules |    3 +
 plugins/u8500.c     |  507 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 514 insertions(+), 0 deletions(-)
 create mode 100644 plugins/u8500.c

diff --git a/Makefile.am b/Makefile.am
index a38fcb9..4762cc8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -110,6 +110,7 @@ builtin_sources += $(gisi_sources) \
 				drivers/isimodem/mtc.h \
 				drivers/isimodem/debug.h \
 				drivers/isimodem/isiutil.h \
+				drivers/isimodem/version.h \
 				drivers/isimodem/debug.c \
 				drivers/isimodem/phonebook.c \
 				drivers/isimodem/devinfo.c \
@@ -144,6 +145,9 @@ builtin_sources += plugins/isiusb.c
 
 builtin_modules += n900
 builtin_sources += plugins/n900.c plugins/nokia-gpio.h plugins/nokia-gpio.c
+
+builtin_modules += u8500
+builtin_sources += plugins/u8500.c
 endif
 
 if ATMODEM
diff --git a/plugins/ofono.rules b/plugins/ofono.rules
index 111f071..333bff0 100644
--- a/plugins/ofono.rules
+++ b/plugins/ofono.rules
@@ -356,6 +356,9 @@ SUBSYSTEMS=="usb", ENV{OFONO_DRIVER}="isiusb", ENV{OFONO_ISI_ADDRESS}="16"
 # Nokia N900 modem
 SUBSYSTEMS=="hsi", ENV{OFONO_DRIVER}="n900", ENV{OFONO_ISI_ADDRESS}="108"
 
+# STE u8500
+KERNEL=="shrm0", ENV{OFONO_DRIVER}="u8500"
+
 LABEL="ofono_isi_end"
 
 SUBSYSTEM!="usb", GOTO="ofono_end"
diff --git a/plugins/u8500.c b/plugins/u8500.c
new file mode 100644
index 0000000..3a3b2bc
--- /dev/null
+++ b/plugins/u8500.c
@@ -0,0 +1,507 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2010  Nokia Corporation and/or its subsidiary(-ies).
+ *  Copyright (C) ST-Ericsson SA 2011.
+ *
+ *  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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include <gisi/netlink.h>
+#include <gisi/modem.h>
+#include <gisi/client.h>
+#include <gisi/message.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+#include <ofono/phonebook.h>
+#include <ofono/netreg.h>
+#include <ofono/voicecall.h>
+#include <ofono/sms.h>
+#include <ofono/cbs.h>
+#include <ofono/sim.h>
+#include <ofono/ussd.h>
+#include <ofono/ssn.h>
+#include <ofono/call-forwarding.h>
+#include <ofono/call-settings.h>
+#include <ofono/call-barring.h>
+#include <ofono/call-meter.h>
+#include <ofono/radio-settings.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+
+#include "drivers/isimodem/isimodem.h"
+#include "drivers/isimodem/isiutil.h"
+#include "drivers/isimodem/mtc.h"
+#include "drivers/isimodem/debug.h"
+#include "drivers/isimodem/version.h"
+
+struct isi_data {
+	char const *ifname;
+	GIsiModem *modem;
+	GIsiClient *client;
+	GIsiPhonetNetlink *link;
+	GIsiPhonetLinkState linkstate;
+	unsigned interval;
+	int reported;
+	ofono_bool_t online;
+	struct isi_cb_data *online_cbd;
+};
+
+static const GIsiVersion modemversion = {
+	.major = 2,
+	.minor = 5,
+};
+
+static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
+{
+	if (g_isi_msg_error(msg) < 0) {
+		DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
+		return FALSE;
+	}
+
+	if (g_isi_msg_id(msg) != msgid) {
+		DBG("Unexpected msg: %s",
+			mce_message_id_name(g_isi_msg_id(msg)));
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static void report_powered(struct ofono_modem *modem, struct isi_data *isi,
+				ofono_bool_t powered)
+{
+	if (powered == isi->reported)
+		return;
+
+	isi->reported = powered;
+	ofono_modem_set_powered(modem, powered);
+}
+
+static void report_online(struct isi_data *isi, ofono_bool_t online)
+{
+	struct isi_cb_data *cbd = isi->online_cbd;
+	ofono_modem_online_cb_t cb = cbd->cb;
+
+	isi->online_cbd = NULL;
+
+	if (isi->online == online)
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	else
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+	g_free(cbd);
+}
+
+static void set_power_by_mce_state(struct ofono_modem *modem,
+					struct isi_data *isi, int mce_state)
+{
+	switch (mce_state) {
+	case MCE_POWER_OFF:
+		report_powered(modem, isi, FALSE);
+		break;
+	case MCE_NORMAL:
+		if (isi->online_cbd)
+			report_online(isi, mce_state == MCE_NORMAL);
+	default:
+		report_powered(modem, isi, TRUE);
+	}
+}
+
+static void mce_state_ind_cb(const GIsiMessage *msg, void *data)
+{
+	struct ofono_modem *modem = data;
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	uint8_t state;
+	uint8_t action;
+
+	if (!isi || g_isi_msg_id(msg) != MCE_MODEM_STATE_IND)
+		return;
+
+	if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
+			!g_isi_msg_data_get_byte(msg, 1, &action))
+		return;
+
+	switch (action) {
+	case MCE_START:
+		DBG("target modem state: %s (0x%02X)",
+			mce_modem_state_name(state), state);
+		break;
+
+	case MCE_READY:
+		DBG("current modem state: %s (0x%02X)",
+			mce_modem_state_name(state), state);
+		set_power_by_mce_state(modem, isi, state);
+		break;
+	default:
+		break;
+	}
+}
+
+static void mce_rf_state_ind_cb(const GIsiMessage *msg, void *data)
+{
+	struct ofono_modem *modem = data;
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	uint8_t state;
+	uint8_t action;
+
+	if (!isi || g_isi_msg_id(msg) != MCE_RF_STATE_IND)
+		return;
+
+	if (!g_isi_msg_data_get_byte(msg, 0, &state) ||
+			!g_isi_msg_data_get_byte(msg, 1, &action))
+		return;
+
+	switch (action) {
+	case MCE_READY:
+		DBG("current rf state: %s (0x%02X)",
+			mce_rf_state_name(state), state);
+		if (isi->online_cbd)
+			report_online(isi, state);
+		break;
+	case MCE_START:
+	default:
+		break;
+	}
+}
+
+static void mce_query_cb(const GIsiMessage *msg, void *data)
+{
+	struct ofono_modem *modem = data;
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	uint8_t current;
+	uint8_t target;
+
+	if (!check_response_status(msg, MCE_MODEM_STATE_QUERY_RESP))
+		return;
+
+	if (!g_isi_msg_data_get_byte(msg, 0, &current) ||
+			!g_isi_msg_data_get_byte(msg, 1, &target))
+		return;
+
+	DBG("Modem state: current=%s (0x%02X) target=%s (0x%02X)",
+		mce_modem_state_name(current), current,
+		mce_modem_state_name(target), target);
+
+	if (current == target)
+		set_power_by_mce_state(modem, isi, current);
+}
+
+static gboolean bootstrap_current_state(gpointer user)
+{
+	struct ofono_modem *om = user;
+	struct isi_data *isi = ofono_modem_get_data(om);
+
+	const uint8_t req[] = {
+		MCE_MODEM_STATE_QUERY_REQ,
+		0x00, 0x00 /* Filler */
+	};
+	size_t len = sizeof(req);
+
+	g_isi_client_send(isi->client, req, len, mce_query_cb, om, NULL);
+
+	return FALSE;
+}
+
+static void reachable_cb(const GIsiMessage *msg, void *data)
+{
+	struct ofono_modem *om = data;
+	struct isi_data *isi = ofono_modem_get_data(om);
+
+	if (!g_isi_msg_error(msg) < 0)
+		return;
+
+	ISI_VERSION_DBG(msg);
+
+	g_isi_client_ind_subscribe(isi->client, MCE_MODEM_STATE_IND,
+					mce_state_ind_cb, om);
+
+	g_isi_client_ind_subscribe(isi->client, MCE_RF_STATE_IND,
+					mce_rf_state_ind_cb, om);
+
+	/*
+	 * FIXME: There is a theoretical race condition here:
+	 * g_isi_client_ind_subscribe() adds the actual message
+	 * sending for committing changes to subscriptions in idle
+	 * loop, which may or may not preserve ordering.  Thus, we
+	 * might miss a state indication if the bootstrap request ends
+	 * up being sent first.
+	 */
+	g_idle_add(bootstrap_current_state, om);
+}
+
+static void phonet_status_cb(GIsiModem *modem, GIsiPhonetLinkState st,
+				char const *ifname, void *data)
+{
+	struct ofono_modem *om = data;
+	struct isi_data *isi = ofono_modem_get_data(om);
+
+	DBG("Link %s (%u) is %s", isi->ifname, g_isi_modem_index(isi->modem),
+		st == PN_LINK_REMOVED ? "removed" :
+		st == PN_LINK_DOWN ? "down" : "up");
+
+	isi->linkstate = st;
+
+	if (st == PN_LINK_UP)
+		g_isi_client_verify(isi->client, reachable_cb, om, NULL);
+	else if (st == PN_LINK_DOWN)
+		set_power_by_mce_state(om, isi, MCE_POWER_OFF);
+}
+
+static int u8500_probe(struct ofono_modem *modem)
+{
+	const char *ifname = ofono_modem_get_string(modem, "Interface");
+	unsigned address = ofono_modem_get_integer(modem, "Address");
+	GIsiModem *isimodem;
+	GIsiClient *client = NULL;
+	GIsiPhonetNetlink *link = NULL;
+	struct isi_data *isi = NULL;
+
+	if (!ifname)
+		return -EINVAL;
+
+	DBG("(%p) with %s", modem, ifname);
+
+	isimodem = g_isi_modem_create_by_name(ifname);
+	if (!isimodem) {
+		DBG("Interface=%s: %s", ifname, strerror(errno));
+		return -errno;
+	}
+
+	if (!g_isi_modem_set_version(isimodem, modemversion))
+		return -EINVAL;
+
+	g_isi_modem_set_userdata(isimodem, modem);
+
+	if (getenv("OFONO_ISI_DEBUG"))
+		g_isi_modem_set_debug(isimodem, ofono_debug);
+
+	if (getenv("OFONO_ISI_TRACE"))
+		g_isi_modem_set_trace(isimodem, isi_trace);
+
+	if (g_isi_pn_netlink_by_modem(isimodem)) {
+		DBG("%s: %s", ifname, strerror(EBUSY));
+		errno = EBUSY;
+		goto error;
+	}
+
+	link = g_isi_pn_netlink_start(isimodem, phonet_status_cb, modem);
+	if (link == NULL) {
+		DBG("%s: %s", ifname, strerror(errno));
+		goto error;
+	}
+
+	if (address) {
+		int error = g_isi_pn_netlink_set_address(isimodem, address);
+		if (error && error != -EEXIST) {
+			DBG("g_isi_pn_netlink_set_address(): %s\n",
+				strerror(-error));
+			errno = -error;
+			goto error;
+		}
+	}
+
+	isi = g_try_new0(struct isi_data, 1);
+	if (!isi) {
+		errno = ENOMEM;
+		goto error;
+	}
+
+	client = g_isi_client_create(isimodem, PN_MODEM_MCE);
+	if (!client)
+		goto error;
+
+	isi->modem = isimodem;
+	isi->ifname = ifname;
+	isi->link = link;
+	isi->reported = -1;
+	isi->client = client;
+
+	ofono_modem_set_data(modem, isi);
+	return 0;
+
+error:
+	g_isi_pn_netlink_stop(link);
+	g_isi_client_destroy(client);
+	g_isi_modem_destroy(isimodem);
+	g_free(isi);
+
+	return -errno;
+}
+
+static void u8500_remove(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+
+	ofono_modem_set_data(modem, NULL);
+
+	if (isi == NULL)
+		return;
+
+	g_isi_pn_netlink_stop(isi->link);
+	g_isi_client_destroy(isi->client);
+	g_isi_modem_destroy(isi->modem);
+	g_free(isi);
+}
+
+static void mce_state_cb(const GIsiMessage *msg, void *data)
+{
+	struct isi_cb_data *cbd = data;
+	struct ofono_modem *modem = cbd->user;
+	ofono_modem_online_cb_t cb = cbd->cb;
+
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	uint8_t cause;
+
+	if (!check_response_status(msg, MCE_RF_STATE_RESP))
+		goto error;
+
+	if (!g_isi_msg_data_get_byte(msg, 0, &cause))
+		goto error;
+
+	DBG("MCE cause: %s (0x%02X)", mce_status_info(cause), cause);
+
+	if (cause == MCE_OK) {
+		isi->online_cbd = cbd;
+		return;
+	}
+
+	if (cause == MCE_ALREADY_ACTIVE) {
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		g_free(cbd);
+		return;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+	g_free(cbd);
+}
+
+static void u8500_online(struct ofono_modem *modem, ofono_bool_t online,
+				ofono_modem_online_cb_t cb, void *data)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	struct isi_cb_data *cbd = isi_cb_data_new(modem, cb, data);
+	const uint8_t req[] = {
+		MCE_RF_STATE_REQ,
+		online ? MCE_RF_ON : MCE_RF_OFF,
+		0x00
+	};
+
+	DBG("(%p) with %s", modem, isi->ifname);
+
+	if (cbd == NULL || isi == NULL)
+		goto error;
+
+	if (g_isi_client_send_with_timeout(isi->client, req, sizeof(req),
+				MTC_STATE_REQ_TIMEOUT,
+				mce_state_cb, cbd, NULL)) {
+		isi->online = online;
+		return;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static void u8500_pre_sim(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+
+	DBG("(%p) with %s", modem, isi->ifname);
+
+	ofono_sim_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_devinfo_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_voicecall_create(modem, ISI_25, "isimodem", isi->modem);
+}
+
+static void u8500_post_sim(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+
+	DBG("(%p) with %s", modem, isi->ifname);
+
+	ofono_phonebook_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_call_forwarding_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_radio_settings_create(modem, ISI_25, "isimodem", isi->modem);
+}
+
+static void u8500_post_online(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+
+	DBG("(%p) with %s", modem, isi->ifname);
+
+	ofono_netreg_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_sms_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_cbs_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_ssn_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_ussd_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_call_settings_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_call_barring_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_call_meter_create(modem, ISI_25, "isimodem", isi->modem);
+	ofono_gprs_create(modem, ISI_25, "isimodem", isi->modem);
+}
+
+static int u8500_enable(struct ofono_modem *modem)
+{
+	return 0;
+}
+
+static int u8500_disable(struct ofono_modem *modem)
+{
+	return 0;
+}
+
+static struct ofono_modem_driver driver = {
+	.name = "u8500",
+	.probe = u8500_probe,
+	.remove = u8500_remove,
+	.set_online = u8500_online,
+	.pre_sim = u8500_pre_sim,
+	.post_sim = u8500_post_sim,
+	.post_online = u8500_post_online,
+	.enable = u8500_enable,
+	.disable = u8500_disable,
+};
+
+static int u8500_init(void)
+{
+	return ofono_modem_driver_register(&driver);
+}
+
+static void u8500_exit(void)
+{
+	ofono_modem_driver_unregister(&driver);
+}
+
+OFONO_PLUGIN_DEFINE(u8500, "Generic modem driver for isi",
+			VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT,
+			u8500_init, u8500_exit)
-- 
1.7.3.5


  reply	other threads:[~2011-02-01 14:13 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-02-01 14:13 [PATCH v2 0/3] ISI modem version detection with plugin Jessica Nilsson
2011-02-01 14:13 ` Jessica Nilsson [this message]
2011-02-01 15:41   ` [PATCH v2 1/3] u8500: add plugin for u8500 Marcel Holtmann
2011-02-01 14:13 ` [PATCH v2 2/3] udev: u8500 support and style fix Jessica Nilsson
2011-02-01 15:39   ` Marcel Holtmann
2011-02-01 15:55     ` Andreas WESTIN
2011-02-01 16:12       ` Marcel Holtmann
2011-02-01 14:13 ` [PATCH v2 3/3] isimodem: header updates for ISI2.5 Jessica Nilsson
2011-02-01 15:43   ` Marcel Holtmann
2011-02-01 16:29     ` Andreas WESTIN
2011-02-01 19:32     ` Aki Niemi
2011-02-02  9:03       ` Andreas WESTIN
2011-02-02 13:03         ` Aki Niemi
2011-02-03  9:32           ` Andreas WESTIN
2011-02-04  9:05             ` Aki Niemi
2011-02-02 10:47       ` Marcel Holtmann
2011-02-08 15:16       ` Aki Niemi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fabc1533cadfaf5d418d3d27833e7fe8d05a8739.1296569048.git.jessica.j.nilsson@stericsson.com \
    --to=jessica.j.nilsson@stericsson.com \
    --cc=ofono@ofono.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.