All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] Samsung IPC modem support
@ 2012-09-18 18:18 Simon Busch
  2012-09-18 18:18 ` [PATCH 01/11] build: Add skeleton for Samsung IPC modem driver Simon Busch
                   ` (11 more replies)
  0 siblings, 12 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

Heyho,

the following patch series adds support for the Samsung IPC protocol which is implemented
in an external library called libsamsung-ipc (see [0]). The library contains the
implementation of the protocol used in most Samsung mobile handsets. As of right now the
implementation contains drivers for the devinfo, sim, voicecall, gprs and gprs-context
subsystems. Implementation for other subsystems like sms will follow.

I submit the patches here for a first review to make sure things I did are right and are
fine for inclusion in ofono. Anyway the code is not ready yet and needs more tweaking and
testing but I think it's time for a first look.

One thing about libsamsung-ipc: The library itself needs some rework and fine tuning and
is not ready for a release yet so this is a hard dependency for the inclusion in ofono.

regards,
Simon

[0]: https://github.com/morphis/libsamsung-ipc

Simon Busch (11):
  build: Add skeleton for Samsung IPC modem driver
  build: add dependency for samsung-ipc library
  samsungmgr: plugin for powering up samsung related modems via an
    additional daemon
  samsungipcmodem: implement the transport layer for the IPC protocol
  samsungipcmodem: add devinfo driver implementation
  samsungipcmodem: add sim driver implementation
  samsungipcmodem: add network registration driver implementation
  samsungipcmodem: add voicecall driver implementation
  samsungipcmodem: add gprs driver implementation
  samsungipcmodem: add gprs-context driver implementation
  samsungipc: Add initial implementation of the Samsung IPC modem
    plugin

 Makefile.am                                    |   25 +
 configure.ac                                   |   11 +
 drivers/samsungipcmodem/devinfo.c              |  214 ++++++++
 drivers/samsungipcmodem/gprs-context.c         |  311 +++++++++++
 drivers/samsungipcmodem/gprs.c                 |  215 ++++++++
 drivers/samsungipcmodem/ipc.c                  |  443 ++++++++++++++++
 drivers/samsungipcmodem/ipc.h                  |   58 ++
 drivers/samsungipcmodem/network-registration.c |  398 ++++++++++++++
 drivers/samsungipcmodem/samsungipcmodem.c      |   53 ++
 drivers/samsungipcmodem/samsungipcmodem.h      |   33 ++
 drivers/samsungipcmodem/sim.c                  |  674 ++++++++++++++++++++++++
 drivers/samsungipcmodem/util.h                 |   57 ++
 drivers/samsungipcmodem/voicecall.c            |  358 +++++++++++++
 plugins/samsungipc.c                           |  414 +++++++++++++++
 plugins/samsungmgr.c                           |  199 +++++++
 15 files changed, 3463 insertions(+)
 create mode 100644 drivers/samsungipcmodem/devinfo.c
 create mode 100644 drivers/samsungipcmodem/gprs-context.c
 create mode 100644 drivers/samsungipcmodem/gprs.c
 create mode 100644 drivers/samsungipcmodem/ipc.c
 create mode 100644 drivers/samsungipcmodem/ipc.h
 create mode 100644 drivers/samsungipcmodem/network-registration.c
 create mode 100644 drivers/samsungipcmodem/samsungipcmodem.c
 create mode 100644 drivers/samsungipcmodem/samsungipcmodem.h
 create mode 100644 drivers/samsungipcmodem/sim.c
 create mode 100644 drivers/samsungipcmodem/util.h
 create mode 100644 drivers/samsungipcmodem/voicecall.c
 create mode 100644 plugins/samsungipc.c
 create mode 100644 plugins/samsungmgr.c

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 01/11] build: Add skeleton for Samsung IPC modem driver
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 02/11] build: add dependency for samsung-ipc library Simon Busch
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am                               |    7 +++++
 configure.ac                              |    5 ++++
 drivers/samsungipcmodem/samsungipcmodem.c |   41 +++++++++++++++++++++++++++++
 drivers/samsungipcmodem/samsungipcmodem.h |   20 ++++++++++++++
 4 files changed, 73 insertions(+)
 create mode 100644 drivers/samsungipcmodem/samsungipcmodem.c
 create mode 100644 drivers/samsungipcmodem/samsungipcmodem.h

diff --git a/Makefile.am b/Makefile.am
index 40a83dc..4cfec6b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -181,6 +181,13 @@ builtin_modules += gobi
 builtin_sources += plugins/gobi.c
 endif
 
+if SAMSUNGIPCMODEM
+builtin_modules += samsungipcmodem
+builtin_sources += \
+	drivers/samsungipcmodem/samsungipcmodem.c \
+	drivers/samsungipcmodem/samsungipcmodem.h
+endif
+
 if ATMODEM
 builtin_modules += atmodem
 builtin_sources += $(gatchat_sources) \
diff --git a/configure.ac b/configure.ac
index 2d6247d..3835d35 100644
--- a/configure.ac
+++ b/configure.ac
@@ -172,6 +172,11 @@ AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
 					[enable_qmimodem=${enableval}])
 AM_CONDITIONAL(QMIMODEM, test "${enable_qmimodem}" != "no")
 
+AC_ARG_ENABLE(samsungipc, AC_HELP_STRING([--disable-samsungipcmodem],
+				[disable Samsung IPC modem support]),
+					[enable_samsungipc=${enableval}])
+AM_CONDITIONAL(SAMSUNGIPCMODEM, test "${enable_samsungipc}" != "no")
+
 AC_ARG_ENABLE(bluetooth, AC_HELP_STRING([--disable-bluetooth],
 				[disable Bluetooth modem support]),
 					[enable_bluetooth=${enableval}])
diff --git a/drivers/samsungipcmodem/samsungipcmodem.c b/drivers/samsungipcmodem/samsungipcmodem.c
new file mode 100644
index 0000000..c302dfd
--- /dev/null
+++ b/drivers/samsungipcmodem/samsungipcmodem.c
@@ -0,0 +1,41 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  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
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+
+#include "samsungipcmodem.h"
+
+static int samsungipcmodem_init(void)
+{
+	return 0;
+}
+
+static void samsungipcmodem_exit(void)
+{
+}
+
+OFONO_PLUGIN_DEFINE(samsungipcmodem, "Samsung IPC modem driver", VERSION,
+		OFONO_PLUGIN_PRIORITY_DEFAULT, samsungipcmodem_init, samsungipcmodem_exit)
diff --git a/drivers/samsungipcmodem/samsungipcmodem.h b/drivers/samsungipcmodem/samsungipcmodem.h
new file mode 100644
index 0000000..3f9b386
--- /dev/null
+++ b/drivers/samsungipcmodem/samsungipcmodem.h
@@ -0,0 +1,20 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  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
+ *
+ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 02/11] build: add dependency for samsung-ipc library
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
  2012-09-18 18:18 ` [PATCH 01/11] build: Add skeleton for Samsung IPC modem driver Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 03/11] samsungmgr: plugin for powering up samsung related modems via an additional daemon Simon Busch
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am  |    2 ++
 configure.ac |    6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 4cfec6b..a7d2d6e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -186,6 +186,8 @@ builtin_modules += samsungipcmodem
 builtin_sources += \
 	drivers/samsungipcmodem/samsungipcmodem.c \
 	drivers/samsungipcmodem/samsungipcmodem.h
+builtin_cflags += @SAMSUNGIPC_CFLAGS@
+builtin_libadd += @SAMSUNGIPC_LIBS@
 endif
 
 if ATMODEM
diff --git a/configure.ac b/configure.ac
index 3835d35..87850b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -175,6 +175,12 @@ AM_CONDITIONAL(QMIMODEM, test "${enable_qmimodem}" != "no")
 AC_ARG_ENABLE(samsungipc, AC_HELP_STRING([--disable-samsungipcmodem],
 				[disable Samsung IPC modem support]),
 					[enable_samsungipc=${enableval}])
+if (test "${enable_samsungipc}" != "no"); then
+	PKG_CHECK_MODULES(SAMSUNGIPC, samsung-ipc-1.0 >= 0.2, dummy=yes,
+			AC_MSG_ERROR(Samsung IPC library >= 0.2 is required))
+fi
+AC_SUBST(SAMSUNGIPC_CFLAGS)
+AC_SUBST(SAMSUNGIPC_LIBS)
 AM_CONDITIONAL(SAMSUNGIPCMODEM, test "${enable_samsungipc}" != "no")
 
 AC_ARG_ENABLE(bluetooth, AC_HELP_STRING([--disable-bluetooth],
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 03/11] samsungmgr: plugin for powering up samsung related modems via an additional daemon
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
  2012-09-18 18:18 ` [PATCH 01/11] build: Add skeleton for Samsung IPC modem driver Simon Busch
  2012-09-18 18:18 ` [PATCH 02/11] build: add dependency for samsung-ipc library Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 04/11] samsungipcmodem: implement the transport layer for the IPC protocol Simon Busch
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am          |    5 ++
 plugins/samsungmgr.c |  199 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 204 insertions(+)
 create mode 100644 plugins/samsungmgr.c

diff --git a/Makefile.am b/Makefile.am
index a7d2d6e..f4e9b8f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -381,6 +381,11 @@ builtin_sources += plugins/ste.c
 builtin_modules += stemgr
 builtin_sources += plugins/stemgr.c
 
+if SAMSUNGIPCMODEM
+builtin_modules += samsungmgr
+builtin_sources += plugins/samsungmgr.c
+endif
+
 builtin_modules += caif
 builtin_sources += plugins/caif.c
 
diff --git a/plugins/samsungmgr.c b/plugins/samsungmgr.c
new file mode 100644
index 0000000..fd0f364
--- /dev/null
+++ b/plugins/samsungmgr.c
@@ -0,0 +1,199 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>
+ *
+ *  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 <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>
+
+#define MGR_SERVICE		"org.samsung.modem"
+#define MGR_INTERFACE		MGR_SERVICE ".Manager"
+
+enum modem_status {
+	OFFLINE,
+	INITIALIZING,
+	ONLINE
+};
+
+static guint modem_daemon_watch;
+static guint property_changed_watch;
+static DBusConnection *connection;
+static enum modem_status modem_status = OFFLINE;
+struct ofono_modem *modem;
+
+static void set_modem_power_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError err;
+
+	dbus_error_init(&err);
+
+	if (dbus_set_error_from_message(&err, reply) == TRUE) {
+		g_printerr("%s: %s\n", err.name, err.message);
+		dbus_error_free(&err);
+	}
+
+	dbus_message_unref(reply);
+}
+
+static int set_modem_power(ofono_bool_t power)
+{
+	DBusMessage *msg;
+	DBusMessageIter iter, value;
+	DBusPendingCall *call;
+	const char *key = "Powered";
+
+	msg = dbus_message_new_method_call(MGR_SERVICE, "/",
+					MGR_INTERFACE, "SetProperty");
+	if (msg == NULL)
+		return -ENOMEM;
+
+	dbus_message_set_auto_start(msg, FALSE);
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+							DBUS_TYPE_BOOLEAN_AS_STRING, &value);
+	dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &power);
+	dbus_message_iter_close_container(&iter, &value);
+
+	if (dbus_connection_send_with_reply(connection, msg, &call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		return -EIO;
+	}
+
+	dbus_message_unref(msg);
+
+	if (call == NULL)
+		return -EINVAL;
+
+	dbus_pending_call_set_notify(call, set_modem_power_reply, NULL, NULL);
+
+	dbus_pending_call_unref(call);
+
+	return 0;
+}
+
+static void modem_status_changed(const char *status)
+{
+	switch (modem_status) {
+		case OFFLINE:
+			if(g_str_equal(status, "online") == TRUE) {
+				modem = ofono_modem_create(NULL, "samsungipc");
+				if (modem == NULL) {
+					ofono_error("Could not create modem");
+					return;
+				}
+				DBG("registering samsung ipc modem ...");
+				ofono_modem_register(modem);
+				modem_status = ONLINE;
+			}
+			break;
+		case ONLINE:
+			if (g_str_equal(status, "offline") == TRUE) {
+				DBG("Samsung modem unregistering");
+				ofono_modem_remove(modem);
+				modem = NULL;
+				modem_status = OFFLINE;
+			}
+			break;
+		default:
+			break;
+	}
+}
+
+static gboolean property_changed(DBusConnection *conn,
+					DBusMessage *message, void *user_data)
+{
+	DBusMessageIter iter, value;
+	const char *key, *status;
+
+	if (dbus_message_iter_init(message, &iter) == FALSE)
+		return TRUE;
+
+	dbus_message_iter_get_basic(&iter, &key);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_recurse(&iter, &value);
+
+	if (g_str_equal(key, "Status") == TRUE) {
+		dbus_message_iter_get_basic(&value, &status);
+		modem_status_changed(status);
+	}
+
+	return TRUE;
+}
+
+static void mgr_connect(DBusConnection *conn, void *user_data)
+{
+	property_changed_watch = g_dbus_add_signal_watch(conn,
+						MGR_SERVICE, NULL,
+						MGR_INTERFACE,
+						"PropertyChanged",
+						property_changed,
+						NULL, NULL);
+
+	// FIXME check wether modem is already powered up
+
+	set_modem_power(TRUE);
+}
+
+static void mgr_disconnect(DBusConnection *conn, void *user_data)
+{
+	g_dbus_remove_watch(conn, property_changed_watch);
+	property_changed_watch = 0;
+}
+
+static int samsungmgr_init(void)
+{
+	connection = ofono_dbus_get_connection();
+
+	modem_daemon_watch = g_dbus_add_service_watch(connection, MGR_SERVICE,
+				mgr_connect, mgr_disconnect, NULL, NULL);
+
+	return 0;
+}
+
+static void samsungmgr_exit(void)
+{
+	set_modem_power(FALSE);
+
+	g_dbus_remove_watch(connection, modem_daemon_watch);
+
+	if (property_changed_watch > 0)
+		g_dbus_remove_watch(connection, property_changed_watch);
+}
+
+OFONO_PLUGIN_DEFINE(samsungmgr, "Samsung Modem Init Daemon detection", VERSION,
+			OFONO_PLUGIN_PRIORITY_DEFAULT, samsungmgr_init, samsungmgr_exit)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 04/11] samsungipcmodem: implement the transport layer for the IPC protocol
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (2 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 03/11] samsungmgr: plugin for powering up samsung related modems via an additional daemon Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 05/11] samsungipcmodem: add devinfo driver implementation Simon Busch
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am                    |    4 +-
 drivers/samsungipcmodem/ipc.c  |  443 ++++++++++++++++++++++++++++++++++++++++
 drivers/samsungipcmodem/ipc.h  |   58 ++++++
 drivers/samsungipcmodem/util.h |   57 ++++++
 4 files changed, 561 insertions(+), 1 deletion(-)
 create mode 100644 drivers/samsungipcmodem/ipc.c
 create mode 100644 drivers/samsungipcmodem/ipc.h
 create mode 100644 drivers/samsungipcmodem/util.h

diff --git a/Makefile.am b/Makefile.am
index f4e9b8f..4c13ec0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -185,7 +185,9 @@ if SAMSUNGIPCMODEM
 builtin_modules += samsungipcmodem
 builtin_sources += \
 	drivers/samsungipcmodem/samsungipcmodem.c \
-	drivers/samsungipcmodem/samsungipcmodem.h
+	drivers/samsungipcmodem/samsungipcmodem.h \
+	drivers/samsungipcmodem/ipc.c \
+	drivers/samsungipcmodem/ipc.h
 builtin_cflags += @SAMSUNGIPC_CFLAGS@
 builtin_libadd += @SAMSUNGIPC_LIBS@
 endif
diff --git a/drivers/samsungipcmodem/ipc.c b/drivers/samsungipcmodem/ipc.c
new file mode 100644
index 0000000..d742acc
--- /dev/null
+++ b/drivers/samsungipcmodem/ipc.c
@@ -0,0 +1,443 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  Some parts of the code below are copied from drivers/qmimodem/qmi.c and are
+ *  Copyright (C) 2011-2012  Intel Corporation. All rights reserved.
+ *
+ *  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
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+
+#include "ipc.h"
+
+struct ipc_request {
+	uint16_t command;
+	uint8_t type;
+	uint8_t id;
+	void *data;
+	uint16_t length;
+	ipc_response_func_t cb;
+	void *cb_data;
+};
+
+struct ipc_device {
+	int ref_count;
+	int fd;
+	GIOChannel *io;
+	bool close_on_unref;
+	guint read_watch;
+	guint write_watch;
+	ipc_debug_func_t debug_func;
+	void *debug_data;
+	struct ipc_client *client;
+	uint8_t next_id;
+	GQueue *req_queue;
+	GQueue *wait_queue;
+	GList *notification_watches;
+	guint next_watch_id;
+};
+
+struct notication_watch {
+	guint id;
+	uint8_t type;
+	uint16_t cmd;
+	ipc_notify_func_t notify_cb;
+	void *notify_data;
+};
+
+static void __debug_device(struct ipc_device *device,
+						const char *format, ...)
+{
+	char strbuf[72 + 16];
+	va_list ap;
+
+	if (!device->debug_func)
+		return;
+
+	va_start(ap, format);
+	vsnprintf(strbuf, sizeof(strbuf), format, ap);
+	va_end(ap);
+
+	device->debug_func(strbuf, device->debug_data);
+}
+
+static guint next_message_id(struct ipc_device *device)
+{
+	if (device->next_id == 255)
+		device->next_id = 1;
+
+	return device->next_id++;
+}
+
+static guint next_watch_id(struct ipc_device *device)
+{
+	if (device->next_watch_id == G_MAXUINT)
+		device->next_watch_id = 1;
+
+	return device->next_watch_id++;
+}
+
+static gint __request_compare(gconstpointer a, gconstpointer b)
+{
+	const struct ipc_request *req = a;
+	uint16_t id = GPOINTER_TO_UINT(b);
+
+	return req->id - id;
+}
+
+static void handle_response(struct ipc_device *device, struct ipc_message_info *resp)
+{
+	GList *list;
+	struct ipc_request *req;
+
+	list = g_queue_find_custom(device->wait_queue,
+			GUINT_TO_POINTER(resp->aseq), __request_compare);
+	if (!list) {
+		__debug_device(device, "Did not found corresponding request for received response message");
+		return;
+	}
+
+	req = list->data;
+	if (req->cb)
+		req->cb(resp->cmd, resp->data, resp->length, 0, req->cb_data);
+}
+
+static void handle_notification(struct ipc_device *device, struct ipc_message_info *resp)
+{
+	GList *list;
+
+	for (list = g_list_first(device->notification_watches); list;
+						list = g_list_next(list)) {
+		struct notication_watch *watch = list->data;
+
+		if (!watch)
+			continue;
+
+		if (watch->type == resp->type && watch->cmd == resp->cmd)
+			watch->notify_cb(resp->cmd, resp->data, resp->length, watch->notify_data);
+	}
+}
+
+static gboolean received_data(GIOChannel *channel, GIOCondition cond,
+							  gpointer user_data)
+{
+	struct ipc_device *device = user_data;
+	struct ipc_message_info resp;
+	int ret;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	ret = ipc_client_recv(device->client, &resp);
+	if (ret < 0) {
+		ofono_error("Could not receive IPC message from modem");
+		return FALSE;
+	}
+
+	switch (resp.type) {
+	case IPC_TYPE_RESP:
+		ofono_debug("Received IPC response message [id=%i, type=%s cmd=%s]",
+				resp.aseq, ipc_response_type_to_str(resp.type),
+				ipc_command_to_str(resp.cmd));
+		handle_response(device, &resp);
+		break;
+	case IPC_TYPE_NOTI:
+	case IPC_TYPE_INDI:
+		ofono_debug("Received IPC %s message [id=%i, type=%s, cmd=%s]",
+				resp.type == IPC_TYPE_NOTI ? "notification" : "indication",
+				resp.aseq, ipc_response_type_to_str(resp.type),
+				ipc_command_to_str(resp.cmd));
+		handle_notification(device, &resp);
+		break;
+		break;
+	default:
+		ofono_error("Received unhandled IPC message type [id=%i, type=%s, cmd=%s]",
+				resp.aseq, ipc_response_type_to_str(resp.type),
+				ipc_command_to_str(resp.cmd));
+		break;
+	}
+
+	// FIXME this leads to a SEGV somehow:
+	// g_source_callback_ref (cb_data=0x0)@/build/buildd/glib2.0-2.32.3/./glib/gmain.c:1275
+	// 1275/build/buildd/glib2.0-2.32.3/.32/glib/gmain.c: Datei oder Verzeichnis nicht gefunden.
+	// ipc_client_response_free(device->client, &resp);
+
+	return TRUE;
+}
+
+static void read_watch_destroy(gpointer user_data)
+{
+	struct ipc_device *device = user_data;
+
+	device->read_watch = 0;
+}
+
+static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
+							gpointer user_data)
+{
+	struct ipc_device *device = user_data;
+	struct ipc_request *req;
+
+	req = g_queue_pop_head(device->req_queue);
+	if (!req)
+		return FALSE;
+
+	ofono_debug("Sending IPC request message [id=%i, cmd=%s, type=%s]",
+			req->id, ipc_command_to_str(req->command),
+			ipc_request_type_to_str(req->type));
+
+	ipc_client_send(device->client, req->command, req->type,
+				req->data, req->length, req->id);
+
+	// FIXME start timeout for message
+
+	g_free(req->data);
+	req->data = NULL;
+
+	if (req->cb != NULL)
+		g_queue_push_tail(device->wait_queue, req);
+
+	if (g_queue_get_length(device->req_queue) > 0)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void write_watch_destroy(gpointer user_data)
+{
+	struct ipc_device *device = user_data;
+
+	device->write_watch = 0;
+}
+
+static void wakeup_writer(struct ipc_device *device)
+{
+	if (device->write_watch > 0)
+		return;
+
+	device->write_watch = g_io_add_watch_full(device->io, G_PRIORITY_HIGH,
+				G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				can_write_data, device, write_watch_destroy);
+}
+
+struct ipc_device *ipc_device_new(int fd, struct ipc_client *client)
+{
+	struct ipc_device *device;
+
+	device = g_try_new0(struct ipc_device, 1);
+	if (!device)
+		return NULL;
+
+	device->ref_count = 1;
+	device->fd = fd;
+	device->next_id = 1;
+	device->next_watch_id = 1;
+	device->client = client;
+	device->close_on_unref = false;
+	device->req_queue = g_queue_new();
+	device->wait_queue = g_queue_new();
+	device->notification_watches = g_list_alloc();
+
+	device->io = g_io_channel_unix_new(device->fd);
+
+	g_io_channel_set_encoding(device->io, NULL, NULL);
+	g_io_channel_set_buffered(device->io, FALSE);
+
+	device->read_watch = g_io_add_watch_full(device->io, G_PRIORITY_DEFAULT,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				received_data, device, read_watch_destroy);
+
+	g_io_channel_unref(device->io);
+
+	return device;
+}
+
+struct ipc_device *ipc_device_ref(struct ipc_device *device)
+{
+	if (!device)
+		return NULL;
+
+	__sync_fetch_and_add(&device->ref_count, 1);
+
+	return device;
+}
+
+static void free_notification_watch(gpointer data)
+{
+	struct notication_watch *watch = data;
+	free(watch);
+}
+
+void ipc_device_unref(struct ipc_device *device)
+{
+	if (!device)
+		return;
+
+	if (__sync_sub_and_fetch(&device->ref_count, 1))
+		return;
+
+	__debug_device(device, "device %p free", device);
+
+	if (device->write_watch > 0)
+		g_source_remove(device->write_watch);
+
+	if (device->read_watch > 0)
+		g_source_remove(device->read_watch);
+
+	if (device->close_on_unref)
+		close(device->fd);
+
+	g_list_free_full(device->notification_watches, free_notification_watch);
+
+	g_free(device);
+}
+
+static guint add_response_watch(struct ipc_device *device, uint8_t type, uint16_t cmd,
+							ipc_notify_func_t notify_cb, void *user_data)
+{
+	struct notication_watch *watch;
+
+	watch = g_try_new0(struct notication_watch, 1);
+	if (!watch)
+		return -1;
+
+	watch->id = next_watch_id(device);
+	watch->type = type;
+	watch->cmd = cmd;
+	watch->notify_cb = notify_cb;
+	watch->notify_data = user_data;
+
+	device->notification_watches = g_list_append(device->notification_watches, watch);
+
+	return watch->id;
+}
+
+guint ipc_device_add_notifcation_watch(struct ipc_device *device, uint16_t cmd,
+							ipc_notify_func_t notify_cb, void *user_data)
+{
+	return add_response_watch(device, IPC_TYPE_NOTI, cmd, notify_cb, user_data);
+}
+
+guint ipc_device_add_indication_watch(struct ipc_device *device, uint16_t cmd,
+							ipc_notify_func_t notify_cb, void *user_data)
+{
+	return add_response_watch(device, IPC_TYPE_INDI, cmd, notify_cb, user_data);
+}
+
+static gint __notification_watch_id_compare(gconstpointer a, gconstpointer b)
+{
+	const struct notication_watch *watch = a;
+	const guint id = GPOINTER_TO_UINT(b);
+
+	if (a == NULL || b == NULL)
+		return -1;
+
+	return watch->id - id;
+}
+
+static void remove_response_watch(struct ipc_device *device, guint id)
+{
+	GList *watches;
+
+	watches = g_list_find_custom(device->notification_watches,
+						GUINT_TO_POINTER(id), __notification_watch_id_compare);
+
+	if (watches == NULL)
+		return;
+
+	device->notification_watches = g_list_delete_link(device->notification_watches, watches);
+}
+
+void ipc_device_remove_watch(struct ipc_device *device, guint id)
+{
+	remove_response_watch(device, id);
+}
+
+int ipc_device_get_fd(struct ipc_device *device)
+{
+	if (!device)
+		return -1;
+
+	return device->fd;
+}
+
+struct ipc_client *ipc_device_get_client(struct ipc_device *device)
+{
+	if (!device)
+		return NULL;
+
+	return device->client;
+}
+
+int ipc_device_enqueue_message(struct ipc_device *device,
+			uint16_t command, uint8_t type, void *data, uint16_t length,
+			ipc_response_func_t cb, void *user_data)
+{
+	struct ipc_request *req;
+
+	req = g_try_new0(struct ipc_request, 1);
+	if (!req)
+		return -1;
+
+	req->command = command;
+	req->type = type;
+	req->cb = cb;
+	req->cb_data = user_data;
+	req->id = next_message_id(device);
+	req->data = data;
+	req->length = length;
+
+	g_queue_push_tail(device->req_queue, req);
+
+	wakeup_writer(device);
+
+	return req->id;
+}
+
+void ipc_device_set_debug(struct ipc_device *device,
+				ipc_debug_func_t func, void *user_data)
+{
+	if (device == NULL)
+		return;
+
+	device->debug_func = func;
+	device->debug_data = user_data;
+}
+
+void ipc_device_set_close_on_unref(struct ipc_device *device, bool do_close)
+{
+	if (!device)
+		return;
+
+	device->close_on_unref = do_close;
+}
diff --git a/drivers/samsungipcmodem/ipc.h b/drivers/samsungipcmodem/ipc.h
new file mode 100644
index 0000000..16dd8e4
--- /dev/null
+++ b/drivers/samsungipcmodem/ipc.h
@@ -0,0 +1,58 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  Some parts of the code below are copied from drivers/qmimodem/qmi.c and are
+ *  Copyright (C) 2011-2012  Intel Corporation. All rights reserved.
+ *
+ *  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
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <samsung-ipc.h>
+
+typedef void (*ipc_debug_func_t)(const char *str, void *user_data);
+typedef void (*ipc_response_func_t)(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data);
+typedef void (*ipc_notify_func_t)(uint16_t cmd, void *data, uint16_t length, void *user_data);
+
+struct ipc_device;
+
+struct ipc_device *ipc_device_new(int fd, struct ipc_client *client);
+struct ipc_device *ipc_device_ref(struct ipc_device *device);
+void ipc_device_unref(struct ipc_device *device);
+
+guint ipc_device_add_notifcation_watch(struct ipc_device *device, uint16_t cmd,
+							ipc_notify_func_t notify_cb, void *user_data);
+guint ipc_device_add_indication_watch(struct ipc_device *device, uint16_t cmd,
+							ipc_notify_func_t notify_cb, void *user_data);
+
+void ipc_device_remove_watch(struct ipc_device *device, guint id);
+
+int ipc_device_get_fd(struct ipc_device *device);
+
+struct ipc_client *ipc_device_get_client(struct ipc_device *device);
+
+int ipc_device_enqueue_message(struct ipc_device *device,
+			uint16_t command, uint8_t type, void *data, uint16_t length,
+			ipc_response_func_t cb, void *user_data);
+
+void ipc_device_set_debug(struct ipc_device *device,
+				ipc_debug_func_t func, void *user_data);
+
+void ipc_device_set_close_on_unref(struct ipc_device *device, bool do_close);
diff --git a/drivers/samsungipcmodem/util.h b/drivers/samsungipcmodem/util.h
new file mode 100644
index 0000000..cf053f0
--- /dev/null
+++ b/drivers/samsungipcmodem/util.h
@@ -0,0 +1,57 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation. All rights reserved.
+ *
+ *  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
+ *
+ */
+
+#include <glib.h>
+
+struct cb_data {
+	void *cb;
+	void *data;
+	void *user;
+};
+
+static inline struct cb_data *cb_data_new(void *cb, void *data)
+{
+	struct cb_data *ret;
+
+	ret = g_new0(struct cb_data, 1);
+	ret->cb = cb;
+	ret->data = data;
+	ret->user = NULL;
+
+	return ret;
+}
+
+#define CALLBACK_WITH_FAILURE(cb, args...)		\
+	do {						\
+		struct ofono_error cb_e;		\
+		cb_e.type = OFONO_ERROR_TYPE_FAILURE;	\
+		cb_e.error = 0;				\
+							\
+		cb(&cb_e, ##args);			\
+	} while (0)					\
+
+#define CALLBACK_WITH_SUCCESS(f, args...)		\
+	do {						\
+		struct ofono_error e;			\
+		e.type = OFONO_ERROR_TYPE_NO_ERROR;	\
+		e.error = 0;				\
+		f(&e, ##args);				\
+	} while (0)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 05/11] samsungipcmodem: add devinfo driver implementation
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (3 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 04/11] samsungipcmodem: implement the transport layer for the IPC protocol Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 06/11] samsungipcmodem: add sim " Simon Busch
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am                               |    3 +-
 drivers/samsungipcmodem/devinfo.c         |  214 +++++++++++++++++++++++++++++
 drivers/samsungipcmodem/samsungipcmodem.c |    2 +
 drivers/samsungipcmodem/samsungipcmodem.h |    3 +
 4 files changed, 221 insertions(+), 1 deletion(-)
 create mode 100644 drivers/samsungipcmodem/devinfo.c

diff --git a/Makefile.am b/Makefile.am
index 4c13ec0..a6f8ce5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -187,7 +187,8 @@ builtin_sources += \
 	drivers/samsungipcmodem/samsungipcmodem.c \
 	drivers/samsungipcmodem/samsungipcmodem.h \
 	drivers/samsungipcmodem/ipc.c \
-	drivers/samsungipcmodem/ipc.h
+	drivers/samsungipcmodem/ipc.h \
+	drivers/samsungipcmodem/devinfo.c
 builtin_cflags += @SAMSUNGIPC_CFLAGS@
 builtin_libadd += @SAMSUNGIPC_LIBS@
 endif
diff --git a/drivers/samsungipcmodem/devinfo.c b/drivers/samsungipcmodem/devinfo.c
new file mode 100644
index 0000000..4db3e83
--- /dev/null
+++ b/drivers/samsungipcmodem/devinfo.c
@@ -0,0 +1,214 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  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 <string.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+
+#include <glib.h>
+
+#include "samsungipcmodem.h"
+#include "ipc.h"
+#include "util.h"
+
+struct devinfo_data {
+	struct ipc_device *device;
+};
+
+static void samsungipc_query_manufacturer(struct ofono_devinfo *devinfo,
+				ofono_devinfo_query_cb_t cb, void *user_data)
+{
+	struct cb_data *cbd = cb_data_new(cb, user_data);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+
+	g_free(cbd);
+}
+
+static void samsungipc_query_model(struct ofono_devinfo *devinfo,
+				ofono_devinfo_query_cb_t cb, void *user_data)
+{
+	struct cb_data *cbd = cb_data_new(cb, user_data);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+
+	g_free(cbd);
+}
+
+static void misc_me_version_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_devinfo_query_cb_t cb = cbd->cb;
+	struct ipc_misc_me_version *version = data;
+	char *str;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+		return;
+	}
+
+	str = g_try_new0(char, 32);
+	if (!str) {
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+		return;
+	}
+
+	strncpy(str, version->sw_version, 32);
+	str[32] = '\0';
+
+	CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
+}
+
+static void samsungipc_query_revision(struct ofono_devinfo *devinfo,
+				ofono_devinfo_query_cb_t cb, void *user_data)
+{
+	struct devinfo_data *data = ofono_devinfo_get_data(devinfo);
+	struct cb_data *cbd = cb_data_new(cb, user_data);
+	uint8_t *msg;
+
+	msg = g_try_new0(uint8_t, 1);
+	msg[0] = 0xff;
+
+	if(ipc_device_enqueue_message(data->device, IPC_MISC_ME_VERSION, IPC_TYPE_GET,
+						msg, 1, misc_me_version_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, data);
+}
+
+static void misc_me_sn_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_devinfo_query_cb_t cb = cbd->cb;
+	struct ipc_misc_me_sn *sn = data;
+	char *str;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+		return;
+	}
+
+	str = g_try_new0(char, sn->length);
+	if (!str) {
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+		return;
+	}
+
+	strncpy(str, sn->data, sn->length);
+	str[sn->length] = '\0';
+
+	CALLBACK_WITH_SUCCESS(cb, str, cbd->data);
+}
+
+static void samsungipc_query_serial(struct ofono_devinfo *devinfo,
+				ofono_devinfo_query_cb_t cb, void *user_data)
+{
+	struct devinfo_data *data = ofono_devinfo_get_data(devinfo);
+	struct cb_data *cbd = cb_data_new(cb, user_data);
+	uint8_t *msg;
+
+	msg = g_try_new0(uint8_t, 1);
+	msg[0] = IPC_MISC_ME_SN_SERIAL_NUM;
+
+	if (ipc_device_enqueue_message(data->device, IPC_MISC_ME_SN, IPC_TYPE_GET,
+						msg, 1, misc_me_sn_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, data);
+}
+
+static void reachable_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct ofono_devinfo *info = user_data;
+
+	if (error) {
+		ofono_devinfo_remove(info);
+		return;
+	}
+
+	ofono_devinfo_register(info);
+}
+
+static int samsungipc_devinfo_probe(struct ofono_devinfo *devinfo,
+				unsigned int vendor, void *user_data)
+{
+	struct devinfo_data *data;
+	struct ipc_device *device = user_data;
+	uint8_t *msg;
+
+	DBG("");
+
+	data = g_new0(struct devinfo_data, 1);
+
+	data->device = device;
+
+	ofono_devinfo_set_data(devinfo, data);
+
+	/* Just issue a IPC_MISC_ME_VERSION request here to check modem availability and
+	 * defer ofono_devinfo_register call */
+	msg = g_try_new0(uint8_t, 1);
+	msg[0] = 0xff;
+	ipc_device_enqueue_message(data->device, IPC_MISC_ME_VERSION, IPC_TYPE_GET,
+						msg, 1, reachable_cb, devinfo);
+
+	return 0;
+}
+
+static void samsungipc_devinfo_remove(struct ofono_devinfo *devinfo)
+{
+	struct devinfo_data *data = ofono_devinfo_get_data(devinfo);
+
+	DBG("");
+
+	ofono_devinfo_set_data(devinfo, NULL);
+
+	g_free(data);
+}
+
+static struct ofono_devinfo_driver driver = {
+	.name				= "samsungipcmodem",
+	.probe				= samsungipc_devinfo_probe,
+	.remove				= samsungipc_devinfo_remove,
+	.query_manufacturer	= samsungipc_query_manufacturer,
+	.query_model		= samsungipc_query_model,
+	.query_revision		= samsungipc_query_revision,
+	.query_serial		= samsungipc_query_serial,
+};
+
+void samsungipc_devinfo_init(void)
+{
+	ofono_devinfo_driver_register(&driver);
+}
+
+void samsungipc_devinfo_exit(void)
+{
+	ofono_devinfo_driver_unregister(&driver);
+}
diff --git a/drivers/samsungipcmodem/samsungipcmodem.c b/drivers/samsungipcmodem/samsungipcmodem.c
index c302dfd..32a00de 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.c
+++ b/drivers/samsungipcmodem/samsungipcmodem.c
@@ -30,11 +30,13 @@
 
 static int samsungipcmodem_init(void)
 {
+	samsungipc_devinfo_init();
 	return 0;
 }
 
 static void samsungipcmodem_exit(void)
 {
+	samsungipc_devinfo_exit();
 }
 
 OFONO_PLUGIN_DEFINE(samsungipcmodem, "Samsung IPC modem driver", VERSION,
diff --git a/drivers/samsungipcmodem/samsungipcmodem.h b/drivers/samsungipcmodem/samsungipcmodem.h
index 3f9b386..64fe7eb 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.h
+++ b/drivers/samsungipcmodem/samsungipcmodem.h
@@ -18,3 +18,6 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
+extern void samsungipc_devinfo_init(void);
+extern void samsungipc_devinfo_exit(void);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 06/11] samsungipcmodem: add sim driver implementation
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (4 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 05/11] samsungipcmodem: add devinfo driver implementation Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 07/11] samsungipcmodem: add network registration " Simon Busch
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am                               |    3 +-
 drivers/samsungipcmodem/samsungipcmodem.c |    2 +
 drivers/samsungipcmodem/samsungipcmodem.h |    2 +
 drivers/samsungipcmodem/sim.c             |  674 +++++++++++++++++++++++++++++
 4 files changed, 680 insertions(+), 1 deletion(-)
 create mode 100644 drivers/samsungipcmodem/sim.c

diff --git a/Makefile.am b/Makefile.am
index a6f8ce5..5553489 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -188,7 +188,8 @@ builtin_sources += \
 	drivers/samsungipcmodem/samsungipcmodem.h \
 	drivers/samsungipcmodem/ipc.c \
 	drivers/samsungipcmodem/ipc.h \
-	drivers/samsungipcmodem/devinfo.c
+	drivers/samsungipcmodem/devinfo.c \
+	drivers/samsungipcmodem/sim.c
 builtin_cflags += @SAMSUNGIPC_CFLAGS@
 builtin_libadd += @SAMSUNGIPC_LIBS@
 endif
diff --git a/drivers/samsungipcmodem/samsungipcmodem.c b/drivers/samsungipcmodem/samsungipcmodem.c
index 32a00de..78e698c 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.c
+++ b/drivers/samsungipcmodem/samsungipcmodem.c
@@ -31,11 +31,13 @@
 static int samsungipcmodem_init(void)
 {
 	samsungipc_devinfo_init();
+	samsungipc_sim_init();
 	return 0;
 }
 
 static void samsungipcmodem_exit(void)
 {
+	samsungipc_sim_exit();
 	samsungipc_devinfo_exit();
 }
 
diff --git a/drivers/samsungipcmodem/samsungipcmodem.h b/drivers/samsungipcmodem/samsungipcmodem.h
index 64fe7eb..c98d213 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.h
+++ b/drivers/samsungipcmodem/samsungipcmodem.h
@@ -21,3 +21,5 @@
 
 extern void samsungipc_devinfo_init(void);
 extern void samsungipc_devinfo_exit(void);
+extern void samsungipc_sim_init(void);
+extern void samsungipc_sim_exit(void);
diff --git a/drivers/samsungipcmodem/sim.c b/drivers/samsungipcmodem/sim.c
new file mode 100644
index 0000000..b0e7e2a
--- /dev/null
+++ b/drivers/samsungipcmodem/sim.c
@@ -0,0 +1,674 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  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
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/sim.h>
+
+#include <glib.h>
+
+#include "samsungipcmodem.h"
+#include "ipc.h"
+#include "util.h"
+#include "simutil.h"
+
+struct sim_data {
+	struct ipc_device *device;
+	guint sim_state_query;
+	int pin_attempts[OFONO_SIM_PASSWORD_INVALID];
+};
+
+#define EF_STATUS_INVALIDATED 0
+#define EF_STATUS_VALID 1
+
+#define SIM_MAX_IMSI_LENGTH	16
+
+static void pin_query_locked_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_locked_cb_t cb = cbd->cb;
+	struct ipc_sec_phone_lock_response *resp = data;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+		goto done;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, resp->status, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_pin_query_enabled(struct ofono_sim *sim,
+				enum ofono_sim_password_type passwd_type,
+				ofono_sim_locked_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd;
+	struct ipc_sec_phone_lock_get *req;
+
+	DBG("");
+
+	switch (passwd_type) {
+	case OFONO_SIM_PASSWORD_SIM_PIN:
+		break;
+	default:
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+		return;
+	}
+
+	req = g_try_new0(struct ipc_sec_phone_lock_get, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	if(ipc_device_enqueue_message(sd->device, IPC_SEC_PHONE_LOCK, IPC_TYPE_GET,
+						req, sizeof(struct ipc_sec_phone_lock_get),
+						pin_query_locked_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, -1, data);
+}
+
+static void change_passwd_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ipc_gen_phone_res *resp = data;
+
+	if (error || cmd != IPC_GEN_PHONE_RES ||
+		ipc_gen_phone_res_check(resp) < 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_change_passwd(struct ofono_sim *sim,
+				enum ofono_sim_password_type passwd_type,
+				const char *old_passwd, const char *new_passwd,
+				ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd;
+	struct ipc_sec_change_locking_pw_set *req;
+
+	DBG("");
+
+	switch (passwd_type) {
+	case OFONO_SIM_PASSWORD_SIM_PIN:
+		break;
+	default:
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	req = g_try_new0(struct ipc_sec_change_locking_pw_set, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	ipc_sec_change_locking_pw_set_setup(req, IPC_SEC_FACILITY_TYPE_SC,
+									(char*) old_passwd, (char*) new_passwd);
+
+	if(ipc_device_enqueue_message(sd->device, IPC_SEC_CHANGE_LOCKING_PW, IPC_TYPE_SET,
+						req, sizeof(struct ipc_sec_change_locking_pw_set),
+						change_passwd_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void pin_enable_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ipc_gen_phone_res *resp = data;
+
+	if (error || cmd != IPC_GEN_PHONE_RES ||
+		ipc_gen_phone_res_check(resp) < 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_pin_enable(struct ofono_sim *sim,
+				enum ofono_sim_password_type passwd_type,
+				int enable, const char *passwd,
+				ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd;
+	struct ipc_sec_phone_lock_set *req;
+	int pin_type;
+
+	switch (passwd_type) {
+	case OFONO_SIM_PASSWORD_SIM_PIN:
+		pin_type = IPC_SEC_PIN_TYPE_PIN1;
+		break;
+	case OFONO_SIM_PASSWORD_SIM_PIN2:
+		pin_type = IPC_SEC_PIN_TYPE_PIN2;
+		break;
+	default:
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	req = g_try_new0(struct ipc_sec_phone_lock_set, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	ipc_sec_phone_lock_set_setup(req, pin_type, enable, (char*) passwd);
+
+	if(ipc_device_enqueue_message(sd->device, IPC_SEC_PHONE_LOCK, IPC_TYPE_SET,
+						req, sizeof(struct ipc_sec_phone_lock_set),
+						pin_enable_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static void puk_send_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ipc_gen_phone_res *resp = data;
+
+	if (error || cmd != IPC_GEN_PHONE_RES ||
+		ipc_gen_phone_res_check(resp) < 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_send_puk(struct ofono_sim *sim, const char *puk,
+				const char *passwd,
+				ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd;
+
+	struct ipc_sec_pin_status_set *req;
+
+	DBG("");
+
+	req = g_try_new0(struct ipc_sec_pin_status_set, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	ipc_sec_pin_status_set_setup(req, IPC_SEC_PIN_TYPE_PIN1, (char*) passwd, (char*) puk);
+
+	if(ipc_device_enqueue_message(sd->device, IPC_SEC_SIM_STATUS, IPC_TYPE_SET,
+						req, sizeof(struct ipc_sec_pin_status_set),
+						puk_send_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void read_binary_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_read_cb_t cb = cbd->cb;
+	const guint8 *response;
+	struct ipc_sec_rsim_access_response *resp;
+	struct ofono_error err;
+
+	if (error || cmd != IPC_SEC_RSIM_ACCESS) {
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+		goto done;
+	}
+
+	resp = data;
+
+	DBG("rsim_access_cb: sw1=%02x, sw2=%02x, len=%i", resp->sw1, resp->sw2, resp->len);
+
+	/* taken from drivers/atmodem/sim.c */
+	if ((resp->sw1 != 0x90 && resp->sw1 != 0x91 && resp->sw1 != 0x92) ||
+		(resp->sw1 == 0x90 && resp->sw2 != 0x00)) {
+		memset(&error, 0, sizeof(error));
+
+		err.type = OFONO_ERROR_TYPE_SIM;
+		err.error = (resp->sw1 << 8) | resp->sw2;
+
+		cb(&err, NULL, 0, cbd->data);
+		goto done;
+	}
+
+	response = (const guint8*) data + sizeof(struct ipc_sec_rsim_access_response);
+
+	cb(&err, response, resp->len, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_read_binary(struct ofono_sim *sim, int fileid,
+					int start, int length,
+					ofono_sim_read_cb_t cb, void *cb_data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd;
+	struct ipc_sec_rsim_access_get *req;
+
+	DBG("");
+
+	req = g_try_new0(struct ipc_sec_rsim_access_get, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, cb_data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, cb_data);
+
+	req->command = IPC_SEC_RSIM_COMMAND_READ_BINARY;
+	req->fileid = (unsigned short) fileid;
+	req->p1 = start >> 8;
+	req->p2 = start & 0xff;
+	req->p3 = length;
+
+	if(ipc_device_enqueue_message(sd->device, IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET,
+						req, sizeof(struct ipc_sec_rsim_access_get),
+						read_binary_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, 0, cb_data);
+}
+
+static void query_passwd_state_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_passwd_cb_t cb = cbd->cb;
+	struct ipc_sec_sim_status_response *resp = data;
+	enum ofono_sim_password_type passwd_state;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+		goto done;
+	}
+
+	switch (resp->facility_lock) {
+	case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ:
+		passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
+		break;
+	case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ:
+		passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
+		break;
+	case IPC_SEC_FACILITY_LOCK_TYPE_SC_UNLOCKED:
+		passwd_state = OFONO_SIM_PASSWORD_NONE;
+		break;
+	default:
+		passwd_state = OFONO_SIM_PASSWORD_INVALID;
+		break;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, passwd_state, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_query_passwd_state(struct ofono_sim *sim,
+					ofono_sim_passwd_cb_t cb, void *user_data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd = cb_data_new(cb, user_data);
+
+	DBG("");
+
+	if(ipc_device_enqueue_message(sd->device, IPC_SEC_SIM_STATUS, IPC_TYPE_GET,
+						NULL, 0, query_passwd_state_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, -1, user_data);
+}
+
+static void notify_sim_status_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ipc_sec_sim_status_response *resp = data;
+	struct sim_data *sd = cbd->user;
+
+	switch (resp->status) {
+	case IPC_SEC_SIM_STATUS_INITIALIZING:
+	case IPC_SEC_SIM_STATUS_PB_INIT_COMPLETE:
+		/* Ok, SIM is initializing now; next status update will tell us more */
+		break;
+	case IPC_SEC_SIM_STATUS_INIT_COMPLETE:
+		/* SIM initialization is done now */
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		goto done;
+	default:
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	return;
+
+done:
+	ipc_device_remove_watch(sd->device, sd->sim_state_query);
+	g_free(cbd);
+}
+
+static void pin_send_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct sim_data *sd = cbd->user;
+	struct ipc_gen_phone_res *resp = data;
+
+	if (error || cmd != IPC_GEN_PHONE_RES ||
+		ipc_gen_phone_res_check(resp) < 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+		return;
+	}
+
+	/* wait until SIM init complete status notification arrives */
+	sd->sim_state_query = ipc_device_add_notifcation_watch(sd->device,
+												IPC_SEC_SIM_STATUS, notify_sim_status_cb, cbd);
+}
+
+static void samsungipc_pin_send(struct ofono_sim *sim, const char *passwd,
+			ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd;
+	struct ipc_sec_pin_status_set *req;
+
+	DBG("");
+
+	req = g_try_new0(struct ipc_sec_pin_status_set, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+	cbd->user = sd;
+
+	ipc_sec_pin_status_set_setup(req, IPC_SEC_PIN_TYPE_PIN1, (char*) passwd, NULL);
+
+	if(ipc_device_enqueue_message(sd->device, IPC_SEC_SIM_STATUS, IPC_TYPE_SET,
+						req, sizeof(struct ipc_sec_pin_status_set),
+						pin_send_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void read_imsi_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_imsi_cb_t cb = cbd->cb;
+	char imsi[SIM_MAX_IMSI_LENGTH + 1];
+	guint8 len;
+	char *imsi_data;
+
+	len = *((guint8*) data);
+	imsi_data = ((char*) data)  + 1;
+
+	strncpy(imsi, imsi_data, len);
+
+	CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
+
+	g_free(cbd);
+}
+
+static void samsungipc_read_imsi(struct ofono_sim *sim,
+				ofono_sim_imsi_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd;
+
+	cbd = cb_data_new(cb, data);
+
+	DBG("");
+
+	if(ipc_device_enqueue_message(sd->device, IPC_MISC_ME_IMSI, IPC_TYPE_GET,
+						NULL, 0, read_imsi_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, data);
+}
+
+static void lock_info_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_pin_retries_cb_t cb = cbd->cb;
+	struct ipc_sec_lock_info_response *resp = data;
+	struct sim_data *sd = cbd->user;
+	struct ipc_sec_lock_info_get *req;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+		goto done;
+	}
+
+	switch (resp->type) {
+	case IPC_SEC_PIN_TYPE_PIN1:
+		sd->pin_attempts[OFONO_SIM_PASSWORD_SIM_PIN] = resp->attempts;
+
+		req = g_try_new0(struct ipc_sec_lock_info_get, 1);
+		if (!req) {
+			CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+			goto done;
+		}
+
+		ipc_sec_lock_info_get_setup(req, IPC_SEC_PIN_TYPE_PIN2);
+
+		if(ipc_device_enqueue_message(sd->device, IPC_SEC_LOCK_INFO, IPC_TYPE_GET,
+						req, sizeof(struct ipc_sec_lock_info_get),
+						lock_info_cb, cbd) > 0)
+			return;
+
+		goto error;
+	case IPC_SEC_PIN_TYPE_PIN2:
+		sd->pin_attempts[OFONO_SIM_PASSWORD_SIM_PIN2] = resp->attempts;
+		break;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, sd->pin_attempts, cbd->data);
+
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_query_pin_retries(struct ofono_sim *sim,
+					ofono_sim_pin_retries_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd;
+	struct ipc_sec_lock_info_get *req;
+
+	DBG("");
+
+	req = g_try_new0(struct ipc_sec_lock_info_get, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, NULL, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+	cbd->user = sd;
+
+	ipc_sec_lock_info_get_setup(req, IPC_SEC_PIN_TYPE_PIN1);
+
+	memset(sd->pin_attempts, 0, sizeof(sd->pin_attempts));
+
+	if(ipc_device_enqueue_message(sd->device, IPC_SEC_LOCK_INFO, IPC_TYPE_GET,
+						req, sizeof(struct ipc_sec_lock_info_get),
+						lock_info_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, data);
+}
+
+static void initial_sim_status_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct ofono_sim *sim = user_data;
+	struct ipc_sec_sim_status_response *resp = data;
+
+	if (error) {
+		ofono_sim_remove(sim);
+		return;
+	}
+
+	ofono_sim_register(sim);
+
+	switch (resp->status) {
+	case IPC_SEC_SIM_STATUS_INITIALIZING:
+	case IPC_SEC_SIM_STATUS_SIM_LOCK_REQUIRED:
+	case IPC_SEC_SIM_STATUS_INIT_COMPLETE:
+	case IPC_SEC_SIM_STATUS_PB_INIT_COMPLETE:
+	case IPC_SEC_SIM_STATUS_LOCK_SC:
+	case IPC_SEC_SIM_STATUS_LOCK_FD:
+	case IPC_SEC_SIM_STATUS_LOCK_PN:
+	case IPC_SEC_SIM_STATUS_LOCK_PU:
+	case IPC_SEC_SIM_STATUS_LOCK_PP:
+		ofono_sim_inserted_notify(sim, TRUE);
+		break;
+	case IPC_SEC_SIM_STATUS_CARD_ERROR:
+	case IPC_SEC_SIM_STATUS_CARD_NOT_PRESENT:
+	case IPC_SEC_SIM_STATUS_INSIDE_PF_ERROR:
+		ofono_sim_inserted_notify(sim, FALSE);
+		break;
+	}
+}
+
+static int samsungipc_sim_probe(struct ofono_sim *sim, unsigned int vendor,
+				void *user_data)
+{
+	struct sim_data *sd;
+
+	DBG("");
+
+	sd = g_try_new0(struct sim_data, 1);
+	if (sd == NULL)
+		return -ENOMEM;
+
+	sd->device = user_data;
+
+	ofono_sim_set_data(sim, sd);
+
+	ipc_device_enqueue_message(sd->device, IPC_SEC_SIM_STATUS, IPC_TYPE_GET,
+						NULL, 0, initial_sim_status_cb, sim);
+
+	return 0;
+}
+
+static void samsungipc_sim_remove(struct ofono_sim *sim)
+{
+	struct sim_data *data = ofono_sim_get_data(sim);
+
+	ofono_sim_set_data(sim, NULL);
+
+	if (data == NULL)
+		return;
+
+	g_free(data);
+}
+
+static struct ofono_sim_driver driver = {
+	.name					= "samsungipcmodem",
+	.probe					= samsungipc_sim_probe,
+	.remove					= samsungipc_sim_remove,
+	.query_passwd_state		= samsungipc_query_passwd_state,
+	.query_pin_retries		= samsungipc_query_pin_retries,
+	.send_passwd			= samsungipc_pin_send,
+	.reset_passwd			= samsungipc_send_puk,
+	.lock					= samsungipc_pin_enable,
+	.change_passwd			= samsungipc_change_passwd,
+	.query_locked			= samsungipc_pin_query_enabled,
+	.read_imsi				= samsungipc_read_imsi,
+	.read_file_transparent	= samsungipc_read_binary,
+};
+
+void samsungipc_sim_init(void)
+{
+	ofono_sim_driver_register(&driver);
+}
+
+void samsungipc_sim_exit(void)
+{
+	ofono_sim_driver_unregister(&driver);
+}
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 07/11] samsungipcmodem: add network registration driver implementation
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (5 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 06/11] samsungipcmodem: add sim " Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 08/11] samsungipcmodem: add voicecall " Simon Busch
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am                                    |    3 +-
 drivers/samsungipcmodem/network-registration.c |  398 ++++++++++++++++++++++++
 drivers/samsungipcmodem/samsungipcmodem.c      |    2 +
 drivers/samsungipcmodem/samsungipcmodem.h      |    2 +
 4 files changed, 404 insertions(+), 1 deletion(-)
 create mode 100644 drivers/samsungipcmodem/network-registration.c

diff --git a/Makefile.am b/Makefile.am
index 5553489..32ed3de 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -189,7 +189,8 @@ builtin_sources += \
 	drivers/samsungipcmodem/ipc.c \
 	drivers/samsungipcmodem/ipc.h \
 	drivers/samsungipcmodem/devinfo.c \
-	drivers/samsungipcmodem/sim.c
+	drivers/samsungipcmodem/sim.c \
+	drivers/samsungipcmodem/network-registration.c
 builtin_cflags += @SAMSUNGIPC_CFLAGS@
 builtin_libadd += @SAMSUNGIPC_LIBS@
 endif
diff --git a/drivers/samsungipcmodem/network-registration.c b/drivers/samsungipcmodem/network-registration.c
new file mode 100644
index 0000000..f8ea22f
--- /dev/null
+++ b/drivers/samsungipcmodem/network-registration.c
@@ -0,0 +1,398 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  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
+ *
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/netreg.h>
+
+#include "samsungipcmodem.h"
+#include "ipc.h"
+#include "util.h"
+
+struct netreg_data {
+	struct ipc_device *device;
+	guint status_watch;
+	guint rssi_watch;
+	int strength;
+};
+
+static void list_operators_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_operator_list_cb_t cb = cbd->cb;
+	struct ofono_network_operator *list;
+	struct ofono_network_operator *op;
+	struct ipc_net_plmn_entries *resp = data;
+	struct ipc_net_plmn_entry *entries = data + sizeof(struct ipc_net_plmn_entries);
+	struct ipc_net_plmn_entry *entry;
+	int i;
+
+	DBG("Got %d elements", resp->num);
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+		goto done;
+	}
+
+	list = g_try_new0(struct ofono_network_operator, resp->num);
+	if (list == NULL) {
+		CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+		goto done;
+	}
+
+	for (i = 0; i < resp->num; i++) {
+		op = &list[i];
+		entry = &entries[i];
+
+		op->status = entry->status - 1;
+
+		strncpy(op->mcc, entry->plmn, 3);
+		op->mcc[OFONO_MAX_MCC_LENGTH] = '\0';
+
+		strncpy(op->mnc, entry->plmn + 3, 2);
+		op->mnc[OFONO_MAX_MNC_LENGTH] = '\0';
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, resp->num, list, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_list_operators(struct ofono_netreg *netreg,
+				ofono_netreg_operator_list_cb_t cb, void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct cb_data *cbd = cb_data_new(cb, data);
+
+	if(ipc_device_enqueue_message(nd->device, IPC_NET_PLMN_LIST, IPC_TYPE_GET,
+						NULL, 0, list_operators_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, 0, NULL, data);
+}
+
+static void samsungipc_signal_strength(struct ofono_netreg *netreg,
+				ofono_netreg_strength_cb_t cb, void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+
+	CALLBACK_WITH_SUCCESS(cb, nd->strength, data);
+}
+
+static void network_register_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_register_cb_t cb = cbd->cb;
+	struct ipc_gen_phone_res *resp = data;
+
+	if (error || ipc_gen_phone_res_check(resp) < 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_register_manual(struct ofono_netreg *netreg,
+				const char *mcc, const char *mnc,
+				ofono_netreg_register_cb_t cb, void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct cb_data *cbd;
+	struct ipc_net_plmn_sel_set *req;
+	char plmn[5];
+
+	req = g_try_new0(struct ipc_net_plmn_sel_set, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	snprintf(plmn, 5, "%s%s", mcc, mnc);
+	ipc_net_plmn_sel_set_setup(req, IPC_NET_PLMN_SEL_MANUAL, plmn,
+						IPC_NET_ACCESS_TECHNOLOGY_UMTS);
+
+	if(ipc_device_enqueue_message(nd->device, IPC_NET_PLMN_SEL, IPC_TYPE_SET,
+						req, sizeof(struct ipc_net_plmn_sel_set),
+						network_register_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void samsungipc_register_auto(struct ofono_netreg *netreg,
+				ofono_netreg_register_cb_t cb, void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct cb_data *cbd;
+	struct ipc_net_plmn_sel_set *req;
+
+	req = g_try_new0(struct ipc_net_plmn_sel_set, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	ipc_net_plmn_sel_set_setup(req, IPC_NET_PLMN_SEL_AUTO, NULL,
+						IPC_NET_ACCESS_TECHNOLOGY_UNKNOWN);
+
+	if(ipc_device_enqueue_message(nd->device, IPC_NET_PLMN_SEL, IPC_TYPE_SET,
+						req, sizeof(struct ipc_net_plmn_sel_set),
+						network_register_cb, cbd) > 0)
+		return;
+
+	g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void current_operator_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_operator_cb_t cb = cbd->cb;
+	struct ipc_net_current_plmn_response *resp = data;
+	struct ofono_network_operator op;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+		goto done;
+	}
+
+	strncpy(op.mcc, resp->plmn, 3);
+	op.mcc[OFONO_MAX_MCC_LENGTH] = '\0';
+
+	strncpy(op.mnc, &resp->plmn[3], 2);
+	op.mnc[OFONO_MAX_MNC_LENGTH] = '\0';
+
+	memset(op.name, 0, OFONO_MAX_OPERATOR_NAME_LENGTH);
+
+	/* Set to current */
+	op.status = 2;
+	/* FIXME check wether this is correct! */
+	op.tech = resp->type;
+
+	DBG("current_operator_cb: mcc=%s, mnc=%s, reg_state=%d, tech=%d",
+		op.mcc, op.mnc, op.status, op.tech);
+
+	CALLBACK_WITH_SUCCESS(cb, &op, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_current_operator(struct ofono_netreg *netreg,
+				ofono_netreg_operator_cb_t cb, void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct cb_data *cbd = cb_data_new(cb, data);
+
+	if(ipc_device_enqueue_message(nd->device, IPC_NET_CURRENT_PLMN, IPC_TYPE_GET,
+						NULL, 0, current_operator_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, NULL, data);
+
+	g_free(cbd);
+}
+
+static void net_status_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_status_cb_t cb = cbd->cb;
+	struct ipc_net_regist_response *resp = data;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, cbd->data);
+		goto done;
+	}
+
+	DBG("reg_state=%i, lac=%i, cid=%i, act=%i", resp->reg_state - 1,
+		resp->lac, resp->cid, resp->act);
+
+	CALLBACK_WITH_SUCCESS(cb, resp->reg_state - 1, resp->lac,
+					resp->cid, resp->act, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_registration_status(struct ofono_netreg *netreg,
+					ofono_netreg_status_cb_t cb,
+					void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct cb_data *cbd;
+	struct ipc_net_regist_get *req;
+
+	req = g_try_new0(struct ipc_net_regist_get, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	ipc_net_regist_get_setup(req, IPC_NET_SERVICE_DOMAIN_GSM);
+
+	if(ipc_device_enqueue_message(nd->device, IPC_NET_REGIST, IPC_TYPE_GET,
+						req, sizeof(struct ipc_net_regist_get),
+						net_status_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data);
+
+	g_free(cbd);
+}
+
+static void notify_status_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_netreg *netreg = user_data;
+	struct ipc_net_regist_response *resp = data;
+
+	if (resp->domain == IPC_NET_SERVICE_DOMAIN_GPRS)
+		return;
+
+	DBG("reg_state=%i, lac=%i, cid=%i, act=%i", resp->reg_state - 1,
+		resp->lac, resp->cid, resp->act);
+
+	ofono_netreg_status_notify(netreg, resp->reg_state - 1,
+							resp->lac, resp->cid, resp->act);
+}
+
+static int convert_signal_strength(unsigned char rssi)
+{
+	int strength = 0;
+
+	if (rssi < 0x6f)
+		strength = ((((rssi - 0x71) * -1) - (((rssi - 0x71) * -1) % 2)) / 2);
+
+	if (strength > 31)
+		strength = 31;
+
+	return ((strength * 100) / (31));
+}
+
+static void notify_rssi_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_netreg *netreg = user_data;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct ipc_disp_rssi_info *resp = data;
+
+	nd->strength = convert_signal_strength(resp->rssi);
+
+	DBG("rssi=%i, strength=%i", resp->rssi, nd->strength);
+
+	ofono_netreg_strength_notify(netreg, nd->strength);
+}
+
+static void initial_status_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_netreg *netreg = user_data;
+	struct ipc_net_regist_response *resp = data;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+
+	ofono_netreg_register(netreg);
+
+	ofono_netreg_status_notify(netreg, resp->reg_state - 1,
+							resp->lac, resp->cid, resp->act);
+
+	ipc_device_remove_watch(nd->device, nd->status_watch);
+
+	nd->status_watch = ipc_device_add_notifcation_watch(nd->device, IPC_NET_REGIST,
+								notify_status_cb, netreg);
+
+	nd->rssi_watch = ipc_device_add_notifcation_watch(nd->device, IPC_DISP_RSSI_INFO,
+													notify_rssi_cb, netreg);
+}
+
+static int samsungipc_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
+				void *data)
+{
+	struct netreg_data *nd;
+
+	nd = g_new0(struct netreg_data, 1);
+	if (!nd)
+		return -ENOMEM;
+
+	nd->device = data;
+	nd->strength = 0;
+
+	ofono_netreg_set_data(netreg, nd);
+
+	nd->status_watch = ipc_device_add_notifcation_watch(nd->device, IPC_NET_REGIST,
+												initial_status_cb, netreg);
+
+	return 0;
+}
+
+static void samsungipc_netreg_remove(struct ofono_netreg *netreg)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+
+	ipc_device_remove_watch(nd->device, nd->status_watch);
+	ipc_device_remove_watch(nd->device, nd->rssi_watch);
+
+	ofono_netreg_set_data(netreg, NULL);
+
+	g_free(nd);
+}
+
+static struct ofono_netreg_driver driver = {
+	.name					= "samsungipcmodem",
+	.probe					= samsungipc_netreg_probe,
+	.remove					= samsungipc_netreg_remove,
+	.registration_status	= samsungipc_registration_status,
+	.current_operator		= samsungipc_current_operator,
+	.register_auto			= samsungipc_register_auto,
+	.register_manual		= samsungipc_register_manual,
+	.strength				= samsungipc_signal_strength,
+	.list_operators			= samsungipc_list_operators,
+};
+
+void samsungipc_netreg_init(void)
+{
+	ofono_netreg_driver_register(&driver);
+}
+
+void samsungipc_netreg_exit(void)
+{
+	ofono_netreg_driver_unregister(&driver);
+}
diff --git a/drivers/samsungipcmodem/samsungipcmodem.c b/drivers/samsungipcmodem/samsungipcmodem.c
index 78e698c..a192686 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.c
+++ b/drivers/samsungipcmodem/samsungipcmodem.c
@@ -32,11 +32,13 @@ static int samsungipcmodem_init(void)
 {
 	samsungipc_devinfo_init();
 	samsungipc_sim_init();
+	samsungipc_netreg_init();
 	return 0;
 }
 
 static void samsungipcmodem_exit(void)
 {
+	samsungipc_netreg_exit();
 	samsungipc_sim_exit();
 	samsungipc_devinfo_exit();
 }
diff --git a/drivers/samsungipcmodem/samsungipcmodem.h b/drivers/samsungipcmodem/samsungipcmodem.h
index c98d213..3f4d5ad 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.h
+++ b/drivers/samsungipcmodem/samsungipcmodem.h
@@ -23,3 +23,5 @@ extern void samsungipc_devinfo_init(void);
 extern void samsungipc_devinfo_exit(void);
 extern void samsungipc_sim_init(void);
 extern void samsungipc_sim_exit(void);
+extern void samsungipc_netreg_init(void);
+extern void samsungipc_netreg_exit(void);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 08/11] samsungipcmodem: add voicecall driver implementation
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (6 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 07/11] samsungipcmodem: add network registration " Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 09/11] samsungipcmodem: add gprs " Simon Busch
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am                               |    3 +-
 drivers/samsungipcmodem/samsungipcmodem.c |    2 +
 drivers/samsungipcmodem/samsungipcmodem.h |    2 +
 drivers/samsungipcmodem/voicecall.c       |  358 +++++++++++++++++++++++++++++
 4 files changed, 364 insertions(+), 1 deletion(-)
 create mode 100644 drivers/samsungipcmodem/voicecall.c

diff --git a/Makefile.am b/Makefile.am
index 32ed3de..012c78d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -190,7 +190,8 @@ builtin_sources += \
 	drivers/samsungipcmodem/ipc.h \
 	drivers/samsungipcmodem/devinfo.c \
 	drivers/samsungipcmodem/sim.c \
-	drivers/samsungipcmodem/network-registration.c
+	drivers/samsungipcmodem/network-registration.c \
+	drivers/samsungipcmodem/voicecall.c
 builtin_cflags += @SAMSUNGIPC_CFLAGS@
 builtin_libadd += @SAMSUNGIPC_LIBS@
 endif
diff --git a/drivers/samsungipcmodem/samsungipcmodem.c b/drivers/samsungipcmodem/samsungipcmodem.c
index a192686..72553a5 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.c
+++ b/drivers/samsungipcmodem/samsungipcmodem.c
@@ -33,11 +33,13 @@ static int samsungipcmodem_init(void)
 	samsungipc_devinfo_init();
 	samsungipc_sim_init();
 	samsungipc_netreg_init();
+	samsungipc_voicecall_init();
 	return 0;
 }
 
 static void samsungipcmodem_exit(void)
 {
+	samsungipc_voicecall_exit();
 	samsungipc_netreg_exit();
 	samsungipc_sim_exit();
 	samsungipc_devinfo_exit();
diff --git a/drivers/samsungipcmodem/samsungipcmodem.h b/drivers/samsungipcmodem/samsungipcmodem.h
index 3f4d5ad..092effd 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.h
+++ b/drivers/samsungipcmodem/samsungipcmodem.h
@@ -25,3 +25,5 @@ extern void samsungipc_sim_init(void);
 extern void samsungipc_sim_exit(void);
 extern void samsungipc_netreg_init(void);
 extern void samsungipc_netreg_exit(void);
+extern void samsungipc_voicecall_init(void);
+extern void samsungipc_voicecall_exit(void);
diff --git a/drivers/samsungipcmodem/voicecall.c b/drivers/samsungipcmodem/voicecall.c
new file mode 100644
index 0000000..5236e0f
--- /dev/null
+++ b/drivers/samsungipcmodem/voicecall.c
@@ -0,0 +1,358 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  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
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/voicecall.h>
+
+#include "samsungipcmodem.h"
+#include "ipc.h"
+#include "util.h"
+
+/* Amount of ms we wait between call status requests */
+#define CALL_STATUS_POLL_INTERVAL 500
+
+struct voicecall_data {
+	struct ipc_device *device;
+	int dtmf_active;
+	unsigned int status_update_pending;
+};
+
+static void send_dtmf_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_voicecall_cb_t cb = cbd->cb;
+	unsigned char ret;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	ret = *((unsigned char*) data);
+	if (!ret) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
+			ofono_voicecall_cb_t cb, void *data)
+{
+	struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct cb_data *cbd;
+	struct ipc_call_cont_dtmf *reqs;
+	int tone_count;
+	int n;
+
+	DBG("");
+
+	tone_count = strlen(dtmf);
+
+	reqs = g_try_new0(struct ipc_call_cont_dtmf, tone_count);
+	if (!reqs) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	for (n = 0; n > tone_count; n++) {
+		reqs[n].state = IPC_CALL_DTMF_STATE_START;
+		reqs[n].tone = dtmf[n];
+	}
+
+	if(ipc_device_enqueue_message(vd->device, IPC_CALL_RELEASE, IPC_TYPE_EXEC,
+						reqs, sizeof(struct ipc_call_cont_dtmf) * tone_count,
+						send_dtmf_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static void common_call_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_voicecall_cb_t cb = cbd->cb;
+	struct ipc_gen_phone_res *resp = data;
+
+	if (error || ipc_gen_phone_res_check(resp) < 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_hangup_active(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct cb_data *cbd = cb_data_new(cb, data);
+
+	DBG("");
+
+	if(ipc_device_enqueue_message(vd->device, IPC_CALL_RELEASE, IPC_TYPE_EXEC,
+						NULL, 0, common_call_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static void samsungipc_answer(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct cb_data *cbd = cb_data_new(cb, data);
+
+	DBG("");
+
+	if(ipc_device_enqueue_message(vd->device, IPC_CALL_ANSWER, IPC_TYPE_EXEC,
+						NULL, 0, common_call_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static void samsungipc_dial(struct ofono_voicecall *vc,
+			const struct ofono_phone_number *ph,
+			enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
+			void *data)
+{
+	struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct ipc_call_outgoing *req;
+	struct cb_data *cbd;
+
+	DBG("");
+
+	req = g_try_new0(struct ipc_call_outgoing, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	switch (clir) {
+	case OFONO_CLIR_OPTION_DEFAULT:
+		req->identity = IPC_CALL_IDENTITY_DEFAULT;
+		break;
+	case OFONO_CLIR_OPTION_INVOCATION:
+		req->identity = IPC_CALL_IDENTITY_SHOW;
+		break;
+	case OFONO_CLIR_OPTION_SUPPRESSION:
+		req->identity = IPC_CALL_IDENTITY_HIDE;
+		break;
+	}
+
+	req->type = IPC_CALL_TYPE_VOICE;
+	req->prefix = (ph->type == 145) ? IPC_CALL_PREFIX_INTL : IPC_CALL_PREFIX_NONE;
+	req->length = strlen(ph->number);
+	strncpy((char*) req->number, ph->number, 86);
+
+	if(ipc_device_enqueue_message(vd->device, IPC_CALL_OUTGOING, IPC_TYPE_EXEC,
+						req, sizeof(struct ipc_call_outgoing),
+						common_call_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+
+	g_free(cbd);
+}
+
+static void call_list_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct ipc_message_info resp;
+	struct ipc_call_list_entry *entry;
+	struct ofono_call call;
+	char *entry_number;
+	int num_entries;
+	int n;
+
+	DBG("");
+
+	if (error)
+		return;
+
+	resp.data = data;
+	resp.length = length;
+
+	num_entries = ipc_call_list_response_get_num_entries(&resp);
+
+	DBG("Got %i entries", num_entries);
+
+	for (n = 0; n < num_entries; n++) {
+		ofono_call_init(&call);
+
+		entry = ipc_call_list_response_get_entry(&resp, n);
+
+		call.id = entry->idx;
+		call.type = (entry->type == IPC_CALL_TYPE_VOICE) ? 0 : 1;
+		call.direction = (entry->term == IPC_CALL_TERM_MT) ? 0 : 1;
+		call.status = entry->state - 1;
+
+		memset(&call.phone_number.type, 0, OFONO_MAX_PHONE_NUMBER_LENGTH);
+
+		entry_number = ipc_call_list_response_get_entry_number(&resp, n);
+		if (entry_number != NULL) {
+			strncpy(call.phone_number.number, entry_number, OFONO_MAX_CALLER_NAME_LENGTH);
+			call.phone_number.number[entry->number_len] = '\0';
+			call.phone_number.type = (entry->number_len > 0 && call.phone_number.number[0] == '+') ? 145 : 129;
+			g_free(entry_number);
+		}
+
+		DBG("id=%i, type=%i, direction=%i, status=%i, number=%s",
+			call.id, call.type, call.direction, call.status,
+			call.phone_number.number);
+
+		ofono_voicecall_notify(vc, &call);
+	}
+
+	vd->status_update_pending = 0;
+}
+
+static void update_call_status(struct ofono_voicecall *vc)
+{
+	struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+	if (vd->status_update_pending)
+		return;
+
+	vd->status_update_pending = 1;
+
+	if(ipc_device_enqueue_message(vd->device, IPC_CALL_LIST, IPC_TYPE_GET,
+						NULL, 0, call_list_cb, vc) > 0)
+		return;
+}
+
+static void notify_call_incoming_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+
+	update_call_status(vc);
+}
+
+static void notify_call_status_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct ipc_call_status *resp = data;
+
+	DBG("");
+
+	if (resp->state == IPC_CALL_STATE_RELEASED) {
+		// FIXME what are possible values for resp->reason?
+		ofono_voicecall_disconnected(vc, resp->id, OFONO_DISCONNECT_REASON_UNKNOWN, NULL);
+		return;
+	}
+
+	update_call_status(vc);
+}
+
+static gboolean initialization_done_cb(gpointer user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+	ipc_device_add_notifcation_watch(vd->device, IPC_CALL_INCOMING, notify_call_incoming_cb, vc);
+	ipc_device_add_notifcation_watch(vd->device, IPC_CALL_STATUS, notify_call_status_cb, vc);
+	ipc_device_add_notifcation_watch(vd->device, IPC_CALL_RELEASE, notify_call_status_cb, vc);
+	ipc_device_add_notifcation_watch(vd->device, IPC_CALL_ANSWER, notify_call_status_cb, vc);
+	ipc_device_add_notifcation_watch(vd->device, IPC_CALL_OUTGOING, notify_call_status_cb, vc);
+	ipc_device_add_notifcation_watch(vd->device, IPC_CALL_WAITING, notify_call_status_cb, vc);
+
+	ofono_voicecall_register(vc);
+
+	return FALSE;
+}
+
+static int samsungipc_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
+				void *data)
+{
+	struct voicecall_data *vd;
+
+	DBG("");
+
+	vd = g_try_new0(struct voicecall_data, 1);
+	if (vd == NULL)
+		return -ENOMEM;
+
+	vd->device = data;
+	vd->dtmf_active = 0;
+	vd->status_update_pending = 0;
+
+	ofono_voicecall_set_data(vc, vd);
+
+	g_timeout_add_seconds(0, initialization_done_cb, vc);
+
+	return 0;
+}
+
+static void samsungipc_voicecall_remove(struct ofono_voicecall *vc)
+{
+	struct voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+	g_free(vd);
+}
+
+static struct ofono_voicecall_driver driver = {
+	.name			= "samsungipcmodem",
+	.probe			= samsungipc_voicecall_probe,
+	.remove			= samsungipc_voicecall_remove,
+	.dial			= samsungipc_dial,
+	.answer			= samsungipc_answer,
+	.hangup_active	= samsungipc_hangup_active,
+	.send_tones		= samsungipc_send_dtmf,
+};
+
+void samsungipc_voicecall_init(void)
+{
+	ofono_voicecall_driver_register(&driver);
+}
+
+void samsungipc_voicecall_exit(void)
+{
+	ofono_voicecall_driver_unregister(&driver);
+}
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 09/11] samsungipcmodem: add gprs driver implementation
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (7 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 08/11] samsungipcmodem: add voicecall " Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 10/11] samsungipcmodem: add gprs-context " Simon Busch
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am                               |    3 +-
 drivers/samsungipcmodem/gprs.c            |  215 +++++++++++++++++++++++++++++
 drivers/samsungipcmodem/samsungipcmodem.c |    2 +
 drivers/samsungipcmodem/samsungipcmodem.h |    2 +
 4 files changed, 221 insertions(+), 1 deletion(-)
 create mode 100644 drivers/samsungipcmodem/gprs.c

diff --git a/Makefile.am b/Makefile.am
index 012c78d..1bfdf91 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -191,7 +191,8 @@ builtin_sources += \
 	drivers/samsungipcmodem/devinfo.c \
 	drivers/samsungipcmodem/sim.c \
 	drivers/samsungipcmodem/network-registration.c \
-	drivers/samsungipcmodem/voicecall.c
+	drivers/samsungipcmodem/voicecall.c \
+	drivers/samsungipcmodem/gprs.c
 builtin_cflags += @SAMSUNGIPC_CFLAGS@
 builtin_libadd += @SAMSUNGIPC_LIBS@
 endif
diff --git a/drivers/samsungipcmodem/gprs.c b/drivers/samsungipcmodem/gprs.c
new file mode 100644
index 0000000..f728bc7
--- /dev/null
+++ b/drivers/samsungipcmodem/gprs.c
@@ -0,0 +1,215 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  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 <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs.h>
+
+#include <glib.h>
+
+#include "samsungipcmodem.h"
+#include "ipc.h"
+#include "util.h"
+
+struct gprs_data {
+	struct ipc_device *device;
+	guint status_watch;
+	guint hsdpa_status_watch;
+};
+
+static void samsungipc_set_attached(struct ofono_gprs *gprs, int attached,
+					ofono_gprs_cb_t cb, void *data)
+{
+	/* No attach/detach possible so always succeed here */
+	CALLBACK_WITH_SUCCESS(cb, data);
+}
+
+static void gprs_attached_status_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_gprs_status_cb_t cb = cbd->cb;
+	struct ipc_net_regist_response *resp = data;
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+		goto done;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, resp->reg_state - 1, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_attached_status(struct ofono_gprs *gprs,
+				ofono_gprs_status_cb_t cb, void *data)
+{
+	struct gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct cb_data *cbd;
+	struct ipc_net_regist_get *req;
+
+	DBG("");
+
+	req = g_try_new0(struct ipc_net_regist_get, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+
+	ipc_net_regist_get_setup(req, IPC_NET_SERVICE_DOMAIN_GPRS);
+
+	if(ipc_device_enqueue_message(gd->device, IPC_NET_REGIST, IPC_TYPE_GET,
+						req, sizeof(struct ipc_net_regist_get),
+						gprs_attached_status_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+
+	g_free(cbd);
+	g_free(req);
+}
+
+static void notify_gprs_status_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_gprs *gprs = user_data;
+	struct ipc_net_regist_response *resp = data;
+
+	if (resp->domain != IPC_NET_SERVICE_DOMAIN_GPRS)
+		return;
+
+	ofono_gprs_status_notify(gprs, resp->reg_state - 1);
+}
+
+static void gprs_status_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct ofono_gprs *gprs = user_data;
+	struct ipc_net_regist_response *resp = data;
+
+	if (resp->domain != IPC_NET_SERVICE_DOMAIN_GPRS || error)
+		return;
+
+	ofono_gprs_status_notify(gprs, resp->reg_state - 1);
+}
+
+static void notify_hsdpa_status_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_gprs *gprs = user_data;
+	struct gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct ipc_net_regist_get *req;
+
+	DBG("");
+
+	req = g_try_new0(struct ipc_net_regist_get, 1);
+	if (!req)
+		return;
+
+	ipc_net_regist_get_setup(req, IPC_NET_SERVICE_DOMAIN_GPRS);
+
+	if(ipc_device_enqueue_message(gd->device, IPC_NET_REGIST, IPC_TYPE_GET,
+						req, sizeof(struct ipc_net_regist_get),
+						gprs_status_cb, gprs) > 0)
+		return;
+
+	g_free(req);
+}
+
+static void initial_status_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_gprs *gprs = user_data;
+	struct ipc_net_regist_response *resp = data;
+	struct gprs_data *gd = ofono_gprs_get_data(gprs);
+
+	if (resp->domain != IPC_NET_SERVICE_DOMAIN_GPRS)
+		return;
+
+	ofono_gprs_register(gprs);
+
+	ofono_gprs_status_notify(gprs, resp->reg_state - 1);
+
+	ipc_device_remove_watch(gd->device, gd->status_watch);
+
+	gd->status_watch = ipc_device_add_notifcation_watch(gd->device, IPC_NET_REGIST,
+								notify_gprs_status_cb, gprs);
+}
+
+static int samsungipc_gprs_probe(struct ofono_gprs *gprs,
+				unsigned int vendor, void *user_data)
+{
+	struct gprs_data *gd;
+	struct ipc_client *client;
+	struct ipc_client_gprs_capabilities caps;
+
+	DBG("");
+
+	gd = g_new0(struct gprs_data, 1);
+	gd->device = user_data;
+
+	ofono_gprs_set_data(gprs, gd);
+
+	gd->status_watch = ipc_device_add_notifcation_watch(gd->device, IPC_NET_REGIST,
+												initial_status_cb, gprs);
+	gd->hsdpa_status_watch = ipc_device_add_notifcation_watch(gd->device, IPC_GPRS_HSDPA_STATUS,
+														notify_hsdpa_status_cb, gprs);
+
+	client = ipc_device_get_client(gd->device);
+	ipc_client_gprs_get_capabilities(client, &caps);
+
+	ofono_gprs_set_cid_range(gprs, 1, caps.cid_max);
+
+	return 0;
+}
+
+static void samsungipc_gprs_remove(struct ofono_gprs *gprs)
+{
+	struct gprs_data *gd = ofono_gprs_get_data(gprs);
+
+	DBG("");
+
+	ipc_device_remove_watch(gd->device, gd->status_watch);
+
+	ofono_gprs_set_data(gprs, NULL);
+
+	g_free(gd);
+}
+
+static struct ofono_gprs_driver driver = {
+	.name			= "samsungipcmodem",
+	.probe			= samsungipc_gprs_probe,
+	.remove			= samsungipc_gprs_remove,
+	.attached_status	= samsungipc_attached_status,
+	.set_attached	= samsungipc_set_attached,
+};
+
+void samsungipc_gprs_init(void)
+{
+	ofono_gprs_driver_register(&driver);
+}
+
+void samsungipc_gprs_exit(void)
+{
+	ofono_gprs_driver_unregister(&driver);
+}
diff --git a/drivers/samsungipcmodem/samsungipcmodem.c b/drivers/samsungipcmodem/samsungipcmodem.c
index 72553a5..c99887d 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.c
+++ b/drivers/samsungipcmodem/samsungipcmodem.c
@@ -34,11 +34,13 @@ static int samsungipcmodem_init(void)
 	samsungipc_sim_init();
 	samsungipc_netreg_init();
 	samsungipc_voicecall_init();
+	samsungipc_gprs_init();
 	return 0;
 }
 
 static void samsungipcmodem_exit(void)
 {
+	samsungipc_gprs_exit();
 	samsungipc_voicecall_exit();
 	samsungipc_netreg_exit();
 	samsungipc_sim_exit();
diff --git a/drivers/samsungipcmodem/samsungipcmodem.h b/drivers/samsungipcmodem/samsungipcmodem.h
index 092effd..2ee5f43 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.h
+++ b/drivers/samsungipcmodem/samsungipcmodem.h
@@ -27,3 +27,5 @@ extern void samsungipc_netreg_init(void);
 extern void samsungipc_netreg_exit(void);
 extern void samsungipc_voicecall_init(void);
 extern void samsungipc_voicecall_exit(void);
+extern void samsungipc_gprs_init(void);
+extern void samsungipc_gprs_exit(void);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 10/11] samsungipcmodem: add gprs-context driver implementation
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (8 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 09/11] samsungipcmodem: add gprs " Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-18 18:18 ` [PATCH 11/11] samsungipc: Add initial implementation of the Samsung IPC modem plugin Simon Busch
  2012-09-19  9:49 ` [PATCH 00/11] Samsung IPC modem support Daniel Wagner
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am                               |    3 +-
 drivers/samsungipcmodem/gprs-context.c    |  311 +++++++++++++++++++++++++++++
 drivers/samsungipcmodem/samsungipcmodem.c |    2 +
 drivers/samsungipcmodem/samsungipcmodem.h |    2 +
 4 files changed, 317 insertions(+), 1 deletion(-)
 create mode 100644 drivers/samsungipcmodem/gprs-context.c

diff --git a/Makefile.am b/Makefile.am
index 1bfdf91..769f848 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -192,7 +192,8 @@ builtin_sources += \
 	drivers/samsungipcmodem/sim.c \
 	drivers/samsungipcmodem/network-registration.c \
 	drivers/samsungipcmodem/voicecall.c \
-	drivers/samsungipcmodem/gprs.c
+	drivers/samsungipcmodem/gprs.c \
+	drivers/samsungipcmodem/gprs-context.c
 builtin_cflags += @SAMSUNGIPC_CFLAGS@
 builtin_libadd += @SAMSUNGIPC_LIBS@
 endif
diff --git a/drivers/samsungipcmodem/gprs-context.c b/drivers/samsungipcmodem/gprs-context.c
new file mode 100644
index 0000000..aae1365
--- /dev/null
+++ b/drivers/samsungipcmodem/gprs-context.c
@@ -0,0 +1,311 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>. All rights reserved.
+ *
+ *  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
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs-context.h>
+
+#include <glib.h>
+
+#include "samsungipcmodem.h"
+#include "ipc.h"
+#include "util.h"
+
+#define IP_MAX_LENGTH	15
+
+struct gprs_context_data {
+	struct ipc_device *device;
+	unsigned int active_context;
+	unsigned int enabled;
+	char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
+	char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
+};
+
+static void notify_gprs_ip_configuration_cb(uint16_t cmd, void *data, uint16_t length,
+										void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_gprs_context_cb_t cb = cbd->cb;
+	struct ofono_gprs_context *gc = cbd->user;
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct ipc_gprs_ip_configuration *resp = data;
+	struct ipc_client *client;
+	char local[IP_MAX_LENGTH];
+	char dns1[IP_MAX_LENGTH];
+	char dns2[IP_MAX_LENGTH];
+	char gateway[IP_MAX_LENGTH];
+	char subnetmask[IP_MAX_LENGTH];
+	const char *dns[3];
+	char *interface;
+
+	snprintf(local, IP_MAX_LENGTH, "%i.%i.%i.%i", resp->ip[0], resp->ip[1],
+			 resp->ip[2], resp->ip[3]);
+	snprintf(dns1, IP_MAX_LENGTH, "%i.%i.%i.%i", resp->dns1[0], resp->dns1[1],
+			 resp->dns1[2], resp->dns1[3]);
+	snprintf(dns2, IP_MAX_LENGTH, "%i.%i.%i.%i", resp->dns2[0], resp->dns2[1],
+			 resp->dns2[2], resp->dns2[3]);
+	snprintf(local, IP_MAX_LENGTH, "%i.%i.%i.%i", resp->gateway[0], resp->gateway[1],
+			 resp->gateway[2], resp->gateway[3]);
+	snprintf(local, IP_MAX_LENGTH, "%i.%i.%i.%i", resp->subnet_mask[0], resp->subnet_mask[1],
+			 resp->subnet_mask[2], resp->subnet_mask[3]);
+
+	dns[0] = dns1;
+	dns[1] = dns2;
+	dns[2] = 0;
+
+	client = ipc_device_get_client(gcd->device);
+	interface = ipc_client_gprs_get_iface(client, gcd->active_context);
+
+	ofono_gprs_context_set_interface(gc, interface);
+	ofono_gprs_context_set_ipv4_address(gc, local, TRUE);
+	ofono_gprs_context_set_ipv4_netmask(gc, subnetmask);
+	ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
+	ofono_gprs_context_set_ipv4_gateway(gc, gateway);
+
+	gcd->enabled = 1;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+	g_free(cbd);
+	g_free(interface);
+}
+
+static void pdp_context_activate_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_gprs_context *gc = cbd->user;
+	ofono_gprs_context_cb_t cb = cbd->cb;
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+
+	if (error) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		gcd->active_context = 0;
+		g_free(cbd);
+		return;
+	}
+
+	ipc_device_add_notifcation_watch(gcd->device, IPC_GPRS_IP_CONFIGURATION,
+								notify_gprs_ip_configuration_cb, cbd);
+}
+
+static void define_pdp_context_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_gprs_context_cb_t cb = cbd->cb;
+	struct ofono_gprs_context *gc = cbd->user;
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct ipc_gen_phone_res *resp = data;
+	struct ipc_gprs_pdp_context_set *req;
+
+	if (error || ipc_gen_phone_res_check(resp) < 0)
+		goto error;
+
+	req = g_try_new0(struct ipc_gprs_pdp_context_set, 1);
+	if (!req)
+		goto error;
+
+	ipc_gprs_pdp_context_setup(req, 1, /* activate the context */
+					gcd->active_context, gcd->username, gcd->password);
+
+	if(ipc_device_enqueue_message(gcd->device, IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET,
+						req, sizeof(struct ipc_gprs_pdp_context_set),
+						pdp_context_activate_cb, cbd) > 0)
+		return;
+
+error:
+	gcd->active_context = 0;
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+	g_free(cbd);
+}
+
+static void samsungipc_gprs_activate_primary(struct ofono_gprs_context *gc,
+				const struct ofono_gprs_primary_context *ctx,
+				ofono_gprs_context_cb_t cb, void *data)
+{
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct ipc_gprs_define_pdp_context *req;
+	struct cb_data *cbd;
+
+	req = g_try_new0(struct ipc_gprs_define_pdp_context, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+	cbd->user = gc;
+
+	/* IPv6 support not implemented */
+	if (ctx->proto != OFONO_GPRS_PROTO_IP)
+		goto error;
+
+	DBG("cid %u", ctx->cid);
+
+	gcd->active_context = ctx->cid;
+	memcpy(gcd->username, ctx->username, sizeof(ctx->username));
+	memcpy(gcd->password, ctx->password, sizeof(ctx->password));
+
+	req->cid = ctx->cid;
+	req->enable = 1; /* enable the context */
+	strncpy((char*) req->apn, ctx->apn, 124);
+
+	if(ipc_device_enqueue_message(gcd->device, IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET,
+						req, sizeof(struct ipc_gprs_define_pdp_context),
+						define_pdp_context_cb, cbd) > 0)
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void pdp_context_deactivate_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct ipc_gen_phone_res *resp = data;
+	struct cb_data *cbd = user_data;
+	ofono_gprs_context_cb_t cb = cbd->cb;
+	struct gprs_context_data *gcd = cbd->user;
+
+	if (error || ipc_gen_phone_res_check(resp) < 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		goto done;
+	}
+
+	gcd->enabled = 0;
+	gcd->active_context = 0;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+done:
+	g_free(cbd);
+}
+
+static void samsungipc_gprs_deactivate_primary(struct ofono_gprs_context *gc,
+					unsigned int cid,
+					ofono_gprs_context_cb_t cb, void *data)
+{
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct ipc_gprs_pdp_context_set *req;
+	struct cb_data *cbd;
+
+	DBG("cid %u", cid);
+
+	req = g_try_new0(struct ipc_gprs_pdp_context_set, 1);
+	if (!req) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data);
+	cbd->user = gcd;
+
+	ipc_gprs_pdp_context_setup(req, 0, /* deactivate the context */
+					cid, NULL, NULL);
+
+	if(ipc_device_enqueue_message(gcd->device, IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET,
+						req, sizeof(struct ipc_gprs_pdp_context_set),
+						pdp_context_deactivate_cb, cbd) > 0)
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static void samsungipc_gprs_detach_shutdown(struct ofono_gprs_context *gc,
+					unsigned int cid)
+{
+	DBG("cid %u", cid);
+}
+
+static void notify_gprs_status_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct ofono_gprs_context *gc = user_data;
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct ipc_gprs_call_status *resp = data;
+
+	if (gcd->enabled &&
+		(resp->state == IPC_GPRS_STATE_NOT_ENABLED ||
+		 resp->state == IPC_GPRS_STATE_DISABLED)) {
+		ofono_gprs_context_deactivated(gc, gcd->active_context);
+	}
+}
+
+static int samsungipc_gprs_context_probe(struct ofono_gprs_context *gc,
+					unsigned int vendor, void *data)
+{
+	struct gprs_context_data *gcd;
+
+	DBG("");
+
+	gcd = g_try_new0(struct gprs_context_data, 1);
+	if (gcd == NULL)
+		return -ENOMEM;
+
+	gcd->device = data;
+	gcd->active_context = 0;
+	gcd->enabled = 0;
+
+	ofono_gprs_context_set_data(gc, gcd);
+
+	ipc_device_add_notifcation_watch(gcd->device, IPC_GPRS_CALL_STATUS,
+								notify_gprs_status_cb, gc);
+
+	return 0;
+}
+
+static void samsungipc_gprs_context_remove(struct ofono_gprs_context *gc)
+{
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+
+	DBG("");
+
+	ofono_gprs_context_set_data(gc, NULL);
+
+	g_free(gcd);
+}
+
+static struct ofono_gprs_context_driver driver = {
+	.name			= "samsungipcmodem",
+	.probe			= samsungipc_gprs_context_probe,
+	.remove			= samsungipc_gprs_context_remove,
+	.activate_primary	= samsungipc_gprs_activate_primary,
+	.deactivate_primary	= samsungipc_gprs_deactivate_primary,
+	.detach_shutdown	= samsungipc_gprs_detach_shutdown,
+};
+
+void samsungipc_gprs_context_init(void)
+{
+	ofono_gprs_context_driver_register(&driver);
+}
+
+void samsungipc_gprs_context_exit(void)
+{
+	ofono_gprs_context_driver_unregister(&driver);
+}
diff --git a/drivers/samsungipcmodem/samsungipcmodem.c b/drivers/samsungipcmodem/samsungipcmodem.c
index c99887d..df55cf5 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.c
+++ b/drivers/samsungipcmodem/samsungipcmodem.c
@@ -35,11 +35,13 @@ static int samsungipcmodem_init(void)
 	samsungipc_netreg_init();
 	samsungipc_voicecall_init();
 	samsungipc_gprs_init();
+	samsungipc_gprs_context_exit();
 	return 0;
 }
 
 static void samsungipcmodem_exit(void)
 {
+	samsungipc_gprs_context_exit();
 	samsungipc_gprs_exit();
 	samsungipc_voicecall_exit();
 	samsungipc_netreg_exit();
diff --git a/drivers/samsungipcmodem/samsungipcmodem.h b/drivers/samsungipcmodem/samsungipcmodem.h
index 2ee5f43..fe1f64b 100644
--- a/drivers/samsungipcmodem/samsungipcmodem.h
+++ b/drivers/samsungipcmodem/samsungipcmodem.h
@@ -29,3 +29,5 @@ extern void samsungipc_voicecall_init(void);
 extern void samsungipc_voicecall_exit(void);
 extern void samsungipc_gprs_init(void);
 extern void samsungipc_gprs_exit(void);
+extern void samsungipc_gprs_context_init(void);
+extern void samsungipc_gprs_context_exit(void);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 11/11] samsungipc: Add initial implementation of the Samsung IPC modem plugin
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (9 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 10/11] samsungipcmodem: add gprs-context " Simon Busch
@ 2012-09-18 18:18 ` Simon Busch
  2012-09-19  9:49 ` [PATCH 00/11] Samsung IPC modem support Daniel Wagner
  11 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-18 18:18 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am          |    3 +
 plugins/samsungipc.c |  414 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 417 insertions(+)
 create mode 100644 plugins/samsungipc.c

diff --git a/Makefile.am b/Makefile.am
index 769f848..ba2e51e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -392,6 +392,9 @@ builtin_sources += plugins/stemgr.c
 if SAMSUNGIPCMODEM
 builtin_modules += samsungmgr
 builtin_sources += plugins/samsungmgr.c
+
+builtin_modules += samsungipc
+builtin_sources += plugins/samsungipc.c
 endif
 
 builtin_modules += caif
diff --git a/plugins/samsungipc.c b/plugins/samsungipc.c
new file mode 100644
index 0000000..98d13eb
--- /dev/null
+++ b/plugins/samsungipc.c
@@ -0,0 +1,414 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2012 Simon Busch <morphis@gravedo.de>
+ *
+ *  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 <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+#include <glib.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/message-waiting.h>
+#include <ofono/netreg.h>
+#include <ofono/sim.h>
+#include <ofono/phonebook.h>
+#include <ofono/voicecall.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/sms.h>
+
+#include "drivers/samsungipcmodem/ipc.h"
+#include "drivers/samsungipcmodem/util.h"
+
+#include <samsung-ipc.h>
+
+struct samsungipc_data {
+	struct ipc_device *device;
+	struct ipc_client *client;
+	ofono_bool_t in_forwarding_mode;
+	uint16_t state;
+	guint power_state_watch;
+};
+
+static void samsungipc_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	ofono_info("%s%s", prefix, str);
+}
+
+static int samsungipc_probe(struct ofono_modem *modem)
+{
+	struct samsungipc_data *data;
+
+	DBG("%p", modem);
+
+	data = g_try_new0(struct samsungipc_data, 1);
+	if (data == NULL)
+		return -ENOMEM;
+
+	data->in_forwarding_mode = FALSE;
+
+	ofono_modem_set_data(modem, data);
+
+	return 0;
+}
+
+static void samsungipc_remove(struct ofono_modem *modem)
+{
+	struct samsungipc_data *data = ofono_modem_get_data(modem);
+
+	DBG("%p", modem);
+
+	ofono_modem_set_data(modem, NULL);
+
+	g_free(data);
+}
+
+static int connect_socket(const char *address, int port)
+{
+	struct sockaddr_in addr;
+	int sk;
+	int err;
+
+	sk = socket(PF_INET, SOCK_STREAM, 0);
+	if (sk < 0)
+		return -EINVAL;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = inet_addr(address);
+	addr.sin_port = htons(port);
+
+	err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0) {
+		close(sk);
+		return -errno;
+	}
+
+	return sk;
+}
+
+static int modem_data_read(void *buf, unsigned int size, void *user_data)
+{
+	struct samsungipc_data *data = user_data;
+	int ret, fd;
+
+	fd = ipc_device_get_fd(data->device);
+	if (fd < 0)
+		return -1;
+
+	ret = read(fd, buf, size);
+	if (ret < 0)
+		return -1;
+
+	return ret;
+}
+
+static int modem_data_write(void *buf, unsigned int size, void *user_data)
+{
+	struct samsungipc_data *data = user_data;
+	int ret, fd;
+
+	fd = ipc_device_get_fd(data->device);
+	if (fd < 0)
+		return -1;
+
+	ret = write(fd, buf, size);
+	if (ret < 0)
+		return -1;
+
+	return ret;
+}
+
+static void retrieve_power_state_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct ofono_modem *modem = user_data;
+	struct samsungipc_data *ipcdata = ofono_modem_get_data(modem);
+	uint16_t state;
+
+	if (error) {
+		ofono_error("Received error instead of power state response");
+		return;
+	}
+
+	state = IPC_PWR_R(*((uint16_t*) data));
+
+	switch (state) {
+	case IPC_PWR_R(IPC_PWR_PHONE_STATE_NORMAL):
+		ofono_error("Modem is already in NORMAL power state; thats wrong!");
+		// FIXME shutdown everything here or switch to LPM/perform a modem reset?
+		break;
+	case IPC_PWR_R(IPC_PWR_PHONE_STATE_LPM):
+		ofono_modem_set_powered(modem, TRUE);
+		ipcdata->state = IPC_PWR_PHONE_STATE_LPM;
+		break;
+	}
+}
+
+static void log_handler(const char *message, void *user_data)
+{
+	ofono_debug("IPC: %s", message);
+}
+
+static int samsungipc_enable(struct ofono_modem *modem)
+{
+	struct samsungipc_data *data = ofono_modem_get_data(modem);
+	const char *address;
+	int port, fd;
+
+	DBG("%p", modem);
+
+	data->client = ipc_client_new(IPC_CLIENT_TYPE_FMT);
+	if (getenv("OFONO_IPC_DEBUG"))
+		ipc_client_set_log_handler(data->client, log_handler, data);
+
+	/* if address and port are set we are using a remote device */
+	address = ofono_modem_get_string(modem, "Address");
+	if (address != NULL) {
+		port = ofono_modem_get_integer(modem, "Port");
+		if (port < 0)
+			return -EINVAL;
+
+		data->in_forwarding_mode = TRUE;
+
+		fd = connect_socket(address, port);
+		if (fd < 0)
+			return fd;
+
+		ipc_client_set_io_handlers(data->client, modem_data_read, data,
+							modem_data_write, data);
+
+		ipc_device_set_close_on_unref(data->device, true);
+	}
+	else {
+		ipc_client_create_handlers_common_data(data->client);
+		ipc_client_open(data->client);
+		fd = ipc_client_get_handlers_common_data_fd(data->client);
+
+		if (fd < 0) {
+			ipc_client_close(data->client);
+			ipc_client_destroy_handlers_common_data(data->client);
+			return fd;
+		}
+	}
+
+	data->device = ipc_device_new(fd, data->client);
+	ipc_device_set_debug(data->device, samsungipc_debug, "IPC: ");
+
+	ipc_device_enqueue_message(data->device, IPC_PWR_PHONE_STATE, IPC_TYPE_GET,
+						NULL, 0, retrieve_power_state_cb, modem);
+
+	return -EINPROGRESS;
+}
+
+static int samsungipc_disable(struct ofono_modem *modem)
+{
+	struct samsungipc_data *data = ofono_modem_get_data(modem);
+
+	DBG("%p", modem);
+
+	ipc_client_close(data->client);
+
+	if (data->in_forwarding_mode)
+		ipc_client_destroy_handlers_common_data(data->client);
+
+	ipc_device_unref(data->device);
+
+	return 0;
+}
+
+static void samsungipc_pre_sim(struct ofono_modem *modem)
+{
+	struct samsungipc_data *data = ofono_modem_get_data(modem);
+
+	DBG("%p", modem);
+
+	ofono_devinfo_create(modem, 0, "samsungipcmodem", data->device);
+	ofono_sim_create(modem, 0, "samsungipcmodem", data->device);
+}
+
+static void samsungipc_post_sim(struct ofono_modem *modem)
+{
+	DBG("%p", modem);
+}
+
+static void notify_power_state_cb(uint16_t cmd, void *data, uint16_t length, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct samsungipc_data *sid = cbd->user;
+	ofono_modem_online_cb_t cb = cbd->cb;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+	ipc_device_remove_watch(sid->device, sid->power_state_watch);
+
+	g_free(cbd);
+}
+
+static void set_device_rf_power_state_cb(uint16_t cmd, void *data, uint16_t length, uint8_t error, void *user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_modem_online_cb_t cb = cbd->cb;
+	struct samsungipc_data *sid = cbd->user;
+	struct ipc_gen_phone_res *resp = data;
+
+	if (error || ipc_gen_phone_res_check(resp) < 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+		return;
+	}
+
+	sid->power_state_watch = ipc_device_add_notifcation_watch(sid->device, IPC_PWR_PHONE_STATE,
+														notify_power_state_cb, cbd);
+}
+
+static void set_device_rf_power_state(struct ofono_modem *modem, uint16_t state, struct cb_data *cbd)
+{
+	struct samsungipc_data *sid = ofono_modem_get_data(modem);
+	uint8_t *msg;
+	ofono_modem_online_cb_t cb = cbd->cb;
+
+	msg = g_try_new0(uint8_t, 2);
+	if (!msg)
+		return;
+
+	memcpy(msg, &state, sizeof(uint16_t));
+
+	switch (state) {
+	case IPC_PWR_PHONE_STATE_NORMAL:
+		ipc_device_enqueue_message(sid->device, IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, msg, 2,
+							set_device_rf_power_state_cb, cbd);
+
+		ofono_debug("Done sending power state change to NORMAL level");
+
+		break;
+	case IPC_PWR_PHONE_STATE_LPM:
+		/* We will not get any response for this request! */
+		ipc_device_enqueue_message(sid->device, IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, msg, 2,
+							NULL, NULL);
+
+		ofono_debug("Done sending power state change to LPM level");
+
+		/* FIXME maybe retrieving power state from modem to make sure it's set? */
+
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		g_free(cbd);
+
+		break;
+	default:
+		/* Not supported power state */
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+
+		break;
+	}
+}
+
+static void samsungipc_set_online(struct ofono_modem *modem, ofono_bool_t online,
+							ofono_modem_online_cb_t cb, void *user_data)
+{
+	struct samsungipc_data *sid = ofono_modem_get_data(modem);
+	struct cb_data *cbd;
+	uint16_t state;
+
+	state = online ? IPC_PWR_PHONE_STATE_NORMAL : IPC_PWR_PHONE_STATE_LPM;
+
+	cbd = cb_data_new(cb, user_data);
+	cbd->user = sid;
+
+	set_device_rf_power_state(modem, state, cbd);
+}
+
+static void samsungipc_post_online(struct ofono_modem *modem)
+{
+	struct samsungipc_data *data = ofono_modem_get_data(modem);
+	struct ofono_gprs *gprs;
+	struct ofono_gprs_context *gc;
+
+	DBG("%p", modem);
+
+	ofono_netreg_create(modem, 0, "samsungipcmodem", data->device);
+	ofono_voicecall_create(modem, 0, "samsungipcmodem", data->device);
+	gprs = ofono_gprs_create(modem, 0, "samsungipcmodem", data->device);
+	gc = ofono_gprs_context_create(modem, 0, "samsungipcmodem", data->device);
+
+	if (gprs && gc)
+		ofono_gprs_add_context(gprs, gc);
+}
+
+static struct ofono_modem_driver samsungipc_driver = {
+	.name		= "samsungipc",
+	.probe		= samsungipc_probe,
+	.remove		= samsungipc_remove,
+	.enable		= samsungipc_enable,
+	.disable	= samsungipc_disable,
+	.pre_sim	= samsungipc_pre_sim,
+	.post_sim	= samsungipc_post_sim,
+	.set_online	= samsungipc_set_online,
+	.post_online	= samsungipc_post_online,
+};
+
+static int samsungipc_init(void)
+{
+	int err;
+	char *remote;
+	struct ofono_modem *modem;
+
+	err = ofono_modem_driver_register(&samsungipc_driver);
+	if (err < 0)
+		return err;
+
+	remote = getenv("OFONO_SAMSUNGIPC_REMOTE");
+	if (remote != NULL) {
+		modem = ofono_modem_create(NULL, "samsungipc");
+		if (modem == NULL)
+			return -1;
+
+		ofono_modem_set_string(modem, "Address", remote);
+		ofono_modem_set_integer(modem, "Port", 3001);
+
+		ofono_modem_register(modem);
+	}
+
+	return 0;
+}
+
+static void samsungipc_exit(void)
+{
+	ofono_modem_driver_unregister(&samsungipc_driver);
+}
+
+OFONO_PLUGIN_DEFINE(samsungipc, "Samsung IPC driver", VERSION,
+		OFONO_PLUGIN_PRIORITY_DEFAULT, samsungipc_init, samsungipc_exit)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 00/11] Samsung IPC modem support
  2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
                   ` (10 preceding siblings ...)
  2012-09-18 18:18 ` [PATCH 11/11] samsungipc: Add initial implementation of the Samsung IPC modem plugin Simon Busch
@ 2012-09-19  9:49 ` Daniel Wagner
  2012-09-19 19:16   ` Simon Busch
  11 siblings, 1 reply; 14+ messages in thread
From: Daniel Wagner @ 2012-09-19  9:49 UTC (permalink / raw)
  To: ofono

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

Hi Simon,


On 18.09.2012 20:18, Simon Busch wrote:
> Heyho,
>
> the following patch series adds support for the Samsung IPC protocol which is implemented
> in an external library called libsamsung-ipc (see [0]). The library contains the
> implementation of the protocol used in most Samsung mobile handsets. As of right now the
> implementation contains drivers for the devinfo, sim, voicecall, gprs and gprs-context
> subsystems. Implementation for other subsystems like sms will follow.


The COPYING file from the libsamsung-ipc indicates that it is released 
under GPLv3. oFono is pure GPLv2. I fear this is a show stopper.

cheers,
daniel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 00/11] Samsung IPC modem support
  2012-09-19  9:49 ` [PATCH 00/11] Samsung IPC modem support Daniel Wagner
@ 2012-09-19 19:16   ` Simon Busch
  0 siblings, 0 replies; 14+ messages in thread
From: Simon Busch @ 2012-09-19 19:16 UTC (permalink / raw)
  To: ofono

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

Am 19.09.2012 11:49, schrieb Daniel Wagner:
> Hi Simon,
> 
> 
> On 18.09.2012 20:18, Simon Busch wrote:
>> Heyho,
>>
>> the following patch series adds support for the Samsung IPC protocol
>> which is implemented
>> in an external library called libsamsung-ipc (see [0]). The library
>> contains the
>> implementation of the protocol used in most Samsung mobile handsets.
>> As of right now the
>> implementation contains drivers for the devinfo, sim, voicecall, gprs
>> and gprs-context
>> subsystems. Implementation for other subsystems like sms will follow.
> 
> 
> The COPYING file from the libsamsung-ipc indicates that it is released
> under GPLv3. oFono is pure GPLv2. I fear this is a show stopper.

Thats something that will change in the near future. Good thing I am the
author of libsamsung-ipc too :)

regards,
Simon

-- 
Simon Busch - http://mm.gravedo.de/blog/

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-09-19 19:16 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-18 18:18 [PATCH 00/11] Samsung IPC modem support Simon Busch
2012-09-18 18:18 ` [PATCH 01/11] build: Add skeleton for Samsung IPC modem driver Simon Busch
2012-09-18 18:18 ` [PATCH 02/11] build: add dependency for samsung-ipc library Simon Busch
2012-09-18 18:18 ` [PATCH 03/11] samsungmgr: plugin for powering up samsung related modems via an additional daemon Simon Busch
2012-09-18 18:18 ` [PATCH 04/11] samsungipcmodem: implement the transport layer for the IPC protocol Simon Busch
2012-09-18 18:18 ` [PATCH 05/11] samsungipcmodem: add devinfo driver implementation Simon Busch
2012-09-18 18:18 ` [PATCH 06/11] samsungipcmodem: add sim " Simon Busch
2012-09-18 18:18 ` [PATCH 07/11] samsungipcmodem: add network registration " Simon Busch
2012-09-18 18:18 ` [PATCH 08/11] samsungipcmodem: add voicecall " Simon Busch
2012-09-18 18:18 ` [PATCH 09/11] samsungipcmodem: add gprs " Simon Busch
2012-09-18 18:18 ` [PATCH 10/11] samsungipcmodem: add gprs-context " Simon Busch
2012-09-18 18:18 ` [PATCH 11/11] samsungipc: Add initial implementation of the Samsung IPC modem plugin Simon Busch
2012-09-19  9:49 ` [PATCH 00/11] Samsung IPC modem support Daniel Wagner
2012-09-19 19:16   ` Simon Busch

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.