All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] Rilmodem driver
@ 2015-10-13 16:07 Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 1/9] src: make bearer/operator enums public Alfonso Sanchez-Beato
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

This patch series implements the rilmodem driver, which uses Android's
radio interface layer (RIL, part of the Android HAL) to interact with
the modem.

The driver is almost feature-complete with some exceptions, being CBS
and SAT the most prominent.

Besides the driver, the patches include the following plugins:
* ril.c: Plugin for Android modems
* infineon.c: Plugin for infineon modems, which are a variant of the ril
  modem
* rildev: plugin that creates ril-type modems using environment
  variables

Finally, the patches contain some minor modifications of the core code
to export a couple of enumerations used by the driver.

The driver is used by Ubuntu for Phones and Sailfish and is quite stable
at the moment.

Alfonso Sanchez-Beato (5):
  include: Add definitions for phone number types
  infineon: Definitions for infineon modem
  infineon: Plugin for infineon modems
  rildev: plugin that creates ril-type modems
  build: Add rilmodem to the build

Tony Espy (4):
  src: make bearer/operator enums public
  gril: Library to communicate with rild
  rilmodem: driver for Android modems
  ril: Plugin for Android modems

 Makefile.am                                |   44 +-
 configure.ac                               |    5 +
 drivers/infineonmodem/infineon_constants.h |   77 ++
 drivers/rilmodem/call-barring.c            |  245 +++++
 drivers/rilmodem/call-forwarding.c         |  327 +++++++
 drivers/rilmodem/call-settings.c           |  286 ++++++
 drivers/rilmodem/call-volume.c             |  182 ++++
 drivers/rilmodem/devinfo.c                 |  218 +++++
 drivers/rilmodem/gprs-context.c            |  585 +++++++++++
 drivers/rilmodem/gprs.c                    |  487 ++++++++++
 drivers/rilmodem/gprs.h                    |   46 +
 drivers/rilmodem/network-registration.c    |  566 +++++++++++
 drivers/rilmodem/phonebook.c               | 1055 ++++++++++++++++++++
 drivers/rilmodem/radio-settings.c          |  300 ++++++
 drivers/rilmodem/radio-settings.h          |   47 +
 drivers/rilmodem/rilmodem.c                |   78 ++
 drivers/rilmodem/rilmodem.h                |   71 ++
 drivers/rilmodem/rilutil.c                 |  194 ++++
 drivers/rilmodem/rilutil.h                 |  165 ++++
 drivers/rilmodem/sim.c                     | 1200 +++++++++++++++++++++++
 drivers/rilmodem/sms.c                     |  315 ++++++
 drivers/rilmodem/ussd.c                    |  264 +++++
 drivers/rilmodem/vendor.h                  |   32 +
 drivers/rilmodem/voicecall.c               |  824 ++++++++++++++++
 drivers/rilmodem/voicecall.h               |   71 ++
 gril/gfunc.h                               |   42 +
 gril/gril.c                                | 1295 +++++++++++++++++++++++++
 gril/gril.h                                |  172 ++++
 gril/grilio.c                              |  399 ++++++++
 gril/grilio.h                              |   69 ++
 gril/grilreply.c                           | 1450 ++++++++++++++++++++++++++++
 gril/grilreply.h                           |  185 ++++
 gril/grilrequest.c                         | 1161 ++++++++++++++++++++++
 gril/grilrequest.h                         |  293 ++++++
 gril/grilunsol.c                           |  638 ++++++++++++
 gril/grilunsol.h                           |   99 ++
 gril/grilutil.c                            |  830 ++++++++++++++++
 gril/grilutil.h                            |   63 ++
 gril/parcel.c                              |  293 ++++++
 gril/parcel.h                              |   53 +
 gril/ril_constants.h                       |  429 ++++++++
 include/types.h                            |    6 +
 plugins/infineon.c                         |   77 ++
 plugins/ril.c                              |  461 +++++++++
 plugins/ril.h                              |   30 +
 plugins/rildev.c                           |  133 +++
 src/common.h                               |   20 +
 src/gprs.c                                 |   12 -
 src/network.c                              |    8 -
 49 files changed, 15881 insertions(+), 21 deletions(-)
 create mode 100644 drivers/infineonmodem/infineon_constants.h
 create mode 100644 drivers/rilmodem/call-barring.c
 create mode 100644 drivers/rilmodem/call-forwarding.c
 create mode 100644 drivers/rilmodem/call-settings.c
 create mode 100644 drivers/rilmodem/call-volume.c
 create mode 100644 drivers/rilmodem/devinfo.c
 create mode 100644 drivers/rilmodem/gprs-context.c
 create mode 100644 drivers/rilmodem/gprs.c
 create mode 100644 drivers/rilmodem/gprs.h
 create mode 100644 drivers/rilmodem/network-registration.c
 create mode 100644 drivers/rilmodem/phonebook.c
 create mode 100644 drivers/rilmodem/radio-settings.c
 create mode 100644 drivers/rilmodem/radio-settings.h
 create mode 100644 drivers/rilmodem/rilmodem.c
 create mode 100644 drivers/rilmodem/rilmodem.h
 create mode 100644 drivers/rilmodem/rilutil.c
 create mode 100644 drivers/rilmodem/rilutil.h
 create mode 100644 drivers/rilmodem/sim.c
 create mode 100644 drivers/rilmodem/sms.c
 create mode 100644 drivers/rilmodem/ussd.c
 create mode 100644 drivers/rilmodem/vendor.h
 create mode 100644 drivers/rilmodem/voicecall.c
 create mode 100644 drivers/rilmodem/voicecall.h
 create mode 100644 gril/gfunc.h
 create mode 100644 gril/gril.c
 create mode 100644 gril/gril.h
 create mode 100644 gril/grilio.c
 create mode 100644 gril/grilio.h
 create mode 100644 gril/grilreply.c
 create mode 100644 gril/grilreply.h
 create mode 100644 gril/grilrequest.c
 create mode 100644 gril/grilrequest.h
 create mode 100644 gril/grilunsol.c
 create mode 100644 gril/grilunsol.h
 create mode 100644 gril/grilutil.c
 create mode 100644 gril/grilutil.h
 create mode 100644 gril/parcel.c
 create mode 100644 gril/parcel.h
 create mode 100644 gril/ril_constants.h
 create mode 100644 plugins/infineon.c
 create mode 100644 plugins/ril.c
 create mode 100644 plugins/ril.h
 create mode 100644 plugins/rildev.c

-- 
2.1.4


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

* [PATCH 1/9] src: make bearer/operator enums public
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 2/9] include: Add definitions for phone number types Alfonso Sanchez-Beato
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

From: Tony Espy <espy@canonical.com>

Move enums for operator_status and packet_bearer to common.h to avoid
duplication in drivers.
---
 src/common.h  | 20 ++++++++++++++++++++
 src/gprs.c    | 12 ------------
 src/network.c |  8 --------
 3 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/src/common.h b/src/common.h
index eb006a7..ef4c58d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -41,6 +41,14 @@ enum network_registration_status {
 	NETWORK_REGISTRATION_STATUS_ROAMING =		5,
 };
 
+/* 27.007 Section 7.3 <stat> */
+enum operator_status {
+	OPERATOR_STATUS_UNKNOWN =	0,
+	OPERATOR_STATUS_AVAILABLE =	1,
+	OPERATOR_STATUS_CURRENT =	2,
+	OPERATOR_STATUS_FORBIDDEN =	3,
+};
+
 /* 27.007 Section 7.6 */
 enum clip_validity {
 	CLIP_VALIDITY_VALID =		0,
@@ -48,6 +56,18 @@ enum clip_validity {
 	CLIP_VALIDITY_NOT_AVAILABLE =	2,
 };
 
+/* 27.007 Section 7.29 */
+enum packet_bearer {
+	PACKET_BEARER_NONE =		0,
+	PACKET_BEARER_GPRS =		1,
+	PACKET_BEARER_EGPRS =		2,
+	PACKET_BEARER_UMTS =		3,
+	PACKET_BEARER_HSUPA =		4,
+	PACKET_BEARER_HSDPA =		5,
+	PACKET_BEARER_HSUPA_HSDPA =	6,
+	PACKET_BEARER_EPS =		7,
+};
+
 /* 27.007 Section 7.30 */
 enum cnap_validity {
 	CNAP_VALIDITY_VALID =		0,
diff --git a/src/gprs.c b/src/gprs.c
index ca24327..344915c 100644
--- a/src/gprs.c
+++ b/src/gprs.c
@@ -58,18 +58,6 @@
 #define MAX_CONTEXTS 256
 #define SUSPEND_TIMEOUT 8
 
-/* 27.007 Section 7.29 */
-enum packet_bearer {
-	PACKET_BEARER_NONE =		0,
-	PACKET_BEARER_GPRS =		1,
-	PACKET_BEARER_EGPRS =		2,
-	PACKET_BEARER_UMTS =		3,
-	PACKET_BEARER_HSUPA =		4,
-	PACKET_BEARER_HSDPA =		5,
-	PACKET_BEARER_HSUPA_HSDPA =	6,
-	PACKET_BEARER_EPS =		7,
-};
-
 struct ofono_gprs {
 	GSList *contexts;
 	ofono_bool_t attached;
diff --git a/src/network.c b/src/network.c
index d1bfca6..1dddcac 100644
--- a/src/network.c
+++ b/src/network.c
@@ -50,14 +50,6 @@ enum network_registration_mode {
 	NETWORK_REGISTRATION_MODE_AUTO_ONLY =	5, /* Out of range of 27.007 */
 };
 
-/* 27.007 Section 7.3 <stat> */
-enum operator_status {
-	OPERATOR_STATUS_UNKNOWN =	0,
-	OPERATOR_STATUS_AVAILABLE =	1,
-	OPERATOR_STATUS_CURRENT =	2,
-	OPERATOR_STATUS_FORBIDDEN =	3,
-};
-
 struct ofono_netreg {
 	int status;
 	int location;
-- 
2.1.4


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

* [PATCH 2/9] include: Add definitions for phone number types
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 1/9] src: make bearer/operator enums public Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 3/9] gril: Library to communicate with rild Alfonso Sanchez-Beato
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

---
 include/types.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/types.h b/include/types.h
index 9a7dfd9..2c64b20 100644
--- a/include/types.h
+++ b/include/types.h
@@ -73,6 +73,12 @@ struct ofono_error {
 #define OFONO_MAX_PHONE_NUMBER_LENGTH 80
 #define OFONO_MAX_CALLER_NAME_LENGTH 80
 
+/* Number types, 3GPP TS 24.008 subclause 10.5.4.7, octect 3 */
+/* Unknown, ISDN numbering plan */
+#define OFONO_NUMBER_TYPE_UNKNOWN 129
+/* International, ISDN numbering plan */
+#define OFONO_NUMBER_TYPE_INTERNATIONAL 145
+
 struct ofono_phone_number {
 	char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 1];
 	int type;
-- 
2.1.4


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

* [PATCH 3/9] gril: Library to communicate with rild
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 1/9] src: make bearer/operator enums public Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 2/9] include: Add definitions for phone number types Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 4/9] rilmodem: driver for Android modems Alfonso Sanchez-Beato
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

From: Tony Espy <espy@canonical.com>

gril is a library used to communicate with rild, the Android telephony
daemon. Communication happens using a named socket over which binder
parcels are transmitted.

Co-authored-by: Tony Espy <espy@canonical.com>
Co-authored-by: Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
Co-authored-by: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
Co-authored-by: Mikko Hurskainen <mikko.hurskainen@nomovok.com>
Co-authored-by: You-Sheng Yang <vicamo.yang@canonical.com>
Co-authored-by: Ratchanan Srirattanamet <peathot@hotmail.com>
---
 gril/gfunc.h         |   42 ++
 gril/gril.c          | 1295 ++++++++++++++++++++++++++++++++++++++++++++
 gril/gril.h          |  172 ++++++
 gril/grilio.c        |  399 ++++++++++++++
 gril/grilio.h        |   69 +++
 gril/grilreply.c     | 1450 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gril/grilreply.h     |  185 +++++++
 gril/grilrequest.c   | 1161 ++++++++++++++++++++++++++++++++++++++++
 gril/grilrequest.h   |  293 ++++++++++
 gril/grilunsol.c     |  638 ++++++++++++++++++++++
 gril/grilunsol.h     |   99 ++++
 gril/grilutil.c      |  830 +++++++++++++++++++++++++++++
 gril/grilutil.h      |   63 +++
 gril/parcel.c        |  293 ++++++++++
 gril/parcel.h        |   53 ++
 gril/ril_constants.h |  429 +++++++++++++++
 16 files changed, 7471 insertions(+)
 create mode 100644 gril/gfunc.h
 create mode 100644 gril/gril.c
 create mode 100644 gril/gril.h
 create mode 100644 gril/grilio.c
 create mode 100644 gril/grilio.h
 create mode 100644 gril/grilreply.c
 create mode 100644 gril/grilreply.h
 create mode 100644 gril/grilrequest.c
 create mode 100644 gril/grilrequest.h
 create mode 100644 gril/grilunsol.c
 create mode 100644 gril/grilunsol.h
 create mode 100644 gril/grilutil.c
 create mode 100644 gril/grilutil.h
 create mode 100644 gril/parcel.c
 create mode 100644 gril/parcel.h
 create mode 100644 gril/ril_constants.h

diff --git a/gril/gfunc.h b/gril/gfunc.h
new file mode 100644
index 0000000..5e13b7d
--- /dev/null
+++ b/gril/gfunc.h
@@ -0,0 +1,42 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GFUNC_H
+#define __GFUNC_H
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*GRilDisconnectFunc)(gpointer user_data);
+typedef void (*GRilReceiveFunc)(const unsigned char *data, gsize size,
+							gpointer user_data);
+typedef void (*GRilDebugFunc)(const char *str, gpointer user_data);
+typedef void (*GRilSuspendFunc)(gpointer user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GFUNC_H */
diff --git a/gril/gril.c b/gril/gril.c
new file mode 100644
index 0000000..fb6c1a9
--- /dev/null
+++ b/gril/gril.c
@@ -0,0 +1,1295 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2013 Canonical Ltd.
+ *  Copyright (C) 2013 Jolla Ltd.
+ *
+ *  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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "log.h"
+#include "ringbuffer.h"
+#include "gril.h"
+#include "grilutil.h"
+
+#define RIL_TRACE(ril, fmt, arg...) do {	\
+	if (ril->trace == TRUE)			\
+		ofono_debug(fmt, ## arg);	\
+} while (0)
+
+#define COMMAND_FLAG_EXPECT_PDU			0x1
+#define COMMAND_FLAG_EXPECT_SHORT_PROMPT	0x2
+
+#define	RADIO_GID 1001
+#define	RADIO_UID 1001
+
+struct ril_request {
+	gchar *data;
+	guint data_len;
+	gint req;
+	gint id;
+	guint gid;
+	GRilResponseFunc callback;
+	gpointer user_data;
+	GDestroyNotify notify;
+};
+
+struct ril_notify_node {
+	guint id;
+	guint gid;
+	GRilNotifyFunc callback;
+	gpointer user_data;
+	gboolean destroyed;
+};
+
+typedef gboolean (*node_remove_func)(struct ril_notify_node *node,
+					gpointer user_data);
+
+struct ril_notify {
+	GSList *nodes;
+};
+
+struct ril_s {
+	gint ref_count;				/* Ref count */
+	gint next_cmd_id;			/* Next command id */
+	guint next_notify_id;			/* Next notify id */
+	guint next_gid;				/* Next group id */
+	GRilIO *io;				/* GRil IO */
+	GQueue *command_queue;			/* Command queue */
+	GQueue *out_queue;			/* Commands sent/been sent */
+	guint req_bytes_written;		/* bytes written from req */
+	GHashTable *notify_list;		/* List of notification reg */
+	GRilDisconnectFunc user_disconnect;	/* user disconnect func */
+	gpointer user_disconnect_data;		/* user disconnect data */
+	guint read_so_far;			/* Number of bytes processed */
+	gboolean suspended;			/* Are we suspended? */
+	GRilDebugFunc debugf;			/* debugging output function */
+	gpointer debug_data;			/* Data to pass to debug func */
+	gboolean debug;
+	gboolean trace;
+	gint timeout_source;
+	gboolean destroyed;			/* Re-entrancy guard */
+	gboolean in_read_handler;		/* Re-entrancy guard */
+	gboolean in_notify;
+	enum ofono_ril_vendor vendor;
+	int slot;
+	GRilMsgIdToStrFunc req_to_string;
+	GRilMsgIdToStrFunc unsol_to_string;
+};
+
+struct _GRil {
+	gint ref_count;
+	struct ril_s *parent;
+	guint group;
+};
+
+struct req_hdr {
+	/* Warning: length is stored in network order */
+	uint32_t length;
+	uint32_t reqid;
+	uint32_t serial;
+};
+
+#define RIL_PRINT_BUF_SIZE 8096
+char print_buf[RIL_PRINT_BUF_SIZE] __attribute__((used));
+
+static void ril_wakeup_writer(struct ril_s *ril);
+
+static const char *request_id_to_string(struct ril_s *ril, int req)
+{
+	const char *str = NULL;
+
+	if (ril->req_to_string)
+		str = ril->req_to_string(req);
+
+	if (str == NULL)
+		str = ril_request_id_to_string(req);
+
+	return str;
+}
+
+static const char *unsol_request_to_string(struct ril_s *ril, int req)
+{
+	const char *str = NULL;
+
+	if (ril->unsol_to_string)
+		str = ril->unsol_to_string(req);
+
+	if (str == NULL)
+		str = ril_unsol_request_to_string(req);
+
+	return str;
+}
+
+static void ril_notify_node_destroy(gpointer data, gpointer user_data)
+{
+	struct ril_notify_node *node = data;
+	g_free(node);
+}
+
+static void ril_notify_destroy(gpointer user_data)
+{
+	struct ril_notify *notify = user_data;
+
+	g_slist_foreach(notify->nodes, ril_notify_node_destroy, NULL);
+	g_slist_free(notify->nodes);
+	g_free(notify);
+}
+
+static gint ril_notify_node_compare_by_id(gconstpointer a, gconstpointer b)
+{
+	const struct ril_notify_node *node = a;
+	guint id = GPOINTER_TO_UINT(b);
+
+	if (node->id < id)
+		return -1;
+
+	if (node->id > id)
+		return 1;
+
+	return 0;
+}
+
+static gboolean ril_unregister_all(struct ril_s *ril,
+					gboolean mark_only,
+					node_remove_func func,
+					gpointer userdata)
+{
+	GHashTableIter iter;
+	struct ril_notify *notify;
+	struct ril_notify_node *node;
+	gpointer key, value;
+	GSList *p;
+	GSList *c;
+	GSList *t;
+
+	if (ril->notify_list == NULL)
+		return FALSE;
+
+	g_hash_table_iter_init(&iter, ril->notify_list);
+
+	while (g_hash_table_iter_next(&iter, &key, &value)) {
+		notify = value;
+
+		p = NULL;
+		c = notify->nodes;
+
+		while (c) {
+			node = c->data;
+
+			if (func(node, userdata) != TRUE) {
+				p = c;
+				c = c->next;
+				continue;
+			}
+
+			if (mark_only) {
+				node->destroyed = TRUE;
+				p = c;
+				c = c->next;
+				continue;
+			}
+
+			if (p)
+				p->next = c->next;
+			else
+				notify->nodes = c->next;
+
+			ril_notify_node_destroy(node, NULL);
+
+			t = c;
+			c = c->next;
+			g_slist_free_1(t);
+		}
+
+		if (notify->nodes == NULL)
+			g_hash_table_iter_remove(&iter);
+	}
+
+	return TRUE;
+}
+
+/*
+ * This function creates a RIL request.  For a good reference on
+ * the layout of RIL requests, responses, and unsolicited requests
+ * see:
+ *
+ * https://wiki.mozilla.org/B2G/RIL
+ */
+static struct ril_request *ril_request_create(struct ril_s *ril,
+						guint gid,
+						const gint req,
+						const gint id,
+						struct parcel *rilp,
+						GRilResponseFunc func,
+						gpointer user_data,
+						GDestroyNotify notify,
+						gboolean wakeup)
+{
+	struct ril_request *r;
+	struct req_hdr header;
+	guint data_len = 0;
+
+	if (rilp != NULL)
+		data_len = rilp->size;
+
+	r = g_try_new0(struct ril_request, 1);
+	if (r == NULL) {
+		ofono_error("%s Out of memory", __func__);
+		return NULL;
+	}
+
+	/* Full request size: header size plus buffer length */
+	r->data_len = data_len + sizeof(header);
+
+	r->data = g_try_new(char, r->data_len);
+	if (r->data == NULL) {
+		ofono_error("ril_request: can't allocate new request.");
+		g_free(r);
+		return NULL;
+	}
+
+	/* Length does not include the length field. Network order. */
+	header.length = htonl(r->data_len - sizeof(header.length));
+	header.reqid = req;
+	header.serial = id;
+
+	/* copy header */
+	memcpy(r->data, &header, sizeof(header));
+	/* copy request data */
+	if (data_len)
+		memcpy(r->data + sizeof(header), rilp->data, data_len);
+
+	r->req = req;
+	r->gid = gid;
+	r->id = id;
+	r->callback = func;
+	r->user_data = user_data;
+	r->notify = notify;
+
+	return r;
+}
+
+static void ril_request_destroy(struct ril_request *req)
+{
+	if (req->notify)
+		req->notify(req->user_data);
+
+	g_free(req->data);
+	g_free(req);
+}
+
+static void ril_cleanup(struct ril_s *p)
+{
+	/* Cleanup pending commands */
+
+	if (p->command_queue) {
+		g_queue_free(p->command_queue);
+		p->command_queue = NULL;
+	}
+
+	if (p->out_queue) {
+		g_queue_free(p->out_queue);
+		p->out_queue = NULL;
+	}
+
+	/* Cleanup registered notifications */
+	if (p->notify_list) {
+		g_hash_table_destroy(p->notify_list);
+		p->notify_list = NULL;
+	}
+
+	if (p->timeout_source) {
+		g_source_remove(p->timeout_source);
+		p->timeout_source = 0;
+	}
+}
+
+void g_ril_set_disconnect_function(GRil *ril, GRilDisconnectFunc disconnect,
+					gpointer user_data)
+{
+	ril->parent->user_disconnect = disconnect;
+	ril->parent->user_disconnect_data = user_data;
+}
+
+static void io_disconnect(gpointer user_data)
+{
+	struct ril_s *ril = user_data;
+
+	ofono_error("%s: disconnected from rild", __func__);
+
+	ril_cleanup(ril);
+	g_ril_io_unref(ril->io);
+	ril->io = NULL;
+
+	if (ril->user_disconnect)
+		ril->user_disconnect(ril->user_disconnect_data);
+}
+
+static void handle_response(struct ril_s *p, struct ril_msg *message)
+{
+	gsize count = g_queue_get_length(p->command_queue);
+	struct ril_request *req;
+	gboolean found = FALSE;
+	guint i, len;
+	gint id;
+
+	g_assert(count > 0);
+
+	for (i = 0; i < count; i++) {
+		req = g_queue_peek_nth(p->command_queue, i);
+
+		if (req->id == message->serial_no) {
+			found = TRUE;
+			message->req = req->req;
+
+			if (message->error != RIL_E_SUCCESS)
+				RIL_TRACE(p, "[%d,%04d]< %s failed %s",
+					p->slot, message->serial_no,
+					request_id_to_string(p, message->req),
+					ril_error_to_string(message->error));
+
+			req = g_queue_pop_nth(p->command_queue, i);
+			if (req->callback)
+				req->callback(message, req->user_data);
+
+			len = g_queue_get_length(p->out_queue);
+
+			for (i = 0; i < len; i++) {
+				id = GPOINTER_TO_INT(g_queue_peek_nth(
+							p->out_queue, i));
+				if (id == req->id) {
+					g_queue_pop_nth(p->out_queue, i);
+					break;
+				}
+			}
+
+			ril_request_destroy(req);
+
+			if (g_queue_peek_head(p->command_queue))
+				ril_wakeup_writer(p);
+
+			break;
+		}
+	}
+
+	if (found == FALSE)
+		ofono_error("No matching request for reply: %s serial_no: %d!",
+			request_id_to_string(p, message->req),
+			message->serial_no);
+
+}
+
+static gboolean node_check_destroyed(struct ril_notify_node *node,
+					gpointer userdata)
+{
+	gboolean val = GPOINTER_TO_UINT(userdata);
+
+	if (node->destroyed == val)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void handle_unsol_req(struct ril_s *p, struct ril_msg *message)
+{
+	GHashTableIter iter;
+	struct ril_notify *notify;
+	int req_key;
+	gpointer key, value;
+	GList *list_item;
+	struct ril_notify_node *node;
+	gboolean found = FALSE;
+
+	if (p->notify_list == NULL)
+		return;
+
+	p->in_notify = TRUE;
+
+	g_hash_table_iter_init(&iter, p->notify_list);
+
+	while (g_hash_table_iter_next(&iter, &key, &value)) {
+		req_key = *((int *)key);
+		notify = value;
+
+		if (req_key != message->req)
+			continue;
+
+		list_item = (GList *) notify->nodes;
+
+		while (list_item != NULL) {
+			node = list_item->data;
+
+			node->callback(message, node->user_data);
+			found = TRUE;
+			list_item = (GList *) g_slist_next(list_item);
+		}
+	}
+
+	/* Only log events not being listended for... */
+	if (!found)
+		DBG("RIL Event slot %d: %s\n",
+			p->slot, unsol_request_to_string(p, message->req));
+
+	p->in_notify = FALSE;
+
+	/* Now destroy nodes possibly removed by callbacks */
+	if (found)
+		ril_unregister_all(p, FALSE, node_check_destroyed,
+					GUINT_TO_POINTER(TRUE));
+}
+
+static void dispatch(struct ril_s *p, struct ril_msg *message)
+{
+	int32_t *unsolicited_field, *id_num_field;
+	gchar *bufp = message->buf;
+	gchar *datap;
+	gsize data_len;
+
+	/* This could be done with a struct/union... */
+	unsolicited_field = (int32_t *) (void *) bufp;
+	if (*unsolicited_field)
+		message->unsolicited = TRUE;
+	else
+		message->unsolicited = FALSE;
+
+	bufp += 4;
+
+	id_num_field = (int32_t *) (void *) bufp;
+	if (message->unsolicited) {
+		message->req = (int) *id_num_field;
+
+		/*
+		 * A RIL Unsolicited Event is two UINT32 fields ( unsolicited,
+		 * and req/ev ), so subtract the length of the header from the
+		 * overall length to calculate the length of the Event Data.
+		 */
+		data_len = message->buf_len - 8;
+	} else {
+		message->serial_no = (int) *id_num_field;
+
+		bufp += 4;
+		message->error = *((int32_t *) (void *) bufp);
+
+		/*
+		 * A RIL Solicited Response is three UINT32 fields ( unsolicied,
+		 * serial_no and error ), so subtract the length of the header
+		 * from the overall length to calculate the length of the Event
+		 * Data.
+		 */
+		data_len = message->buf_len - 12;
+	}
+
+	/* advance to start of data.. */
+	bufp += 4;
+
+	/*
+	 * Now, use buffer for event data if present
+	 */
+	if (data_len) {
+		datap = g_try_malloc(data_len);
+		if (datap == NULL)
+			goto error;
+
+		/* Copy event bytes from message->buf into new buffer */
+		memcpy(datap, bufp, data_len);
+
+		/* Free buffer that includes header */
+		g_free(message->buf);
+
+		/* ...and replace with new buffer */
+		message->buf = datap;
+		message->buf_len = data_len;
+	} else {
+		/* Free buffer that includes header */
+		g_free(message->buf);
+
+		/* To know if there was no data when parsing */
+		message->buf = NULL;
+		message->buf_len = 0;
+	}
+
+	if (message->unsolicited == TRUE)
+		handle_unsol_req(p, message);
+	else
+		handle_response(p, message);
+
+error:
+	g_free(message->buf);
+	g_free(message);
+}
+
+static struct ril_msg *read_fixed_record(struct ril_s *p,
+						const guchar *bytes, gsize *len)
+{
+	struct ril_msg *message;
+	unsigned message_len, plen;
+
+	/* First four bytes are length in TCP byte order (Big Endian) */
+	plen = ntohl(*((uint32_t *) (void *) bytes));
+	bytes += 4;
+
+	/*
+	 * TODO: Verify that 4k is the max message size from rild.
+	 *
+	 * These conditions shouldn't happen.  If it does
+	 * there are three options:
+	 *
+	 * 1) ASSERT; ofono will restart via DBus
+	 * 2) Consume the bytes & continue
+	 * 3) force a disconnect
+	 */
+	g_assert(plen >= 8 && plen <= 4092);
+
+	/*
+	 * If we don't have the whole fixed record in the ringbuffer
+	 * then return NULL & leave ringbuffer as is.
+	 */
+
+	message_len = *len - 4;
+	if (message_len < plen)
+		return NULL;
+
+	message = g_try_malloc(sizeof(struct ril_msg));
+	g_assert(message != NULL);
+
+	/* allocate ril_msg->buffer */
+	message->buf_len = plen;
+	message->buf = g_try_malloc(plen);
+	g_assert(message->buf != NULL);
+
+	/* Copy bytes into message buffer */
+	memmove(message->buf, (const void *) bytes, plen);
+
+	/* Indicate to caller size of record we extracted */
+	*len = plen + 4;
+	return message;
+}
+
+static void new_bytes(struct ring_buffer *rbuf, gpointer user_data)
+{
+	struct ril_msg *message;
+	struct ril_s *p = user_data;
+	unsigned int len = ring_buffer_len(rbuf);
+	unsigned int wrap = ring_buffer_len_no_wrap(rbuf);
+	guchar *buf = ring_buffer_read_ptr(rbuf, p->read_so_far);
+
+	p->in_read_handler = TRUE;
+
+	while (p->suspended == FALSE && (p->read_so_far < len)) {
+		gsize rbytes = MIN(len - p->read_so_far, wrap - p->read_so_far);
+
+		if (rbytes < 4) {
+			DBG("Not enough bytes for header length: len: %d", len);
+			return;
+		}
+
+		/*
+		 * This function attempts to read the next full length
+		 * fixed message from the stream.  if not all bytes are
+		 * available, it returns NULL.  otherwise it allocates
+		 * and returns a ril_message with the copied bytes, and
+		 * drains those bytes from the ring_buffer
+		 */
+		message = read_fixed_record(p, buf, &rbytes);
+
+		/* wait for the rest of the record... */
+		if (message == NULL)
+			break;
+
+		buf += rbytes;
+		p->read_so_far += rbytes;
+
+		/* TODO: need to better understand how wrap works! */
+		if (p->read_so_far == wrap) {
+			buf = ring_buffer_read_ptr(rbuf, p->read_so_far);
+			wrap = len;
+		}
+
+		dispatch(p, message);
+
+		ring_buffer_drain(rbuf, p->read_so_far);
+
+		len -= p->read_so_far;
+		wrap -= p->read_so_far;
+		p->read_so_far = 0;
+	}
+
+	p->in_read_handler = FALSE;
+
+	if (p->destroyed)
+		g_free(p);
+}
+
+/*
+ * This function is a GIOFunc and may be called directly or via an IO watch.
+ * The return value controls whether the watch stays active ( TRUE ), or is
+ * removed ( FALSE ).
+ */
+static gboolean can_write_data(gpointer data)
+{
+	struct ril_s *ril = data;
+	struct ril_request *req;
+	gsize bytes_written, towrite, len;
+	guint qlen, oqlen;
+	gint id;
+	gboolean written = TRUE;
+	guint i, j;
+
+	qlen = g_queue_get_length(ril->command_queue);
+	if (qlen < 1)
+		return FALSE;
+
+	/* if the whole request was not written */
+	if (ril->req_bytes_written != 0) {
+
+		for (i = 0; i < qlen; i++) {
+			req = g_queue_peek_nth(ril->command_queue, i);
+			if (req) {
+				id = GPOINTER_TO_INT(g_queue_peek_head(
+							ril->out_queue));
+				if (req->id == id)
+					goto out;
+			} else {
+				return FALSE;
+			}
+		}
+	}
+	/* if no requests already sent */
+	oqlen = g_queue_get_length(ril->out_queue);
+	if (oqlen < 1) {
+		req = g_queue_peek_head(ril->command_queue);
+		if (req == NULL)
+			return FALSE;
+
+		g_queue_push_head(ril->out_queue, GINT_TO_POINTER(req->id));
+
+		goto out;
+	}
+
+	for (i = 0; i < qlen; i++) {
+		req = g_queue_peek_nth(ril->command_queue, i);
+		if (req == NULL)
+			return FALSE;
+
+		for (j = 0; j < oqlen; j++) {
+			id = GPOINTER_TO_INT(
+					g_queue_peek_nth(ril->out_queue, j));
+			if (req->id == id) {
+				written = TRUE;
+				break;
+			} else {
+				written = FALSE;
+			}
+		}
+
+		if (written == FALSE)
+			break;
+	}
+
+	/* watcher fired though requests already written */
+	if (written == TRUE)
+		return FALSE;
+
+	g_queue_push_head(ril->out_queue, GINT_TO_POINTER(req->id));
+
+out:
+	len = req->data_len;
+
+	towrite = len - ril->req_bytes_written;
+
+#ifdef WRITE_SCHEDULER_DEBUG
+	if (towrite > 5)
+		towrite = 5;
+#endif
+
+	bytes_written = g_ril_io_write(ril->io,
+					req->data + ril->req_bytes_written,
+					towrite);
+
+	if (bytes_written == 0)
+		return FALSE;
+
+	ril->req_bytes_written += bytes_written;
+	if (bytes_written < towrite)
+		return TRUE;
+	else
+		ril->req_bytes_written = 0;
+
+	return FALSE;
+}
+
+static void ril_wakeup_writer(struct ril_s *ril)
+{
+	g_ril_io_set_write_handler(ril->io, can_write_data, ril);
+}
+
+static void ril_suspend(struct ril_s *ril)
+{
+	ril->suspended = TRUE;
+
+	g_ril_io_set_write_handler(ril->io, NULL, NULL);
+	g_ril_io_set_read_handler(ril->io, NULL, NULL);
+	g_ril_io_set_debug(ril->io, NULL, NULL);
+}
+
+static gboolean ril_set_debug(struct ril_s *ril,
+				GRilDebugFunc func, gpointer user_data)
+{
+
+	ril->debugf = func;
+	ril->debug_data = user_data;
+
+	if (ril->io)
+		g_ril_io_set_debug(ril->io, func, user_data);
+
+	return TRUE;
+}
+
+static void ril_unref(struct ril_s *ril)
+{
+	gboolean is_zero;
+
+	is_zero = g_atomic_int_dec_and_test(&ril->ref_count);
+
+	if (is_zero == FALSE)
+		return;
+
+	if (ril->io) {
+		ril_suspend(ril);
+		g_ril_io_unref(ril->io);
+		ril->io = NULL;
+		ril_cleanup(ril);
+	}
+
+	if (ril->in_read_handler)
+		ril->destroyed = TRUE;
+	else
+		g_free(ril);
+}
+
+static gboolean node_compare_by_group(struct ril_notify_node *node,
+					gpointer userdata)
+{
+	guint group = GPOINTER_TO_UINT(userdata);
+
+	if (node->gid == group)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void set_process_id(gid_t gid, uid_t uid)
+{
+	if (setegid(gid) < 0)
+		ofono_error("%s: setegid(%d) failed: %s (%d)",
+				__func__, gid, strerror(errno), errno);
+
+	if (seteuid(uid) < 0)
+		ofono_error("%s: seteuid(%d) failed: %s (%d)",
+				__func__, uid, strerror(errno), errno);
+}
+
+static struct ril_s *create_ril(const char *sock_path)
+
+{
+	struct ril_s *ril;
+	struct sockaddr_un addr;
+	int sk;
+	GIOChannel *io;
+
+	ril = g_try_new0(struct ril_s, 1);
+	if (ril == NULL)
+		return ril;
+
+	ril->ref_count = 1;
+	ril->next_cmd_id = 1;
+	ril->next_notify_id = 1;
+	ril->next_gid = 0;
+	ril->debugf = NULL;
+	ril->req_bytes_written = 0;
+	ril->trace = FALSE;
+
+	/* sock_path is allowed to be NULL for unit tests */
+	if (sock_path == NULL)
+		return ril;
+
+	sk = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sk < 0) {
+		ofono_error("create_ril: can't create unix socket: %s (%d)\n",
+				strerror(errno), errno);
+		goto error;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
+
+	/* RIL expects user radio to connect to the socket */
+	set_process_id(RADIO_GID, RADIO_UID);
+
+	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		ofono_error("create_ril: can't connect to RILD: %s (%d)\n",
+				strerror(errno), errno);
+		/* Switch back to root */
+		set_process_id(0, 0);
+		goto error;
+	}
+
+	/* Switch back to root */
+	set_process_id(0, 0);
+
+	io = g_io_channel_unix_new(sk);
+	if (io == NULL) {
+		ofono_error("create_ril: can't open RILD io channel: %s (%d)\n",
+				strerror(errno), errno);
+		goto error;
+	}
+
+	g_io_channel_set_close_on_unref(io, TRUE);
+	g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+
+	ril->io = g_ril_io_new(io);
+	if (ril->io == NULL) {
+		ofono_error("create_ril: can't create ril->io");
+		goto error;
+	}
+
+	g_ril_io_set_disconnect_function(ril->io, io_disconnect, ril);
+
+	ril->command_queue = g_queue_new();
+	if (ril->command_queue == NULL) {
+		ofono_error("create_ril: Couldn't create command_queue.");
+		goto error;
+	}
+
+	ril->out_queue = g_queue_new();
+	if (ril->out_queue == NULL) {
+		ofono_error("create_ril: Couldn't create out_queue.");
+		goto error;
+	}
+
+	ril->notify_list = g_hash_table_new_full(g_int_hash, g_int_equal,
+							g_free,
+							ril_notify_destroy);
+
+	g_ril_io_set_read_handler(ril->io, new_bytes, ril);
+
+	return ril;
+
+error:
+	ril_unref(ril);
+
+	return NULL;
+}
+
+static struct ril_notify *ril_notify_create(struct ril_s *ril,
+						const int req)
+{
+	struct ril_notify *notify;
+	int *key;
+
+	notify = g_try_new0(struct ril_notify, 1);
+	if (notify == NULL)
+		return 0;
+
+	key = g_try_new0(int, 1);
+	if (key == NULL)
+		return 0;
+
+	*key = req;
+
+	g_hash_table_insert(ril->notify_list, key, notify);
+
+	return notify;
+}
+
+static void ril_cancel_group(struct ril_s *ril, guint group)
+{
+	int n = 0;
+	guint len, i;
+	struct ril_request *req;
+	gboolean sent;
+
+	if (ril->command_queue == NULL)
+		return;
+
+	while ((req = g_queue_peek_nth(ril->command_queue, n)) != NULL) {
+		if (req->id == 0 || req->gid != group) {
+			n += 1;
+			continue;
+		}
+
+		req->callback = NULL;
+		sent = FALSE;
+
+		len = g_queue_get_length(ril->out_queue);
+		for (i = 0; i < len; i++) {
+			if (GPOINTER_TO_INT(
+					g_queue_peek_nth(ril->out_queue, i))
+					== req->id) {
+				n += 1;
+				sent = TRUE;
+				break;
+			}
+		 }
+
+		if (sent)
+			continue;
+
+		g_queue_remove(ril->command_queue, req);
+		ril_request_destroy(req);
+	}
+}
+
+static guint ril_register(struct ril_s *ril, guint group,
+				const int req, GRilNotifyFunc func,
+				gpointer user_data)
+{
+	struct ril_notify *notify;
+	struct ril_notify_node *node;
+
+	if (ril->notify_list == NULL)
+		return 0;
+
+	if (func == NULL)
+		return 0;
+
+	notify = g_hash_table_lookup(ril->notify_list, &req);
+
+	if (notify == NULL)
+		notify = ril_notify_create(ril, req);
+
+	if (notify == NULL)
+		return 0;
+
+	node = g_try_new0(struct ril_notify_node, 1);
+	if (node == NULL)
+		return 0;
+
+	node->id = ril->next_notify_id++;
+	node->gid = group;
+	node->callback = func;
+	node->user_data = user_data;
+
+	notify->nodes = g_slist_prepend(notify->nodes, node);
+
+	return node->id;
+}
+
+static gboolean ril_unregister(struct ril_s *ril, gboolean mark_only,
+					guint group, guint id)
+{
+	GHashTableIter iter;
+	struct ril_notify *notify;
+	struct ril_notify_node *node;
+	gpointer key, value;
+	GSList *l;
+
+	if (ril->notify_list == NULL)
+		return FALSE;
+
+	g_hash_table_iter_init(&iter, ril->notify_list);
+
+	while (g_hash_table_iter_next(&iter, &key, &value)) {
+		notify = value;
+
+		l = g_slist_find_custom(notify->nodes, GUINT_TO_POINTER(id),
+					ril_notify_node_compare_by_id);
+
+		if (l == NULL)
+			continue;
+
+		node = l->data;
+
+		if (node->gid != group)
+			return FALSE;
+
+		if (mark_only) {
+			node->destroyed = TRUE;
+			return TRUE;
+		}
+
+		ril_notify_node_destroy(node, NULL);
+		notify->nodes = g_slist_remove(notify->nodes, node);
+
+		if (notify->nodes == NULL)
+			g_hash_table_iter_remove(&iter);
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+void g_ril_init_parcel(const struct ril_msg *message, struct parcel *rilp)
+{
+	/* Set up Parcel struct for proper parsing */
+	rilp->data = message->buf;
+	rilp->size = message->buf_len;
+	rilp->capacity = message->buf_len;
+	rilp->offset = 0;
+	rilp->malformed = 0;
+}
+
+GRil *g_ril_new(const char *sock_path, enum ofono_ril_vendor vendor)
+{
+	GRil *ril;
+
+	ril = g_try_new0(GRil, 1);
+	if (ril == NULL)
+		return NULL;
+
+	ril->parent = create_ril(sock_path);
+	if (ril->parent == NULL) {
+		g_free(ril);
+		return NULL;
+	}
+
+	ril->group = ril->parent->next_gid++;
+	ril->ref_count = 1;
+
+	ril->parent->vendor = vendor;
+
+	return ril;
+}
+
+GRil *g_ril_clone(GRil *clone)
+{
+	GRil *ril;
+
+	if (clone == NULL)
+		return NULL;
+
+	ril = g_try_new0(GRil, 1);
+	if (ril == NULL)
+		return NULL;
+
+	ril->parent = clone->parent;
+	ril->group = ril->parent->next_gid++;
+	ril->ref_count = 1;
+	g_atomic_int_inc(&ril->parent->ref_count);
+
+	return ril;
+}
+
+GIOChannel *g_ril_get_channel(GRil *ril)
+{
+	if (ril == NULL || ril->parent->io == NULL)
+		return NULL;
+
+	return g_ril_io_get_channel(ril->parent->io);
+
+}
+
+GRilIO *g_ril_get_io(GRil *ril)
+{
+	if (ril == NULL)
+		return NULL;
+
+	return ril->parent->io;
+}
+
+GRil *g_ril_ref(GRil *ril)
+{
+	if (ril == NULL)
+		return NULL;
+
+	g_atomic_int_inc(&ril->ref_count);
+
+	return ril;
+}
+
+gint g_ril_send(GRil *ril, const gint reqid, struct parcel *rilp,
+		GRilResponseFunc func, gpointer user_data,
+		GDestroyNotify notify)
+{
+	struct ril_request *r;
+	struct ril_s *p;
+
+	if (ril == NULL
+		|| ril->parent == NULL
+		|| ril->parent->command_queue == NULL)
+			return 0;
+
+	p = ril->parent;
+
+	r = ril_request_create(p, ril->group, reqid, p->next_cmd_id, rilp,
+				func, user_data, notify, FALSE);
+
+	if (rilp != NULL)
+		parcel_free(rilp);
+
+	if (r == NULL)
+		return 0;
+
+	p->next_cmd_id++;
+
+	g_queue_push_tail(p->command_queue, r);
+
+	ril_wakeup_writer(p);
+
+	if (rilp == NULL)
+		g_ril_print_request_no_args(ril, r->id, reqid);
+	else
+		g_ril_print_request(ril, r->id, reqid);
+
+	return r->id;
+}
+
+void g_ril_unref(GRil *ril)
+{
+	gboolean is_zero;
+
+	if (ril == NULL)
+		return;
+
+	is_zero = g_atomic_int_dec_and_test(&ril->ref_count);
+
+	if (is_zero == FALSE)
+		return;
+
+	ril_cancel_group(ril->parent, ril->group);
+	g_ril_unregister_all(ril);
+	ril_unref(ril->parent);
+
+	g_free(ril);
+}
+
+gboolean g_ril_get_trace(GRil *ril)
+{
+
+	if (ril == NULL || ril->parent == NULL)
+		return FALSE;
+
+	return ril->parent->trace;
+}
+
+gboolean g_ril_set_trace(GRil *ril, gboolean trace)
+{
+
+	if (ril == NULL || ril->parent == NULL)
+		return FALSE;
+
+	return ril->parent->trace = trace;
+}
+
+gboolean g_ril_set_slot(GRil *ril, int slot)
+{
+	if (ril == NULL || ril->parent == NULL)
+		return FALSE;
+
+	ril->parent->slot = slot;
+	return TRUE;
+}
+
+int g_ril_get_slot(GRil *ril)
+{
+	if (ril == NULL)
+		return 0;
+
+	return ril->parent->slot;
+}
+
+gboolean g_ril_set_debugf(GRil *ril,
+			GRilDebugFunc func, gpointer user_data)
+{
+
+	if (ril == NULL || ril->group != 0)
+		return FALSE;
+
+	return ril_set_debug(ril->parent, func, user_data);
+}
+
+gboolean g_ril_set_vendor_print_msg_id_funcs(GRil *ril,
+					GRilMsgIdToStrFunc req_to_string,
+					GRilMsgIdToStrFunc unsol_to_string)
+{
+	if (ril == NULL || ril->parent == NULL)
+		return FALSE;
+
+	ril->parent->req_to_string = req_to_string;
+	ril->parent->unsol_to_string = unsol_to_string;
+
+	return TRUE;
+}
+
+guint g_ril_register(GRil *ril, const int req,
+			GRilNotifyFunc func, gpointer user_data)
+{
+	if (ril == NULL)
+		return 0;
+
+	return ril_register(ril->parent, ril->group, req,
+				func, user_data);
+}
+
+gboolean g_ril_unregister(GRil *ril, guint id)
+{
+	if (ril == NULL)
+		return FALSE;
+
+	return ril_unregister(ril->parent, ril->parent->in_notify,
+					ril->group, id);
+}
+
+gboolean g_ril_unregister_all(GRil *ril)
+{
+	if (ril == NULL)
+		return FALSE;
+
+	return ril_unregister_all(ril->parent,
+					ril->parent->in_notify,
+					node_compare_by_group,
+					GUINT_TO_POINTER(ril->group));
+}
+
+enum ofono_ril_vendor g_ril_vendor(GRil *ril)
+{
+	if (ril == NULL)
+		return OFONO_RIL_VENDOR_AOSP;
+
+	return ril->parent->vendor;
+}
+
+const char *g_ril_request_id_to_string(GRil *ril, int req)
+{
+	return request_id_to_string(ril->parent, req);
+}
+
+const char *g_ril_unsol_request_to_string(GRil *ril, int req)
+{
+	return unsol_request_to_string(ril->parent, req);
+}
diff --git a/gril/gril.h b/gril/gril.h
new file mode 100644
index 0000000..7d64e7e
--- /dev/null
+++ b/gril/gril.h
@@ -0,0 +1,172 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012 Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GRIL_H
+#define __GRIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "grilio.h"
+#include "grilutil.h"
+#include "parcel.h"
+#include "ril_constants.h"
+#include "drivers/rilmodem/vendor.h"
+
+#define RIL_MAX_NUM_ACTIVE_DATA_CALLS 2
+
+struct _GRil;
+
+typedef struct _GRil GRil;
+
+/*
+ * This struct represents an entire RIL message read
+ * from the command socket.  It can hold responses or
+ * unsolicited requests from RILD.
+ */
+struct ril_msg {
+	gchar *buf;
+	gsize buf_len;
+	gboolean unsolicited;
+	int req;
+	int serial_no;
+	int error;
+};
+
+typedef void (*GRilResponseFunc)(struct ril_msg *message, gpointer user_data);
+
+typedef void (*GRilNotifyFunc)(struct ril_msg *message, gpointer user_data);
+
+typedef const char *(*GRilMsgIdToStrFunc)(int msg_id);
+
+/**
+ * TRACE:
+ * @fmt: format string
+ * @arg...: list of arguments
+ *
+ * Simple macro around ofono_debug() used for tracing RIL messages
+ * name it is called in.
+ */
+#define G_RIL_TRACE(gril, fmt, arg...) do {	\
+	if (gril && g_ril_get_trace(gril))	\
+		ofono_debug(fmt, ## arg);	\
+} while (0)
+
+extern char print_buf[];
+
+#define g_ril_print_request(gril, token, req)				\
+	G_RIL_TRACE(gril, "[%d,%04d]> %s %s",				\
+		g_ril_get_slot(gril), token,				\
+		g_ril_request_id_to_string(gril, req), print_buf)
+#define g_ril_print_request_no_args(gril, token, req)			\
+	G_RIL_TRACE(gril, "[%d,%04d]> %s",				\
+			g_ril_get_slot(gril), token,			\
+			g_ril_request_id_to_string(gril, req))
+#define g_ril_print_response(gril, message)				\
+	G_RIL_TRACE(gril, "[%d,%04d]< %s %s",				\
+			g_ril_get_slot(gril),				\
+			message->serial_no,				\
+			g_ril_request_id_to_string(gril, message->req), \
+							print_buf)
+#define g_ril_print_response_no_args(gril, message)			\
+	G_RIL_TRACE(gril, "[%d,%04d]< %s",				\
+		g_ril_get_slot(gril), message->serial_no,		\
+			g_ril_request_id_to_string(gril, message->req))
+
+#define g_ril_append_print_buf(gril, x...) do {	\
+	if (gril && g_ril_get_trace(gril))	\
+		sprintf(print_buf, x);		\
+} while (0)
+
+#define g_ril_print_unsol(gril, message)				\
+	G_RIL_TRACE(gril, "[%d,UNSOL]< %s %s",				\
+			g_ril_get_slot(gril),				\
+			g_ril_unsol_request_to_string(gril,		\
+							message->req),	\
+			print_buf)
+#define g_ril_print_unsol_no_args(gril, message)			\
+	G_RIL_TRACE(gril, "[%d,UNSOL]< %s", g_ril_get_slot(gril),	\
+			g_ril_unsol_request_to_string(gril, message->req))
+
+void g_ril_init_parcel(const struct ril_msg *message, struct parcel *rilp);
+
+GRil *g_ril_new(const char *sock_path, enum ofono_ril_vendor vendor);
+
+GIOChannel *g_ril_get_channel(GRil *ril);
+GRilIO *g_ril_get_io(GRil *ril);
+
+GRil *g_ril_ref(GRil *ril);
+void g_ril_unref(GRil *ril);
+
+GRil *g_ril_clone(GRil *ril);
+
+void g_ril_set_disconnect_function(GRil *ril, GRilDisconnectFunc disconnect,
+					gpointer user_data);
+
+gboolean g_ril_get_trace(GRil *ril);
+gboolean g_ril_set_trace(GRil *ril, gboolean trace);
+
+int g_ril_get_slot(GRil *ril);
+gboolean g_ril_set_slot(GRil *ril, int slot);
+
+/*!
+ * If the function is not NULL, then on every read/write from the GIOChannel
+ * provided to GRil the logging function will be called with the
+ * input/output string and user data
+ */
+gboolean g_ril_set_debugf(GRil *ril, GRilDebugFunc func, gpointer user_data);
+
+gboolean g_ril_set_vendor_print_msg_id_funcs(GRil *ril,
+					GRilMsgIdToStrFunc req_to_string,
+					GRilMsgIdToStrFunc unsol_to_string);
+
+
+/*!
+ * Queue an RIL request for execution.  The request contents are given
+ * in data.  Once the command executes, the callback function given by
+ * func is called with user provided data in user_data.
+ *
+ * Returns an id of the queued command which can be canceled using
+ * g_ril_cancel.  If an error occurred, an id of 0 is returned.
+ *
+ */
+gint g_ril_send(GRil *ril, const gint reqid, struct parcel *rilp,
+		GRilResponseFunc func, gpointer user_data,
+		GDestroyNotify notify);
+
+guint g_ril_register(GRil *ril, const int req,
+			GRilNotifyFunc func, gpointer user_data);
+
+gboolean g_ril_unregister(GRil *ril, guint id);
+gboolean g_ril_unregister_all(GRil *ril);
+
+enum ofono_ril_vendor g_ril_vendor(GRil *ril);
+
+const char *g_ril_request_id_to_string(GRil *ril, int req);
+const char *g_ril_unsol_request_to_string(GRil *ril, int req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRIL_H */
diff --git a/gril/grilio.c b/gril/grilio.c
new file mode 100644
index 0000000..14ae908
--- /dev/null
+++ b/gril/grilio.c
@@ -0,0 +1,399 @@
+/*
+ *
+ *  RIL chat library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  Canonical Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "ringbuffer.h"
+#include "grilio.h"
+#include "grilutil.h"
+
+struct _GRilIO {
+	gint ref_count;				/* Ref count */
+	guint read_watch;			/* GSource read id, 0 if no */
+	guint write_watch;			/* GSource write id, 0 if no */
+	GIOChannel *channel;			/* comms channel */
+	GRilDisconnectFunc user_disconnect;	/* user disconnect func */
+	gpointer user_disconnect_data;		/* user disconnect data */
+	struct ring_buffer *buf;		/* Current read buffer */
+	guint max_read_attempts;		/* max reads / select */
+	GRilIOReadFunc read_handler;		/* Read callback */
+	gpointer read_data;			/* Read callback userdata */
+	gboolean use_write_watch;		/* Use write select */
+	GRilIOWriteFunc write_handler;		/* Write callback */
+	gpointer write_data;			/* Write callback userdata */
+	GRilDebugFunc debugf;			/* debugging output function */
+	gpointer debug_data;			/* Data to pass to debug func */
+	GRilDisconnectFunc write_done_func;	/* tx empty notifier */
+	gpointer write_done_data;		/* tx empty data */
+	gboolean destroyed;			/* Re-entrancy guard */
+};
+
+static void read_watcher_destroy_notify(gpointer user_data)
+{
+	GRilIO *io = user_data;
+
+	ring_buffer_free(io->buf);
+	io->buf = NULL;
+
+	io->debugf = NULL;
+	io->debug_data = NULL;
+
+	io->read_watch = 0;
+	io->read_handler = NULL;
+	io->read_data = NULL;
+
+	g_io_channel_unref(io->channel);
+	io->channel = NULL;
+
+	if (io->destroyed)
+		g_free(io);
+	else if (io->user_disconnect)
+		io->user_disconnect(io->user_disconnect_data);
+}
+
+static gboolean received_data(GIOChannel *channel, GIOCondition cond,
+				gpointer data)
+{
+	unsigned char *buf;
+	GRilIO *io = data;
+	GIOStatus status;
+	gsize rbytes;
+	gsize toread;
+	gsize total_read = 0;
+	guint read_count = 0;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	/* Regardless of condition, try to read all the data available */
+	do {
+		toread = ring_buffer_avail_no_wrap(io->buf);
+
+		if (toread == 0)
+			break;
+
+		rbytes = 0;
+		buf = ring_buffer_write_ptr(io->buf, 0);
+
+		status = g_io_channel_read_chars(channel, (char *) buf,
+							toread, &rbytes, NULL);
+
+		g_ril_util_debug_hexdump(TRUE, (guchar *) buf, rbytes,
+						io->debugf, io->debug_data);
+
+		read_count++;
+
+		total_read += rbytes;
+
+		if (rbytes > 0)
+			ring_buffer_write_advance(io->buf, rbytes);
+
+	} while (status == G_IO_STATUS_NORMAL && rbytes > 0 &&
+					read_count < io->max_read_attempts);
+
+	if (total_read > 0 && io->read_handler)
+		io->read_handler(io->buf, io->read_data);
+
+	if (cond & (G_IO_HUP | G_IO_ERR))
+		return FALSE;
+
+	if (read_count > 0 && rbytes == 0 && status != G_IO_STATUS_AGAIN)
+		return FALSE;
+
+	/* We're overflowing the buffer, shutdown the socket */
+	if (ring_buffer_avail(io->buf) == 0)
+		return FALSE;
+
+	return TRUE;
+}
+
+gsize g_ril_io_write(GRilIO *io, const gchar *data, gsize count)
+{
+	GIOStatus status;
+	gsize bytes_written;
+
+	status = g_io_channel_write_chars(io->channel, data,
+						count, &bytes_written, NULL);
+
+	if (status != G_IO_STATUS_NORMAL) {
+		g_source_remove(io->read_watch);
+		return 0;
+	}
+
+	g_ril_util_debug_hexdump(FALSE, (guchar *) data, bytes_written,
+				io->debugf, io->debug_data);
+
+	return bytes_written;
+}
+
+static void write_watcher_destroy_notify(gpointer user_data)
+{
+	GRilIO *io = user_data;
+
+	io->write_watch = 0;
+	io->write_handler = NULL;
+	io->write_data = NULL;
+
+	if (io->write_done_func) {
+		io->write_done_func(io->write_done_data);
+		io->write_done_func = NULL;
+		io->write_done_data = NULL;
+	}
+}
+
+static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
+				gpointer data)
+{
+	GRilIO *io = data;
+
+	if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
+		return FALSE;
+
+	if (io->write_handler == NULL)
+		return FALSE;
+
+	return io->write_handler(io->write_data);
+}
+
+static GRilIO *create_io(GIOChannel *channel, GIOFlags flags)
+{
+	GRilIO *io;
+
+	if (channel == NULL)
+		return NULL;
+
+	io = g_try_new0(GRilIO, 1);
+	if (io == NULL)
+		return io;
+
+	io->ref_count = 1;
+	io->debugf = NULL;
+
+	if (flags & G_IO_FLAG_NONBLOCK) {
+		io->max_read_attempts = 3;
+		io->use_write_watch = TRUE;
+	} else {
+		io->max_read_attempts = 1;
+		io->use_write_watch = FALSE;
+	}
+
+	io->buf = ring_buffer_new(8192);
+
+	if (!io->buf)
+		goto error;
+
+	if (!g_ril_util_setup_io(channel, flags))
+		goto error;
+
+	io->channel = channel;
+	io->read_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				received_data, io,
+				read_watcher_destroy_notify);
+
+	return io;
+
+error:
+	if (io->buf)
+		ring_buffer_free(io->buf);
+
+	g_free(io);
+
+	return NULL;
+}
+
+GRilIO *g_ril_io_new(GIOChannel *channel)
+{
+	return create_io(channel, G_IO_FLAG_NONBLOCK);
+}
+
+GRilIO *g_ril_io_new_blocking(GIOChannel *channel)
+{
+	return create_io(channel, 0);
+}
+
+GIOChannel *g_ril_io_get_channel(GRilIO *io)
+{
+	if (io == NULL)
+		return NULL;
+
+	return io->channel;
+}
+
+gboolean g_ril_io_set_read_handler(GRilIO *io, GRilIOReadFunc read_handler,
+					gpointer user_data)
+{
+	if (io == NULL)
+		return FALSE;
+
+	io->read_handler = read_handler;
+	io->read_data = user_data;
+
+	if (read_handler && ring_buffer_len(io->buf) > 0)
+		read_handler(io->buf, user_data);
+
+	return TRUE;
+}
+
+static gboolean call_blocking_read(gpointer user_data)
+{
+	GRilIO *io = user_data;
+
+	while (can_write_data(io->channel, G_IO_OUT, io) == TRUE)
+		;
+
+	write_watcher_destroy_notify(io);
+
+	return FALSE;
+}
+
+gboolean g_ril_io_set_write_handler(GRilIO *io, GRilIOWriteFunc write_handler,
+					gpointer user_data)
+{
+	if (io == NULL)
+		return FALSE;
+
+	if (io->write_watch > 0) {
+		if (write_handler == NULL) {
+			g_source_remove(io->write_watch);
+			return TRUE;
+		}
+
+		return FALSE;
+	}
+
+	if (write_handler == NULL)
+		return FALSE;
+
+	io->write_handler = write_handler;
+	io->write_data = user_data;
+
+	if (io->use_write_watch == TRUE)
+		io->write_watch = g_io_add_watch_full(io->channel,
+				G_PRIORITY_HIGH,
+				G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				can_write_data, io,
+				write_watcher_destroy_notify);
+	else
+		io->write_watch = g_idle_add(call_blocking_read, io);
+
+	return TRUE;
+}
+
+GRilIO *g_ril_io_ref(GRilIO *io)
+{
+	if (io == NULL)
+		return NULL;
+
+	g_atomic_int_inc(&io->ref_count);
+
+	return io;
+}
+
+static gboolean io_shutdown(GRilIO *io)
+{
+	/* Don't trigger user disconnect on shutdown */
+	io->user_disconnect = NULL;
+	io->user_disconnect_data = NULL;
+
+	if (io->read_watch > 0)
+		g_source_remove(io->read_watch);
+
+	if (io->write_watch > 0)
+		g_source_remove(io->write_watch);
+
+	return TRUE;
+}
+
+void g_ril_io_unref(GRilIO *io)
+{
+	gboolean is_zero;
+
+	if (io == NULL)
+		return;
+
+	is_zero = g_atomic_int_dec_and_test(&io->ref_count);
+
+	if (is_zero == FALSE)
+		return;
+
+	io_shutdown(io);
+
+	/* glib delays the destruction of the watcher until it exits, this
+	 * means we can't free the data just yet, even though we've been
+	 * destroyed already.  We have to wait until the read_watcher
+	 * destroy function gets called
+	 */
+	if (io->read_watch > 0)
+		io->destroyed = TRUE;
+	else
+		g_free(io);
+}
+
+gboolean g_ril_io_set_disconnect_function(GRilIO *io,
+			GRilDisconnectFunc disconnect, gpointer user_data)
+{
+	if (io == NULL)
+		return FALSE;
+
+	io->user_disconnect = disconnect;
+	io->user_disconnect_data = user_data;
+
+	return TRUE;
+}
+
+gboolean g_ril_io_set_debug(GRilIO *io, GRilDebugFunc func, gpointer user_data)
+{
+	if (io == NULL)
+		return FALSE;
+
+	io->debugf = func;
+	io->debug_data = user_data;
+
+	return TRUE;
+}
+
+void g_ril_io_set_write_done(GRilIO *io, GRilDisconnectFunc func,
+				gpointer user_data)
+{
+	if (io == NULL)
+		return;
+
+	io->write_done_func = func;
+	io->write_done_data = user_data;
+}
+
+void g_ril_io_drain_ring_buffer(GRilIO *io, guint len)
+{
+	ring_buffer_drain(io->buf, len);
+}
diff --git a/gril/grilio.h b/gril/grilio.h
new file mode 100644
index 0000000..22fb60e
--- /dev/null
+++ b/gril/grilio.h
@@ -0,0 +1,69 @@
+/*
+ *
+ *  RIL chat library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GRILIO_H
+#define __GRILIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gfunc.h"
+
+struct _GRilIO;
+
+typedef struct _GRilIO GRilIO;
+
+struct ring_buffer;
+
+typedef void (*GRilIOReadFunc)(struct ring_buffer *buffer, gpointer user_data);
+typedef gboolean (*GRilIOWriteFunc)(gpointer user_data);
+
+GRilIO *g_ril_io_new(GIOChannel *channel);
+GRilIO *g_ril_io_new_blocking(GIOChannel *channel);
+
+GIOChannel *g_ril_io_get_channel(GRilIO *io);
+
+GRilIO *g_ril_io_ref(GRilIO *io);
+void g_ril_io_unref(GRilIO *io);
+
+gboolean g_ril_io_set_read_handler(GRilIO *io, GRilIOReadFunc read_handler,
+					gpointer user_data);
+gboolean g_ril_io_set_write_handler(GRilIO *io, GRilIOWriteFunc write_handler,
+					gpointer user_data);
+void g_ril_io_set_write_done(GRilIO *io, GRilDisconnectFunc func,
+				gpointer user_data);
+
+void g_ril_io_drain_ring_buffer(GRilIO *io, guint len);
+
+gsize g_ril_io_write(GRilIO *io, const gchar *data, gsize count);
+
+gboolean g_ril_io_set_disconnect_function(GRilIO *io,
+			GRilDisconnectFunc disconnect, gpointer user_data);
+
+gboolean g_ril_io_set_debug(GRilIO *io, GRilDebugFunc func, gpointer user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRILIO_H */
diff --git a/gril/grilreply.c b/gril/grilreply.c
new file mode 100644
index 0000000..8792f47
--- /dev/null
+++ b/gril/grilreply.c
@@ -0,0 +1,1450 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013 Jolla Ltd
+ *  Contact: Jussi Kangas <jussi.kangas@tieto.com>
+ *  Copyright (C) 2012-2014  Canonical Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-forwarding.h>
+#include <ofono/gprs-context.h>
+
+#include "common.h"
+#include "util.h"
+#include "grilreply.h"
+#include "grilutil.h"
+
+#define OPERATOR_NUM_PARAMS 3
+
+/* Indexes for registration state replies */
+#define RST_IX_STATE 0
+#define RST_IX_LAC 1
+#define RST_IX_CID 2
+#define RST_IX_RAT 3
+#define RDST_IX_MAXDC 5
+
+#define MTK_MODEM_MAX_CIDS 3
+
+static void ril_reply_free_operator(gpointer data)
+{
+	struct reply_operator *reply = data;
+
+	if (reply) {
+		g_free(reply->lalpha);
+		g_free(reply->salpha);
+		g_free(reply->numeric);
+		g_free(reply->status);
+		g_free(reply);
+	}
+}
+
+void g_ril_reply_free_avail_ops(struct reply_avail_ops *reply)
+{
+	if (reply) {
+		g_slist_free_full(reply->list, ril_reply_free_operator);
+		g_free(reply);
+	}
+}
+
+struct reply_avail_ops *g_ril_reply_parse_avail_ops(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	struct reply_operator *operator;
+	struct reply_avail_ops *reply = NULL;
+	unsigned int num_ops, num_strings;
+	unsigned int i;
+	int strings_per_opt;
+
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK)
+		strings_per_opt = 5;
+	else
+		strings_per_opt = 4;
+
+	/*
+	 * Minimum message length is 4:
+	 * - array size
+	 */
+	if (message->buf_len < 4) {
+		ofono_error("%s: invalid QUERY_AVAIL_NETWORKS reply: "
+				"size too small (< 4): %d ",
+				__func__,
+				(int) message->buf_len);
+		goto error;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+	g_ril_append_print_buf(gril, "{");
+
+	/* Number of operators at the list */
+	num_strings = (unsigned int) parcel_r_int32(&rilp);
+	if (num_strings % strings_per_opt) {
+		ofono_error("%s: invalid QUERY_AVAIL_NETWORKS reply: "
+				"num_strings (%d) MOD %d != 0",
+				__func__,
+				num_strings, strings_per_opt);
+		goto error;
+	}
+
+	num_ops = num_strings / strings_per_opt;
+	DBG("noperators = %d", num_ops);
+
+	reply = g_try_new0(struct reply_avail_ops, 1);
+	if (reply == NULL) {
+		ofono_error("%s: can't allocate reply struct", __func__);
+		goto error;
+	}
+
+	reply->num_ops = num_ops;
+	for (i = 0; i < num_ops; i++) {
+		operator = g_try_new0(struct reply_operator, 1);
+		if (operator == NULL) {
+			ofono_error("%s: can't allocate reply struct",
+					__func__);
+			goto error;
+		}
+
+		operator->lalpha = parcel_r_string(&rilp);
+		operator->salpha = parcel_r_string(&rilp);
+		operator->numeric = parcel_r_string(&rilp);
+		operator->status = parcel_r_string(&rilp);
+
+		/*
+		 * MTK: additional string with technology: 2G/3G are the only
+		 * valid values currently.
+		 */
+		if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) {
+			char *tech = parcel_r_string(&rilp);
+			if (strcmp(tech, "3G") == 0)
+				operator->tech = RADIO_TECH_UMTS;
+			else
+				operator->tech = RADIO_TECH_GSM;
+			g_free(tech);
+		} else {
+			operator->tech = RADIO_TECH_GSM;
+		}
+
+		if (operator->lalpha == NULL && operator->salpha == NULL) {
+			ofono_error("%s: operator (%s) doesn't specify names",
+					operator->numeric,
+					__func__);
+			g_ril_reply_free_operator(operator);
+			continue;
+		}
+
+		if (operator->numeric == NULL) {
+			ofono_error("%s: operator (%s/%s) "
+					"doesn't specify numeric",
+					operator->lalpha,
+					operator->salpha,
+					__func__);
+			g_ril_reply_free_operator(operator);
+			continue;
+		}
+
+		if (operator->status == NULL) {
+			ofono_error("%s: operator (%s/%s) "
+					"doesn't specify status",
+					operator->lalpha,
+					operator->salpha,
+					__func__);
+			g_ril_reply_free_operator(operator);
+			continue;
+		}
+
+		reply->list = g_slist_append(reply->list, operator);
+
+		g_ril_append_print_buf(gril, "%s [lalpha=%s, salpha=%s, "
+				" numeric=%s status=%s tech=%s]",
+				print_buf,
+				operator->lalpha,
+				operator->salpha,
+				operator->numeric,
+				operator->status,
+				ril_radio_tech_to_string(operator->tech));
+	}
+
+	g_ril_append_print_buf(gril, "%s}", print_buf);
+	g_ril_print_response(gril, message);
+
+	return reply;
+
+error:
+	if (reply)
+		g_ril_reply_free_avail_ops(reply);
+
+	return NULL;
+}
+
+void g_ril_reply_free_operator(struct reply_operator *reply)
+{
+	ril_reply_free_operator(reply);
+}
+
+struct reply_operator *g_ril_reply_parse_operator(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int num_params;
+	struct reply_operator *reply = NULL;
+
+	/*
+	 * Minimum message length is 16:
+	 * - array size
+	 * - 3 NULL strings
+	 */
+	if (message->buf_len < 16) {
+		ofono_error("%s: invalid OPERATOR reply: "
+				"size too small (< 16): %d ",
+				__func__,
+				(int) message->buf_len);
+		goto error;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	num_params = parcel_r_int32(&rilp);
+	if (num_params != OPERATOR_NUM_PARAMS) {
+		ofono_error("%s: invalid OPERATOR reply: "
+				"number of params is %d; should be 3.",
+				__func__,
+				num_params);
+		goto error;
+	}
+
+	reply =	g_new0(struct reply_operator, 1);
+
+	reply->lalpha = parcel_r_string(&rilp);
+	reply->salpha = parcel_r_string(&rilp);
+	reply->numeric = parcel_r_string(&rilp);
+
+	if (reply->lalpha == NULL && reply->salpha == NULL) {
+		ofono_error("%s: invalid OPERATOR reply: "
+				" no names returned.",
+				__func__);
+
+		goto error;
+	}
+
+	if (reply->numeric == NULL) {
+		ofono_error("%s: invalid OPERATOR reply: "
+				" no numeric returned.",
+				__func__);
+		goto error;
+	}
+
+	g_ril_append_print_buf(gril,
+				"(lalpha=%s, salpha=%s, numeric=%s)",
+				reply->lalpha, reply->salpha, reply->numeric);
+
+	g_ril_print_response(gril, message);
+
+	return reply;
+
+error:
+	if (reply)
+		g_ril_reply_free_operator(reply);
+
+	return NULL;
+}
+
+static void set_reg_state(GRil *gril, struct reply_reg_state *reply,
+				int i, const char *str)
+{
+	int val;
+	char *endp;
+	int base;
+	const char *strstate;
+
+	if (str == NULL || *str == '\0')
+		goto no_val;
+
+	if (i == RST_IX_LAC || i == RST_IX_CID)
+		base = 16;
+	else
+		base = 10;
+
+	val = (int) strtol(str, &endp, base);
+	if (*endp != '\0')
+		goto no_val;
+
+	switch (i) {
+	case RST_IX_STATE:
+		switch (val) {
+		case RIL_REG_STATE_NOT_REGISTERED:
+		case RIL_REG_STATE_REGISTERED:
+		case RIL_REG_STATE_SEARCHING:
+		case RIL_REG_STATE_DENIED:
+		case RIL_REG_STATE_UNKNOWN:
+		case RIL_REG_STATE_ROAMING:
+			/* Only valid values for ofono */
+			strstate = registration_status_to_string(val);
+			break;
+		case RIL_REG_STATE_EMERGENCY_NOT_REGISTERED:
+		case RIL_REG_STATE_EMERGENCY_SEARCHING:
+		case RIL_REG_STATE_EMERGENCY_DENIED:
+		case RIL_REG_STATE_EMERGENCY_UNKNOWN:
+			/* Map to states valid for ofono core */
+			val -= RIL_REG_STATE_EMERGENCY_NOT_REGISTERED;
+			strstate = str;
+			break;
+		default:
+			val = NETWORK_REGISTRATION_STATUS_UNKNOWN;
+			strstate = str;
+		}
+		reply->status = val;
+		g_ril_append_print_buf(gril, "%s%s", print_buf, strstate);
+		break;
+	case RST_IX_LAC:
+		reply->lac = val;
+		g_ril_append_print_buf(gril, "%s0x%x", print_buf, val);
+		break;
+	case RST_IX_CID:
+		reply->ci = val;
+		g_ril_append_print_buf(gril, "%s0x%x", print_buf, val);
+		break;
+	case RST_IX_RAT:
+		g_ril_append_print_buf(gril, "%s%s", print_buf,
+					ril_radio_tech_to_string(val));
+
+		if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) {
+			switch (val) {
+			case MTK_RADIO_TECH_HSDPAP:
+			case MTK_RADIO_TECH_HSDPAP_UPA:
+			case MTK_RADIO_TECH_HSUPAP:
+			case MTK_RADIO_TECH_HSUPAP_DPA:
+				val = RADIO_TECH_HSPAP;
+				break;
+			case MTK_RADIO_TECH_DC_DPA:
+				val = RADIO_TECH_HSDPA;
+				break;
+			case MTK_RADIO_TECH_DC_UPA:
+				val = RADIO_TECH_HSUPA;
+				break;
+			case MTK_RADIO_TECH_DC_HSDPAP:
+			case MTK_RADIO_TECH_DC_HSDPAP_UPA:
+			case MTK_RADIO_TECH_DC_HSDPAP_DPA:
+			case MTK_RADIO_TECH_DC_HSPAP:
+				val = RADIO_TECH_HSPAP;
+				break;
+			}
+		}
+
+		reply->tech = val;
+		break;
+	default:
+		goto no_val;
+	}
+
+	return;
+
+no_val:
+	g_ril_append_print_buf(gril, "%s%s", print_buf, str ? str : "(null)");
+}
+
+struct reply_reg_state *g_ril_reply_parse_voice_reg_state(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	struct parcel_str_array *str_arr;
+	struct reply_reg_state *reply = NULL;
+	int i;
+
+	g_ril_init_parcel(message, &rilp);
+
+	str_arr = parcel_r_str_array(&rilp);
+	if (str_arr == NULL) {
+		ofono_error("%s: parse error for %s", __func__,
+				ril_request_id_to_string(message->req));
+		goto out;
+	}
+
+	reply =	g_try_malloc0(sizeof(*reply));
+	if (reply == NULL) {
+		ofono_error("%s: out of memory", __func__);
+		goto out;
+	}
+
+	reply->status = -1;
+	reply->lac = -1;
+	reply->ci = -1;
+
+	g_ril_append_print_buf(gril, "{");
+
+	for (i = 0; i < str_arr->num_str; ++i) {
+		char *str = str_arr->str[i];
+
+		if (i > 0)
+			g_ril_append_print_buf(gril, "%s,", print_buf);
+
+		switch (i) {
+		case RST_IX_STATE: case RST_IX_LAC:
+		case RST_IX_CID:   case RST_IX_RAT:
+			set_reg_state(gril, reply, i, str);
+			break;
+		default:
+			g_ril_append_print_buf(gril, "%s%s", print_buf,
+						str ? str : "(null)");
+		}
+	}
+
+	g_ril_append_print_buf(gril, "%s}", print_buf);
+	g_ril_print_response(gril, message);
+
+	/* As a minimum we require a valid status string */
+	if (reply->status == -1) {
+		ofono_error("%s: invalid status", __func__);
+		g_free(reply);
+		reply = NULL;
+	}
+
+out:
+	parcel_free_str_array(str_arr);
+
+	return reply;
+}
+
+static void set_data_reg_state(GRil *gril, struct reply_data_reg_state *reply,
+				int i, const char *str)
+{
+	unsigned val;
+	char *endp;
+
+	if (str == NULL || *str == '\0')
+		goto no_val;
+
+	val = (unsigned) strtoul(str, &endp, 10);
+	if (*endp != '\0')
+		goto no_val;
+
+	switch (i) {
+	case RDST_IX_MAXDC:
+		/*
+		 * MTK modem does not return max_cids, string for this index
+		 * actually contains the maximum data bearer capability.
+		 */
+		if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK)
+			reply->max_cids = MTK_MODEM_MAX_CIDS;
+		else
+			reply->max_cids = val;
+		g_ril_append_print_buf(gril, "%s%u", print_buf, val);
+		break;
+	default:
+		goto no_val;
+	}
+
+	return;
+
+no_val:
+	g_ril_append_print_buf(gril, "%s%s", print_buf, str ? str : "(null)");
+}
+
+struct reply_data_reg_state *g_ril_reply_parse_data_reg_state(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	struct parcel_str_array *str_arr;
+	struct reply_data_reg_state *reply = NULL;
+	int i;
+
+	g_ril_init_parcel(message, &rilp);
+
+	str_arr = parcel_r_str_array(&rilp);
+	if (str_arr == NULL) {
+		ofono_error("%s: parse error for %s", __func__,
+				ril_request_id_to_string(message->req));
+		goto out;
+	}
+
+	reply =	g_try_malloc0(sizeof(*reply));
+	if (reply == NULL) {
+		ofono_error("%s: out of memory", __func__);
+		goto out;
+	}
+
+	reply->reg_state.status = -1;
+	reply->reg_state.lac = -1;
+	reply->reg_state.ci = -1;
+
+	g_ril_append_print_buf(gril, "{");
+
+	for (i = 0; i < str_arr->num_str; ++i) {
+		char *str = str_arr->str[i];
+
+		if (i > 0)
+			g_ril_append_print_buf(gril, "%s,", print_buf);
+
+		switch (i) {
+		case RST_IX_STATE: case RST_IX_LAC:
+		case RST_IX_CID:   case RST_IX_RAT:
+			set_reg_state(gril, &reply->reg_state, i, str);
+			break;
+		case RDST_IX_MAXDC:
+			set_data_reg_state(gril, reply, i, str);
+			break;
+		default:
+			g_ril_append_print_buf(gril, "%s%s", print_buf,
+						str ? str : "(null)");
+		}
+	}
+
+	g_ril_append_print_buf(gril, "%s}", print_buf);
+	g_ril_print_response(gril, message);
+
+	/* As a minimum we require a valid status string */
+	if (reply->reg_state.status == -1) {
+		ofono_error("%s: invalid status", __func__);
+		g_free(reply);
+		reply = NULL;
+	}
+
+out:
+	parcel_free_str_array(str_arr);
+
+	return reply;
+}
+
+void g_ril_reply_free_sim_io(struct reply_sim_io *reply)
+{
+	if (reply) {
+		g_free(reply->hex_response);
+		g_free(reply);
+	}
+}
+
+struct reply_sim_io *g_ril_reply_parse_sim_io(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	char *response = NULL;
+	struct reply_sim_io *reply;
+
+	/*
+	 * Minimum length of SIM_IO_Response is 12:
+	 * sw1 (int32)
+	 * sw2 (int32)
+	 * simResponse (string)
+	 */
+	if (message->buf_len < 12) {
+		ofono_error("Invalid SIM IO reply: size too small (< 12): %d ",
+			    (int) message->buf_len);
+		return NULL;
+	}
+
+	reply =	g_new0(struct reply_sim_io, 1);
+
+	g_ril_init_parcel(message, &rilp);
+	reply->sw1 = parcel_r_int32(&rilp);
+	reply->sw2 = parcel_r_int32(&rilp);
+
+	response = parcel_r_string(&rilp);
+
+	g_ril_append_print_buf(gril,
+				"(sw1=0x%.2X,sw2=0x%.2X,%s)",
+				reply->sw1,
+				reply->sw2,
+				response);
+	g_ril_print_response(gril, message);
+
+	if (rilp.malformed)
+		goto error;
+
+	if (response != NULL) {
+		reply->hex_response =
+			decode_hex(response, strlen(response),
+					(long *) &reply->hex_len, -1);
+		g_free(response);
+
+		if (reply->hex_response == NULL)
+			goto error;
+	}
+
+	return reply;
+
+error:
+	g_free(reply);
+
+	return NULL;
+}
+
+gchar *g_ril_reply_parse_imsi(GRil *gril, const struct ril_msg *message)
+{
+	struct parcel rilp;
+	gchar *imsi;
+
+	g_ril_init_parcel(message, &rilp);
+
+	imsi = parcel_r_string(&rilp);
+
+	g_ril_append_print_buf(gril, "{%s}", imsi ? imsi : "NULL");
+	g_ril_print_response(gril, message);
+
+	return imsi;
+}
+
+void g_ril_reply_free_sim_status(struct reply_sim_status *status)
+{
+	if (status) {
+		guint i;
+
+		for (i = 0; i < status->num_apps; i++) {
+			if (status->apps[i] != NULL) {
+				g_free(status->apps[i]->aid_str);
+				g_free(status->apps[i]->app_str);
+				g_free(status->apps[i]);
+			}
+		}
+
+		g_free(status);
+	}
+}
+
+struct reply_sim_status *g_ril_reply_parse_sim_status(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	unsigned int i;
+	struct reply_sim_status *status;
+
+	g_ril_append_print_buf(gril, "[%d,%04d]< %s",
+			g_ril_get_slot(gril), message->serial_no,
+			ril_request_id_to_string(message->req));
+
+	g_ril_init_parcel(message, &rilp);
+
+	status = g_new0(struct reply_sim_status, 1);
+
+	status->card_state = parcel_r_int32(&rilp);
+
+	/*
+	 * NOTE:
+	 *
+	 * The global pin_status is used for multi-application
+	 * UICC cards.  For example, there are SIM cards that
+	 * can be used in both GSM and CDMA phones.  Instead
+	 * of managed PINs for both applications, a global PIN
+	 * is set instead.  It's not clear at this point if
+	 * such SIM cards are supported by ofono or RILD.
+	 */
+
+	status->pin_state = parcel_r_int32(&rilp);
+	status->gsm_umts_index = parcel_r_int32(&rilp);
+	status->cdma_index = parcel_r_int32(&rilp);
+	status->ims_index = parcel_r_int32(&rilp);
+	status->num_apps = parcel_r_int32(&rilp);
+
+	if (rilp.malformed)
+		goto error;
+
+	g_ril_append_print_buf(gril,
+				"(card_state=%d,universal_pin_state=%d,"
+				"gsm_umts_index=%d,cdma_index=%d,"
+				"ims_index=%d, ",
+				status->card_state,
+				status->pin_state,
+				status->gsm_umts_index,
+				status->cdma_index,
+				status->ims_index);
+
+	if (status->card_state != RIL_CARDSTATE_PRESENT)
+		goto done;
+
+	if (status->num_apps > MAX_UICC_APPS) {
+		ofono_error("SIM error; too many apps: %d", status->num_apps);
+		status->num_apps = MAX_UICC_APPS;
+	}
+
+	for (i = 0; i < status->num_apps; i++) {
+		struct reply_sim_app *app;
+		DBG("processing app[%d]", i);
+		status->apps[i] = g_try_new0(struct reply_sim_app, 1);
+		app = status->apps[i];
+		if (app == NULL) {
+			ofono_error("Can't allocate app_data");
+			goto error;
+		}
+
+		app->app_type = parcel_r_int32(&rilp);
+		app->app_state = parcel_r_int32(&rilp);
+		app->perso_substate = parcel_r_int32(&rilp);
+
+		/*
+		 * TODO: we need a way to instruct parcel to skip
+		 * a string, without allocating memory...
+		 */
+		/* application ID (AID) */
+		app->aid_str = parcel_r_string(&rilp);
+		/* application label */
+		app->app_str = parcel_r_string(&rilp);
+
+		app->pin_replaced = parcel_r_int32(&rilp);
+		app->pin1_state = parcel_r_int32(&rilp);
+		app->pin2_state = parcel_r_int32(&rilp);
+
+		g_ril_append_print_buf(gril,
+					"%s[app_type=%d,app_state=%d,"
+					"perso_substate=%d,aid_ptr=%s,"
+					"app_label_ptr=%s,pin1_replaced=%d,"
+					"pin1=%d,pin2=%d],",
+					print_buf,
+					app->app_type,
+					app->app_state,
+					app->perso_substate,
+					app->aid_str ? app->aid_str : "NULL",
+					app->app_str ? app->app_str : "NULL",
+					app->pin_replaced,
+					app->pin1_state,
+					app->pin2_state);
+	}
+
+	if (rilp.malformed)
+		goto error;
+
+done:
+	g_ril_append_print_buf(gril, "%s}", print_buf);
+	g_ril_print_response(gril, message);
+
+	return status;
+
+error:
+	g_ril_reply_free_sim_status(status);
+
+	return NULL;
+}
+
+struct ofono_phone_number *g_ril_reply_parse_get_smsc_address(
+						GRil *gril,
+						const struct ril_msg *message)
+{
+	struct ofono_phone_number *sca;
+	struct parcel rilp;
+	char *number, *temp_buf;
+
+	sca = g_new0(struct ofono_phone_number, 1);
+	if (sca == NULL) {
+		ofono_error("%s Out of memory", __func__);
+		goto err_alloc;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	temp_buf = parcel_r_string(&rilp);
+	if (temp_buf == NULL) {
+		ofono_error("%s Cannot read SMSC address", __func__);
+		goto err_readsca;
+	}
+
+	/* RIL gives address in quotes */
+	number = strtok(temp_buf, "\"");
+	if (number == NULL || *number == '\0') {
+		ofono_error("%s Invalid SMSC address", __func__);
+		goto err_scaformat;
+	}
+
+	if (number[0] == '+') {
+		number = number + 1;
+		sca->type = OFONO_NUMBER_TYPE_INTERNATIONAL;
+	} else {
+		sca->type = OFONO_NUMBER_TYPE_UNKNOWN;
+	}
+
+	strncpy(sca->number, number, OFONO_MAX_PHONE_NUMBER_LENGTH);
+	sca->number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
+
+	g_ril_append_print_buf(gril, "{type=%d,number=%s}",
+				sca->type, sca->number);
+	g_ril_print_response(gril, message);
+
+	g_free(temp_buf);
+
+	return sca;
+
+err_scaformat:
+	g_free(temp_buf);
+err_readsca:
+	g_free(sca);
+err_alloc:
+	return NULL;
+}
+
+int g_ril_reply_parse_sms_response(GRil *gril, const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int error, mr;
+	char *ack_pdu;
+
+	/* Set up Parcel struct for proper parsing */
+	g_ril_init_parcel(message, &rilp);
+
+	/*
+	 * TP-Message-Reference for GSM/
+	 * BearerData MessageId for CDMA
+	 */
+	mr = parcel_r_int32(&rilp);
+	ack_pdu = parcel_r_string(&rilp);
+	error = parcel_r_int32(&rilp);
+
+	g_ril_append_print_buf(gril, "{%d,%s,%d}",
+				mr, ack_pdu, error);
+	g_ril_print_response(gril, message);
+
+	g_free(ack_pdu);
+
+	return mr;
+}
+
+static gint g_ril_call_compare(gconstpointer a, gconstpointer b)
+{
+	const struct ofono_call *ca = a;
+	const struct ofono_call *cb = b;
+
+	if (ca->id < cb->id)
+		return -1;
+
+	if (ca->id > cb->id)
+		return 1;
+
+	return 0;
+}
+
+GSList *g_ril_reply_parse_get_calls(GRil *gril, const struct ril_msg *message)
+{
+	struct ofono_call *call;
+	struct parcel rilp;
+	GSList *l = NULL;
+	int num, i;
+	gchar *number, *name;
+
+	g_ril_init_parcel(message, &rilp);
+
+	g_ril_append_print_buf(gril, "{");
+
+	/* maguro signals no calls with empty event data */
+	if (rilp.size < sizeof(int32_t))
+		goto no_calls;
+
+	/* Number of RIL_Call structs */
+	num = parcel_r_int32(&rilp);
+	for (i = 0; i < num; i++) {
+		call = g_try_new(struct ofono_call, 1);
+		if (call == NULL)
+			break;
+
+		ofono_call_init(call);
+		call->status = parcel_r_int32(&rilp);
+		call->id = parcel_r_int32(&rilp);
+		call->phone_number.type = parcel_r_int32(&rilp);
+		parcel_r_int32(&rilp); /* isMpty */
+		parcel_r_int32(&rilp); /* isMT */
+		parcel_r_int32(&rilp); /* als */
+		call->type = parcel_r_int32(&rilp); /* isVoice */
+		parcel_r_int32(&rilp); /* isVoicePrivacy */
+		number = parcel_r_string(&rilp);
+		if (number) {
+			strncpy(call->phone_number.number, number,
+				OFONO_MAX_PHONE_NUMBER_LENGTH);
+			g_free(number);
+		}
+
+		parcel_r_int32(&rilp); /* numberPresentation */
+		name = parcel_r_string(&rilp);
+		if (name) {
+			strncpy(call->name, name,
+				OFONO_MAX_CALLER_NAME_LENGTH);
+			g_free(name);
+		}
+
+		parcel_r_int32(&rilp); /* namePresentation */
+		parcel_r_int32(&rilp); /* uusInfo */
+
+		if (strlen(call->phone_number.number) > 0)
+			call->clip_validity = 0;
+		else
+			call->clip_validity = 2;
+
+		g_ril_append_print_buf(gril,
+					"%s [id=%d,status=%d,type=%d,"
+					"number=%s,name=%s]",
+					print_buf,
+					call->id, call->status, call->type,
+					call->phone_number.number, call->name);
+
+		l = g_slist_insert_sorted(l, call, g_ril_call_compare);
+	}
+
+no_calls:
+	g_ril_append_print_buf(gril, "%s}", print_buf);
+	g_ril_print_response(gril, message);
+
+	return l;
+}
+
+enum ofono_disconnect_reason g_ril_reply_parse_call_fail_cause(
+				GRil *gril, const struct ril_msg *message)
+{
+	enum ofono_disconnect_reason reason = OFONO_DISCONNECT_REASON_ERROR;
+	int last_cause = CALL_FAIL_ERROR_UNSPECIFIED;
+	struct parcel rilp;
+
+	g_ril_init_parcel(message, &rilp);
+
+	if (rilp.size < sizeof(int32_t))
+		ofono_error("%s: Parcel is too small", __func__);
+	else if (parcel_r_int32(&rilp) > 0)
+		last_cause = parcel_r_int32(&rilp);
+
+	if (last_cause == CALL_FAIL_NORMAL || last_cause == CALL_FAIL_BUSY)
+		reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
+
+	g_ril_append_print_buf(gril, "{%d}", last_cause);
+	g_ril_print_response(gril, message);
+
+	return reason;
+}
+
+int g_ril_reply_parse_get_mute(GRil *gril, const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int muted;
+
+	g_ril_init_parcel(message, &rilp);
+
+	/* skip length of int[] */
+	parcel_r_int32(&rilp);
+	muted = parcel_r_int32(&rilp);
+
+	g_ril_append_print_buf(gril, "{%d}", muted);
+	g_ril_print_response(gril, message);
+
+	return muted;
+
+}
+
+char *g_ril_reply_parse_baseband_version(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	char *version;
+
+	g_ril_init_parcel(message, &rilp);
+
+	version = parcel_r_string(&rilp);
+
+	g_ril_append_print_buf(gril, "{%s}", version);
+	g_ril_print_response(gril, message);
+
+	return version;
+}
+
+char *g_ril_reply_parse_get_imei(GRil *gril,
+					const struct ril_msg *message)
+{
+	struct parcel rilp;
+	char *imei;
+
+	g_ril_init_parcel(message, &rilp);
+
+	imei = parcel_r_string(&rilp);
+
+	g_ril_append_print_buf(gril, "{%s}", imei);
+	g_ril_print_response(gril, message);
+
+	return imei;
+}
+
+int g_ril_reply_parse_query_call_waiting(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int numint, enabled, cls;
+
+	g_ril_init_parcel(message, &rilp);
+
+	numint = parcel_r_int32(&rilp);
+	if (numint < 1) {
+		ofono_error("%s Wrong format", __func__);
+		goto error;
+	}
+
+	enabled = parcel_r_int32(&rilp);
+
+	if (enabled > 0)
+		cls = parcel_r_int32(&rilp);
+	else
+		cls = 0;
+
+	g_ril_append_print_buf(gril, "{%d,0x%x}", enabled, cls);
+	g_ril_print_response(gril, message);
+
+	return cls;
+
+error:
+	return -1;
+}
+
+int g_ril_reply_parse_query_clip(GRil *gril,
+					const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int clip_status, numint;
+
+	g_ril_init_parcel(message, &rilp);
+
+	numint = parcel_r_int32(&rilp);
+	if (numint != 1) {
+		ofono_error("%s Wrong format", __func__);
+		goto error;
+	}
+
+	clip_status = parcel_r_int32(&rilp);
+
+	g_ril_append_print_buf(gril, "{%d}", clip_status);
+	g_ril_print_response(gril, message);
+
+	return clip_status;
+
+error:
+	return -1;
+}
+
+void g_ril_reply_free_get_clir(struct reply_clir *rclir)
+{
+	g_free(rclir);
+}
+
+struct reply_clir *g_ril_reply_parse_get_clir(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	struct reply_clir *rclir;
+	int numint;
+
+	rclir = g_try_malloc0(sizeof(*rclir));
+	if (rclir == NULL) {
+		ofono_error("%s Out of memory", __func__);
+		goto error;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	/* Length */
+	numint = parcel_r_int32(&rilp);
+	if (numint != 2) {
+		ofono_error("%s Wrong format", __func__);
+		goto error;
+	}
+
+	/* Set HideCallerId property from network */
+	rclir->status = parcel_r_int32(&rilp);
+
+	/* State of the CLIR supplementary service in the network */
+	rclir->provisioned = parcel_r_int32(&rilp);
+
+	g_ril_append_print_buf(gril, "{%d,%d}",
+				rclir->status, rclir->provisioned);
+	g_ril_print_response(gril, message);
+
+	return rclir;
+
+error:
+	g_free(rclir);
+	return NULL;
+}
+
+struct ofono_call_forwarding_condition
+	*g_ril_reply_parse_query_call_fwd(GRil *gril,
+						const struct ril_msg *message,
+						unsigned int *list_size)
+{
+	struct ofono_call_forwarding_condition *list;
+	struct parcel rilp;
+	unsigned int i;
+
+	if (list_size == NULL) {
+		ofono_error("%s: list_size is NULL!", __func__);
+		goto error;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	if (rilp.size < sizeof(int32_t)) {
+		ofono_error("%s: malformed parcel, can't read num params",
+				__func__);
+		goto error;
+	}
+
+	*list_size = parcel_r_int32(&rilp);
+	if (*list_size == 0) {
+		/* not really an error; handled in caller */
+		goto error;
+	}
+
+	list = g_try_new0(struct ofono_call_forwarding_condition, *list_size);
+	if (list == NULL) {
+		ofono_error("%s: Out of memory", __func__);
+		goto error;
+	}
+
+	g_ril_append_print_buf(gril, "{");
+
+	for (i = 0; i < *list_size; i++) {
+		char *str;
+
+		list[i].status =  parcel_r_int32(&rilp);
+
+		parcel_r_int32(&rilp); /* skip reason */
+
+		list[i].cls = parcel_r_int32(&rilp);
+		list[i].phone_number.type = parcel_r_int32(&rilp);
+
+		str = parcel_r_string(&rilp);
+
+		if (str != NULL) {
+			strncpy(list[i].phone_number.number, str,
+				OFONO_MAX_PHONE_NUMBER_LENGTH);
+			g_free(str);
+
+			list[i].phone_number.number[
+				OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
+		}
+
+		list[i].time = parcel_r_int32(&rilp);
+
+		if (rilp.malformed) {
+			ofono_error("%s: malformed parcel", __func__);
+			g_free(list);
+			goto error;
+		}
+
+		g_ril_append_print_buf(gril, "%s [%d,%d,%d,%s,%d]",
+					print_buf,
+					list[i].status,
+					list[i].cls,
+					list[i].phone_number.type,
+					list[i].phone_number.number,
+					list[i].time);
+
+	}
+
+	g_ril_append_print_buf(gril, "%s}", print_buf);
+	g_ril_print_response(gril, message);
+
+	return list;
+
+error:
+	return NULL;
+}
+
+int g_ril_reply_parse_get_preferred_network_type(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int numint, parcel_net_type, net_type;
+
+	g_ril_init_parcel(message, &rilp);
+
+	numint = parcel_r_int32(&rilp);
+	if (numint != 1) {
+		ofono_error("%s: Wrong format", __func__);
+		goto error;
+	}
+
+	parcel_net_type = parcel_r_int32(&rilp);
+	net_type = parcel_net_type;
+
+	/* Try to translate special MTK settings */
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) {
+		switch (net_type) {
+		/* 4G preferred */
+		case MTK_PREF_NET_TYPE_LTE_GSM_WCDMA:
+		case MTK_PREF_NET_TYPE_LTE_GSM_WCDMA_MMDC:
+		case MTK_PREF_NET_TYPE_LTE_GSM_TYPE:
+		case MTK_PREF_NET_TYPE_LTE_GSM_MMDC_TYPE:
+			net_type = PREF_NET_TYPE_LTE_GSM_WCDMA;
+			break;
+		/* 3G or 2G preferred over LTE */
+		case MTK_PREF_NET_TYPE_GSM_WCDMA_LTE:
+		case MTK_PREF_NET_TYPE_GSM_WCDMA_LTE_MMDC:
+			net_type = PREF_NET_TYPE_GSM_WCDMA;
+			break;
+		}
+	}
+
+	if (net_type < 0 || net_type > PREF_NET_TYPE_LTE_ONLY) {
+		ofono_error("%s: unknown network type", __func__);
+		goto error;
+	}
+
+	if (rilp.malformed) {
+		ofono_error("%s: malformed parcel", __func__);
+		goto error;
+	}
+
+	g_ril_append_print_buf(gril, "{%d}", parcel_net_type);
+	g_ril_print_response(gril, message);
+
+	return net_type;
+
+error:
+	return -1;
+}
+
+int g_ril_reply_parse_query_facility_lock(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int status, numint;
+
+	g_ril_init_parcel(message, &rilp);
+
+	/* infineon returns two integers */
+	numint = parcel_r_int32(&rilp);
+	if (numint < 1) {
+		ofono_error("%s: wrong format", __func__);
+		goto error;
+	}
+
+	status = parcel_r_int32(&rilp);
+
+	if (rilp.malformed) {
+		ofono_error("%s: malformed parcel", __func__);
+		goto error;
+	}
+
+	g_ril_append_print_buf(gril, "{%d}", status);
+	g_ril_print_response(gril, message);
+
+	return status;
+
+error:
+	return -1;
+}
+
+int g_ril_reply_parse_set_facility_lock(GRil *gril,
+					const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int retries = -1, numint;
+
+	g_ril_init_parcel(message, &rilp);
+
+	/* mako reply has no payload for call barring */
+	if (parcel_data_avail(&rilp) == 0)
+		goto end;
+
+	numint = parcel_r_int32(&rilp);
+	if (numint != 1) {
+		ofono_error("%s: wrong format", __func__);
+		goto end;
+	}
+
+	retries = parcel_r_int32(&rilp);
+
+	if (rilp.malformed) {
+		ofono_error("%s: malformed parcel", __func__);
+		goto end;
+	}
+
+end:
+	g_ril_append_print_buf(gril, "{%d}", retries);
+	g_ril_print_response(gril, message);
+
+	return retries;
+}
+
+int *g_ril_reply_parse_retries(GRil *gril, const struct ril_msg *message,
+				enum ofono_sim_password_type passwd_type)
+{
+	struct parcel rilp;
+	int i, numint;
+	int *retries = g_try_malloc0(sizeof(int) * OFONO_SIM_PASSWORD_INVALID);
+
+	if (retries == NULL) {
+		ofono_error("%s: out of memory", __func__);
+		goto no_data;
+	}
+
+	for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; ++i)
+		retries[i] = -1;
+
+	g_ril_init_parcel(message, &rilp);
+
+	/* maguro/infineon: no data is returned */
+	if (parcel_data_avail(&rilp) == 0)
+		goto no_data;
+
+	numint = parcel_r_int32(&rilp);
+
+	switch (g_ril_vendor(gril)) {
+	case OFONO_RIL_VENDOR_AOSP:
+	case OFONO_RIL_VENDOR_QCOM_MSIM:
+		/*
+		 * The number of retries is valid only when a wrong password has
+		 * been introduced in Nexus 4. TODO: check Nexus 5 behaviour.
+		 */
+		if (message->error == RIL_E_PASSWORD_INCORRECT)
+			retries[passwd_type] = parcel_r_int32(&rilp);
+
+		g_ril_append_print_buf(gril, "{%d}", retries[passwd_type]);
+		break;
+	case OFONO_RIL_VENDOR_MTK:
+		/*
+		 * Some versions of MTK modem return just the retries for the
+		 * password just entered while others return the retries for all
+		 * passwords.
+		 */
+		if (numint == 1) {
+			retries[passwd_type] = parcel_r_int32(&rilp);
+
+			g_ril_append_print_buf(gril, "{%d}",
+							retries[passwd_type]);
+		} else if (numint == 4) {
+			retries[OFONO_SIM_PASSWORD_SIM_PIN] =
+							parcel_r_int32(&rilp);
+			retries[OFONO_SIM_PASSWORD_SIM_PIN2] =
+							parcel_r_int32(&rilp);
+			retries[OFONO_SIM_PASSWORD_SIM_PUK] =
+							parcel_r_int32(&rilp);
+			retries[OFONO_SIM_PASSWORD_SIM_PUK2] =
+							parcel_r_int32(&rilp);
+
+			g_ril_append_print_buf(gril,
+					"{pin %d, pin2 %d, puk %d, puk2 %d}",
+					retries[OFONO_SIM_PASSWORD_SIM_PIN],
+					retries[OFONO_SIM_PASSWORD_SIM_PIN2],
+					retries[OFONO_SIM_PASSWORD_SIM_PUK],
+					retries[OFONO_SIM_PASSWORD_SIM_PUK2]);
+		} else {
+			ofono_error("%s: wrong format", __func__);
+			goto no_data;
+		}
+		break;
+	case OFONO_RIL_VENDOR_INFINEON:
+		ofono_error("%s: infineon type should not arrive here",
+				__func__);
+		g_assert(FALSE);
+		break;
+	}
+
+	if (rilp.malformed) {
+		ofono_error("%s: malformed parcel", __func__);
+		goto no_data;
+	}
+
+	g_ril_print_response(gril, message);
+
+	return retries;
+
+no_data:
+	g_free(retries);
+
+	return NULL;
+}
+
+void g_ril_reply_free_oem_hook(struct reply_oem_hook *oem_hook)
+{
+	if (oem_hook) {
+		g_free(oem_hook->data);
+		g_free(oem_hook);
+	}
+}
+
+struct reply_oem_hook *g_ril_reply_oem_hook_raw(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct reply_oem_hook *reply = NULL;
+	struct parcel rilp;
+
+	reply = g_try_malloc0(sizeof(*reply));
+	if (reply == NULL) {
+		ofono_error("%s: out of memory", __func__);
+		goto end;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	reply->data = parcel_r_raw(&rilp, &(reply->length));
+
+	if (rilp.malformed) {
+		ofono_error("%s: malformed parcel", __func__);
+		g_ril_reply_free_oem_hook(reply);
+		reply = NULL;
+		goto end;
+	}
+
+	g_ril_append_print_buf(gril, "{%d", reply->length);
+
+	if (reply->data != NULL) {
+		char *hex_dump;
+		hex_dump = encode_hex(reply->data, reply->length, '\0');
+		g_ril_append_print_buf(gril, "%s,%s", print_buf, hex_dump);
+		g_free(hex_dump);
+	}
+
+	g_ril_append_print_buf(gril, "%s}", print_buf);
+	g_ril_print_response(gril, message);
+
+end:
+	return reply;
+}
+
+struct parcel_str_array *g_ril_reply_oem_hook_strings(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	struct parcel_str_array *str_arr;
+	int i;
+
+	g_ril_init_parcel(message, &rilp);
+
+	str_arr = parcel_r_str_array(&rilp);
+	if (str_arr == NULL) {
+		ofono_error("%s: no strings", __func__);
+		goto out;
+	}
+
+	g_ril_append_print_buf(gril, "{");
+
+	for (i = 0; i < str_arr->num_str; ++i) {
+		if (i + 1 == str_arr->num_str)
+			g_ril_append_print_buf(gril, "%s%s}", print_buf,
+						str_arr->str[i]);
+		else
+			g_ril_append_print_buf(gril, "%s%s, ", print_buf,
+						str_arr->str[i]);
+	}
+
+	g_ril_print_response(gril, message);
+
+out:
+	return str_arr;
+}
diff --git a/gril/grilreply.h b/gril/grilreply.h
new file mode 100644
index 0000000..b419762
--- /dev/null
+++ b/gril/grilreply.h
@@ -0,0 +1,185 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2014  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GRILREPLY_H
+#define __GRILREPLY_H
+
+#include <ofono/types.h>
+#include <ofono/sim.h>
+
+#include "gril.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct reply_operator {
+	char *lalpha;
+	char *salpha;
+	char *numeric;
+	char *status;
+	int tech;
+};
+
+struct reply_avail_ops {
+	guint num_ops;
+	GSList *list;
+};
+
+struct reply_reg_state {
+	int status;
+	int lac;
+	int ci;
+	int tech;
+};
+
+struct reply_data_reg_state {
+	struct reply_reg_state reg_state;
+	unsigned int max_cids;
+};
+
+struct reply_sim_io {
+	int sw1;
+	int sw2;
+	int hex_len;
+	unsigned char *hex_response;
+};
+
+#define MAX_UICC_APPS 16
+
+struct reply_sim_app {
+	guint app_type;
+	guint app_state;
+	guint perso_substate;
+	char *aid_str;
+	char *app_str;
+	guint pin_replaced;
+	guint pin1_state;
+	guint pin2_state;
+};
+
+struct reply_sim_status {
+	guint card_state;
+	guint pin_state;
+	guint gsm_umts_index;
+	guint cdma_index;
+	guint ims_index;
+	guint num_apps;
+	struct reply_sim_app *apps[MAX_UICC_APPS];
+};
+
+struct reply_clir {
+	int status;
+	int provisioned;
+};
+
+struct reply_oem_hook {
+	int length;
+	void *data;
+};
+
+void g_ril_reply_free_avail_ops(struct reply_avail_ops *reply);
+
+struct reply_avail_ops *g_ril_reply_parse_avail_ops(GRil *gril,
+						const struct ril_msg *message);
+void g_ril_reply_free_operator(struct reply_operator *reply);
+
+struct reply_operator *g_ril_reply_parse_operator(GRil *gril,
+						const struct ril_msg *message);
+
+void g_ril_reply_free_sim_io(struct reply_sim_io *reply);
+
+struct reply_sim_io *g_ril_reply_parse_sim_io(GRil *gril,
+						const struct ril_msg *message);
+
+gchar *g_ril_reply_parse_imsi(GRil *gril, const struct ril_msg *message);
+
+struct reply_reg_state *g_ril_reply_parse_voice_reg_state(GRil *gril,
+						const struct ril_msg *message);
+struct reply_data_reg_state *g_ril_reply_parse_data_reg_state(GRil *gril,
+						const struct ril_msg *message);
+
+void g_ril_reply_free_sim_status(struct reply_sim_status *status);
+
+struct reply_sim_status *g_ril_reply_parse_sim_status(GRil *gril,
+						const struct ril_msg *message);
+
+struct ofono_phone_number *g_ril_reply_parse_get_smsc_address(
+						GRil *gril,
+						const struct ril_msg *message);
+
+int g_ril_reply_parse_sms_response(GRil *gril, const struct ril_msg *message);
+
+GSList *g_ril_reply_parse_get_calls(GRil *gril, const struct ril_msg *message);
+
+enum ofono_disconnect_reason g_ril_reply_parse_call_fail_cause(
+				GRil *gril, const struct ril_msg *message);
+
+int g_ril_reply_parse_get_mute(GRil *gril, const struct ril_msg *message);
+
+char *g_ril_reply_parse_baseband_version(GRil *gril,
+						const struct ril_msg *message);
+
+char *g_ril_reply_parse_get_imei(GRil *gril,
+					const struct ril_msg *message);
+
+int g_ril_reply_parse_query_call_waiting(GRil *gril,
+						const struct ril_msg *message);
+
+int g_ril_reply_parse_query_clip(GRil *gril,
+					const struct ril_msg *message);
+
+void g_ril_reply_free_get_clir(struct reply_clir *rclir);
+
+struct reply_clir *g_ril_reply_parse_get_clir(GRil *gril,
+						const struct ril_msg *message);
+
+struct ofono_call_forwarding_condition
+	*g_ril_reply_parse_query_call_fwd(GRil *gril,
+						const struct ril_msg *message,
+						unsigned int *list_size);
+
+int g_ril_reply_parse_get_preferred_network_type(GRil *gril,
+						const struct ril_msg *message);
+
+int g_ril_reply_parse_query_facility_lock(GRil *gril,
+						const struct ril_msg *message);
+
+int g_ril_reply_parse_set_facility_lock(GRil *gril,
+					const struct ril_msg *message);
+
+int *g_ril_reply_parse_retries(GRil *gril, const struct ril_msg *message,
+				enum ofono_sim_password_type passwd_type);
+
+void g_ril_reply_free_oem_hook(struct reply_oem_hook *oem_hook);
+
+struct reply_oem_hook *g_ril_reply_oem_hook_raw(GRil *gril,
+						const struct ril_msg *message);
+
+struct parcel_str_array *g_ril_reply_oem_hook_strings(GRil *gril,
+						const struct ril_msg *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRILREPLY_H */
diff --git a/gril/grilrequest.c b/gril/grilrequest.c
new file mode 100644
index 0000000..3571c6b
--- /dev/null
+++ b/gril/grilrequest.c
@@ -0,0 +1,1161 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2014  Canonical Ltd.
+ *  Copyright (C) 2015 Ratchanan Srirattanamet.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs-context.h>
+
+#include "grilrequest.h"
+#include "simutil.h"
+#include "util.h"
+#include "common.h"
+
+/* DEACTIVATE_DATA_CALL request parameters */
+#define DEACTIVATE_DATA_CALL_NUM_PARAMS 2
+
+/* POWER request parameters */
+#define POWER_PARAMS 1
+
+/* SETUP_DATA_CALL_PARAMS request parameters */
+#define SETUP_DATA_CALL_PARAMS 7
+#define DATA_PROFILE_DEFAULT_STR "0"
+#define DATA_PROFILE_TETHERED_STR "1"
+#define DATA_PROFILE_IMS_STR "2"
+#define DATA_PROFILE_FOTA_STR "3"
+#define DATA_PROFILE_CBS_STR "4"
+#define DATA_PROFILE_OEM_BASE_STR "1000"
+#define DATA_PROFILE_MTK_MMS_STR "1001"
+
+/* SETUP_DATA_CALL_PARAMS reply parameters */
+#define MIN_DATA_CALL_REPLY_SIZE 36
+
+/* Commands defined for TS 27.007 +CRSM */
+#define CMD_READ_BINARY   176 /* 0xB0   */
+#define CMD_READ_RECORD   178 /* 0xB2   */
+#define CMD_GET_RESPONSE  192 /* 0xC0   */
+#define CMD_UPDATE_BINARY 214 /* 0xD6   */
+#define CMD_UPDATE_RECORD 220 /* 0xDC   */
+#define CMD_STATUS        242 /* 0xF2   */
+#define CMD_RETRIEVE_DATA 203 /* 0xCB   */
+#define CMD_SET_DATA      219 /* 0xDB   */
+
+/* FID/path of SIM/USIM root directory */
+#define ROOTMF ((char[]) {'\x3F', '\x00'})
+#define ROOTMF_SZ sizeof(ROOTMF)
+
+/* RIL_Request* parameter counts */
+#define GET_IMSI_NUM_PARAMS 1
+#define ENTER_SIM_PIN_PARAMS 2
+#define SET_FACILITY_LOCK_PARAMS 5
+#define ENTER_SIM_PUK_PARAMS 3
+#define CHANGE_SIM_PIN_PARAMS 3
+
+/* RIL_FACILITY_LOCK parameters */
+#define RIL_FACILITY_UNLOCK "0"
+#define RIL_FACILITY_LOCK "1"
+
+/* Call ID should not really be a big number */
+#define MAX_CID_DIGITS 3
+
+#define OFONO_EINVAL(error) do {		\
+	error->type = OFONO_ERROR_TYPE_FAILURE;	\
+	error->error = -EINVAL;			\
+} while (0)
+
+#define OFONO_NO_ERROR(error) do {			\
+	error->type = OFONO_ERROR_TYPE_NO_ERROR;	\
+	error->error = 0;				\
+} while (0)
+
+/*
+ * TODO:
+ *
+ * A potential future change here is to create a driver
+ * abstraction for each request/reply/event method, and a
+ * corresponding method to allow new per-message implementations
+ * to be registered.  This would allow PES to easily add code
+ * to quirk a particular RIL implementation.
+ *
+ * struct g_ril_messages_driver {
+ *	const char *name;
+ * };
+ *
+ */
+
+static gboolean set_path(GRil *ril, guint app_type,
+				struct parcel *rilp,
+				const int fileid, const guchar *path,
+				const guint path_len)
+{
+	unsigned char db_path[6] = { 0x00 };
+	unsigned char *comm_path = db_path;
+	char *hex_path = NULL;
+	int len = 0;
+
+	if (path_len > 0 && path_len < 7) {
+		memcpy(db_path, path, path_len);
+		len = path_len;
+	} else if (app_type == RIL_APPTYPE_USIM) {
+		len = sim_ef_db_get_path_3g(fileid, db_path);
+	} else if (app_type == RIL_APPTYPE_SIM) {
+		len = sim_ef_db_get_path_2g(fileid, db_path);
+	} else {
+		ofono_error("Unsupported app_type: 0%x", app_type);
+		return FALSE;
+	}
+
+	/*
+	 * db_path contains the ID of the MF, but MediaTek modems return an
+	 * error if we do not remove it. Other devices work the other way
+	 * around: they need the MF in the path. In fact MTK behaviour seem to
+	 * be the right one: to have the MF in the file is forbidden following
+	 * ETSI TS 102 221, section 8.4.2 (we are accessing the card in mode
+	 * "select by path from MF", see 3gpp 27.007, +CRSM).
+	 */
+	if (g_ril_vendor(ril) == OFONO_RIL_VENDOR_MTK && len >= (int) ROOTMF_SZ
+			&& memcmp(db_path, ROOTMF, ROOTMF_SZ) == 0) {
+		comm_path = db_path + ROOTMF_SZ;
+		len -= ROOTMF_SZ;
+	}
+
+	if (len > 0) {
+		hex_path = encode_hex(comm_path, len, 0);
+		parcel_w_string(rilp, hex_path);
+
+		g_ril_append_print_buf(ril,
+					"%spath=%s,",
+					print_buf,
+					hex_path);
+
+		g_free(hex_path);
+	} else {
+		/*
+		 * The only known case of this is EFPHASE_FILED (0x6FAE).
+		 * The ef_db table ( see /src/simutil.c ) entry for
+		 * EFPHASE contains a value of 0x0000 for it's
+		 * 'parent3g' member.  This causes a NULL path to
+		 * be returned.
+		 * (EF_PHASE does not exist for USIM)
+		 */
+		parcel_w_string(rilp, NULL);
+
+		g_ril_append_print_buf(ril,
+					"%spath=(null),",
+					print_buf);
+	}
+
+	return TRUE;
+}
+
+gboolean g_ril_request_deactivate_data_call(GRil *gril,
+				const struct req_deactivate_data_call *req,
+				struct parcel *rilp,
+				struct ofono_error *error)
+{
+	gchar *cid_str = NULL;
+	gchar *reason_str = NULL;
+
+	if (req->reason != RIL_DEACTIVATE_DATA_CALL_NO_REASON &&
+		req->reason != RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN) {
+		goto error;
+	}
+
+	parcel_init(rilp);
+	parcel_w_int32(rilp, DEACTIVATE_DATA_CALL_NUM_PARAMS);
+
+	cid_str = g_strdup_printf("%d", req->cid);
+	parcel_w_string(rilp, cid_str);
+
+	/*
+	 * TODO: airplane-mode; change reason to '1',
+	 * which means "radio power off".
+	 */
+	reason_str = g_strdup_printf("%d", req->reason);
+	parcel_w_string(rilp, reason_str);
+
+	g_ril_append_print_buf(gril, "(%s,%s)", cid_str, reason_str);
+
+	g_free(cid_str);
+	g_free(reason_str);
+
+	OFONO_NO_ERROR(error);
+	return TRUE;
+
+error:
+	OFONO_EINVAL(error);
+	return FALSE;
+}
+
+void g_ril_request_power(GRil *gril,
+				const gboolean power,
+				struct parcel *rilp)
+{
+	DBG("");
+
+	parcel_init(rilp);
+	parcel_w_int32(rilp, POWER_PARAMS);
+	parcel_w_int32(rilp, (int32_t) power);
+
+	g_ril_append_print_buf(gril, "(%d)", power);
+}
+
+void g_ril_request_set_net_select_manual(GRil *gril,
+					const char *mccmnc,
+					struct parcel *rilp)
+{
+	DBG("");
+
+	parcel_init(rilp);
+	parcel_w_string(rilp, mccmnc);
+
+	g_ril_append_print_buf(gril, "(%s)", mccmnc);
+}
+
+gboolean g_ril_request_setup_data_call(GRil *gril,
+					const struct req_setup_data_call *req,
+					struct parcel *rilp,
+					struct ofono_error *error)
+{
+	const gchar *protocol_str;
+	gchar *tech_str;
+	gchar *auth_str;
+	gchar *profile_str;
+	int num_param = SETUP_DATA_CALL_PARAMS;
+
+	DBG("");
+
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK)
+		num_param = SETUP_DATA_CALL_PARAMS + 1;
+
+	/*
+	 * Radio technology to use: 0-CDMA, 1-GSM/UMTS, 2...
+	 * values > 2 are (RADIO_TECH + 2)
+	 */
+	if (req->tech < 1 || req->tech > (RADIO_TECH_GSM + 2)) {
+		ofono_error("%s: Invalid tech value: %d",
+				__func__,
+				req->tech);
+		goto error;
+	}
+
+	/*
+	 * TODO(OEM): This code doesn't currently support
+	 * OEM data profiles.  If a use case exist, then
+	 * this code will need to be modified.
+	 */
+	switch (req->data_profile) {
+	case RIL_DATA_PROFILE_DEFAULT:
+		profile_str = DATA_PROFILE_DEFAULT_STR;
+		break;
+	case RIL_DATA_PROFILE_TETHERED:
+		profile_str = DATA_PROFILE_TETHERED_STR;
+		break;
+	case RIL_DATA_PROFILE_IMS:
+		profile_str = DATA_PROFILE_IMS_STR;
+		break;
+	case RIL_DATA_PROFILE_FOTA:
+		profile_str = DATA_PROFILE_FOTA_STR;
+		break;
+	case RIL_DATA_PROFILE_CBS:
+		profile_str = DATA_PROFILE_CBS_STR;
+		break;
+	case RIL_DATA_PROFILE_MTK_MMS:
+		if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) {
+			profile_str = DATA_PROFILE_MTK_MMS_STR;
+			break;
+		}
+	default:
+		ofono_error("%s, invalid data_profile value: %d",
+				__func__,
+				req->data_profile);
+		goto error;
+	}
+
+	if (req->apn == NULL)
+		goto error;
+
+	if (req->auth_type > RIL_AUTH_BOTH) {
+		ofono_error("%s: Invalid auth type: %d",
+				__func__,
+				req->auth_type);
+		goto error;
+	}
+
+	protocol_str = ril_ofono_protocol_to_ril_string(req->protocol);
+	if (protocol_str == NULL) {
+		ofono_error("%s: Invalid protocol: %d",
+				__func__,
+				req->protocol);
+		goto error;
+	}
+
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, num_param);
+
+	tech_str = g_strdup_printf("%d", req->tech);
+	parcel_w_string(rilp, tech_str);
+	parcel_w_string(rilp, profile_str);
+	parcel_w_string(rilp, req->apn);
+	parcel_w_string(rilp, req->username);
+	parcel_w_string(rilp, req->password);
+
+	auth_str = g_strdup_printf("%d", req->auth_type);
+	parcel_w_string(rilp, auth_str);
+	parcel_w_string(rilp, protocol_str);
+
+	g_ril_append_print_buf(gril,
+				"(%s,%s,%s,%s,%s,%s,%s",
+				tech_str,
+				profile_str,
+				req->apn,
+				req->username,
+				req->password,
+				auth_str,
+				protocol_str);
+
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) {
+		/* MTK request_cid parameter */
+		char cid_str[MAX_CID_DIGITS + 1];
+
+		snprintf(cid_str, sizeof(cid_str), "%u", req->req_cid);
+		parcel_w_string(rilp, cid_str);
+		g_ril_append_print_buf(gril, "%s,%s", print_buf, cid_str);
+	}
+
+	g_ril_append_print_buf(gril, "%s)", print_buf);
+
+	g_free(tech_str);
+	g_free(auth_str);
+
+	OFONO_NO_ERROR(error);
+	return TRUE;
+
+error:
+	OFONO_EINVAL(error);
+	return FALSE;
+}
+
+gboolean g_ril_request_sim_read_info(GRil *gril,
+					const struct req_sim_read_info *req,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, CMD_GET_RESPONSE);
+	parcel_w_int32(rilp, req->fileid);
+
+	g_ril_append_print_buf(gril,
+				"(cmd=0x%.2X,efid=0x%.4X,",
+				CMD_GET_RESPONSE,
+				req->fileid);
+
+	if (set_path(gril, req->app_type, rilp, req->fileid,
+			req->path, req->path_len) == FALSE)
+		goto error;
+
+	parcel_w_int32(rilp, 0);           /* P1 */
+	parcel_w_int32(rilp, 0);           /* P2 */
+
+	/*
+	 * TODO: review parameters values used by Android.
+	 * The values of P1-P3 in this code were based on
+	 * values used by the atmodem driver impl.
+	 *
+	 * NOTE:
+	 * GET_RESPONSE_EF_SIZE_BYTES == 15; !255
+	 */
+	parcel_w_int32(rilp, 15);         /* P3 - max length */
+	parcel_w_string(rilp, NULL);       /* data; only req'd for writes */
+	parcel_w_string(rilp, NULL);       /* pin2; only req'd for writes */
+	parcel_w_string(rilp, req->aid_str); /* AID (Application ID) */
+
+	/*
+	 * sessionId, specific to latest MTK modems (harmless for older ones).
+	 * It looks like this field selects one or another SIM application, but
+	 * we use only one at a time so using zero here seems safe.
+	 */
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK)
+		parcel_w_int32(rilp, 0);
+
+	return TRUE;
+
+error:
+	return FALSE;
+}
+
+gboolean g_ril_request_sim_read_binary(GRil *gril,
+					const struct req_sim_read_binary *req,
+					struct parcel *rilp)
+{
+	g_ril_append_print_buf(gril,
+				"(cmd=0x%.2X,efid=0x%.4X,",
+				CMD_READ_BINARY,
+				req->fileid);
+
+	parcel_init(rilp);
+	parcel_w_int32(rilp, CMD_READ_BINARY);
+	parcel_w_int32(rilp, req->fileid);
+
+	if (set_path(gril, req->app_type, rilp, req->fileid,
+			req->path, req->path_len) == FALSE)
+		goto error;
+
+	parcel_w_int32(rilp, (req->start >> 8));   /* P1 */
+	parcel_w_int32(rilp, (req->start & 0xff)); /* P2 */
+	parcel_w_int32(rilp, req->length);         /* P3 */
+	parcel_w_string(rilp, NULL);          /* data; only req'd for writes */
+	parcel_w_string(rilp, NULL);          /* pin2; only req'd for writes */
+	parcel_w_string(rilp, req->aid_str);
+
+	/* sessionId, specific to latest MTK modems (harmless for older ones) */
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK)
+		parcel_w_int32(rilp, 0);
+
+	return TRUE;
+
+error:
+	return FALSE;
+}
+
+gboolean g_ril_request_sim_read_record(GRil *gril,
+					const struct req_sim_read_record *req,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+	parcel_w_int32(rilp, CMD_READ_RECORD);
+	parcel_w_int32(rilp, req->fileid);
+
+	g_ril_append_print_buf(gril,
+				"(cmd=0x%.2X,efid=0x%.4X,",
+				CMD_READ_RECORD,
+				req->fileid);
+
+	if (set_path(gril, req->app_type, rilp, req->fileid,
+			req->path, req->path_len) == FALSE)
+		goto error;
+
+	parcel_w_int32(rilp, req->record);      /* P1 */
+	parcel_w_int32(rilp, 4);           /* P2 */
+	parcel_w_int32(rilp, req->length);      /* P3 */
+	parcel_w_string(rilp, NULL);       /* data; only req'd for writes */
+	parcel_w_string(rilp, NULL);       /* pin2; only req'd for writes */
+	parcel_w_string(rilp, req->aid_str); /* AID (Application ID) */
+
+	/* sessionId, specific to latest MTK modems (harmless for older ones) */
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK)
+		parcel_w_int32(rilp, 0);
+
+	return TRUE;
+
+error:
+	return FALSE;
+}
+
+gboolean g_ril_request_sim_write_binary(GRil *gril,
+					const struct req_sim_write_binary *req,
+					struct parcel *rilp)
+{
+	char *hex_data;
+	int p1, p2;
+
+	parcel_init(rilp);
+	parcel_w_int32(rilp, CMD_UPDATE_BINARY);
+	parcel_w_int32(rilp, req->fileid);
+
+	g_ril_append_print_buf(gril, "(cmd=0x%02X,efid=0x%04X,",
+				CMD_UPDATE_BINARY, req->fileid);
+
+	if (set_path(gril, req->app_type, rilp, req->fileid,
+			req->path, req->path_len) == FALSE)
+		goto error;
+
+	p1 = req->start >> 8;
+	p2 = req->start & 0xff;
+	hex_data = encode_hex(req->data, req->length, 0);
+
+	parcel_w_int32(rilp, p1);		/* P1 */
+	parcel_w_int32(rilp, p2);		/* P2 */
+	parcel_w_int32(rilp, req->length);	/* P3 (Lc) */
+	parcel_w_string(rilp, hex_data);	/* data */
+	parcel_w_string(rilp, NULL);		/* pin2; only for FDN/BDN */
+	parcel_w_string(rilp, req->aid_str);	/* AID (Application ID) */
+
+	/* sessionId, specific to latest MTK modems (harmless for older ones) */
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK)
+		parcel_w_int32(rilp, 0);
+
+	g_ril_append_print_buf(gril,
+				"%s%d,%d,%d,%s,pin2=(null),aid=%s)",
+				print_buf,
+				p1,
+				p2,
+				req->length,
+				hex_data,
+				req->aid_str);
+
+	g_free(hex_data);
+
+	return TRUE;
+
+error:
+	return FALSE;
+}
+
+static int get_sim_record_access_p2(enum req_record_access_mode mode)
+{
+	switch (mode) {
+	case GRIL_REC_ACCESS_MODE_CURRENT:
+		return 4;
+	case GRIL_REC_ACCESS_MODE_ABSOLUTE:
+		return 4;
+	case GRIL_REC_ACCESS_MODE_NEXT:
+		return 2;
+	case GRIL_REC_ACCESS_MODE_PREVIOUS:
+		return 3;
+	}
+
+	return -1;
+}
+
+gboolean g_ril_request_sim_write_record(GRil *gril,
+					const struct req_sim_write_record *req,
+					struct parcel *rilp)
+{
+	char *hex_data;
+	int p2;
+
+	parcel_init(rilp);
+	parcel_w_int32(rilp, CMD_UPDATE_RECORD);
+	parcel_w_int32(rilp, req->fileid);
+
+	g_ril_append_print_buf(gril, "(cmd=0x%02X,efid=0x%04X,",
+				CMD_UPDATE_RECORD, req->fileid);
+
+	if (set_path(gril, req->app_type, rilp, req->fileid,
+			req->path, req->path_len) == FALSE)
+		goto error;
+
+	p2 = get_sim_record_access_p2(req->mode);
+	hex_data = encode_hex(req->data, req->length, 0);
+
+	parcel_w_int32(rilp, req->record);	/* P1 */
+	parcel_w_int32(rilp, p2);		/* P2 (access mode) */
+	parcel_w_int32(rilp, req->length);	/* P3 (Lc) */
+	parcel_w_string(rilp, hex_data);	/* data */
+	parcel_w_string(rilp, NULL);		/* pin2; only for FDN/BDN */
+	parcel_w_string(rilp, req->aid_str);	/* AID (Application ID) */
+
+	/* sessionId, specific to latest MTK modems (harmless for older ones) */
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK)
+		parcel_w_int32(rilp, 0);
+
+	g_ril_append_print_buf(gril,
+				"%s%d,%d,%d,%s,pin2=(null),aid=%s)",
+				print_buf,
+				req->record,
+				p2,
+				req->length,
+				hex_data,
+				req->aid_str);
+
+	g_free(hex_data);
+
+	return TRUE;
+
+error:
+	return FALSE;
+}
+
+void g_ril_request_read_imsi(GRil *gril,
+				const gchar *aid_str,
+				struct parcel *rilp)
+{
+	parcel_init(rilp);
+	parcel_w_int32(rilp, GET_IMSI_NUM_PARAMS);
+	parcel_w_string(rilp, aid_str);
+
+	g_ril_append_print_buf(gril, "(%d,%s)", GET_IMSI_NUM_PARAMS, aid_str);
+}
+
+void g_ril_request_pin_send(GRil *gril,
+				const char *passwd,
+				const gchar *aid_str,
+				struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, ENTER_SIM_PIN_PARAMS);
+	parcel_w_string(rilp, passwd);
+	parcel_w_string(rilp, aid_str);
+
+	g_ril_append_print_buf(gril, "(%s,aid=%s)", passwd, aid_str);
+}
+
+gboolean g_ril_request_pin_change_state(GRil *gril,
+					const struct req_pin_change_state *req,
+					struct parcel *rilp)
+{
+	const char *lock_type;
+
+	/*
+	 * TODO: clean up the use of string literals &
+	 * the multiple g_ril_append_print_buf() calls
+	 * by using a table lookup as does the core sim code
+	 */
+	switch (req->passwd_type) {
+	case OFONO_SIM_PASSWORD_SIM_PIN:
+		g_ril_append_print_buf(gril, "(SC,");
+		lock_type = "SC";
+		break;
+	case OFONO_SIM_PASSWORD_PHSIM_PIN:
+		g_ril_append_print_buf(gril, "(PS,");
+		lock_type = "PS";
+		break;
+	case OFONO_SIM_PASSWORD_PHFSIM_PIN:
+		g_ril_append_print_buf(gril, "(PF,");
+		lock_type = "PF";
+		break;
+	case OFONO_SIM_PASSWORD_SIM_PIN2:
+		g_ril_append_print_buf(gril, "(P2,");
+		lock_type = "P2";
+		break;
+	case OFONO_SIM_PASSWORD_PHNET_PIN:
+		g_ril_append_print_buf(gril, "(PN,");
+		lock_type = "PN";
+		break;
+	case OFONO_SIM_PASSWORD_PHNETSUB_PIN:
+		g_ril_append_print_buf(gril, "(PU,");
+		lock_type = "PU";
+		break;
+	case OFONO_SIM_PASSWORD_PHSP_PIN:
+		g_ril_append_print_buf(gril, "(PP,");
+		lock_type = "PP";
+		break;
+	case OFONO_SIM_PASSWORD_PHCORP_PIN:
+		g_ril_append_print_buf(gril, "(PC,");
+		lock_type = "PC";
+		break;
+	default:
+		ofono_error("%s: Invalid password type: %d",
+				__func__,
+				req->passwd_type);
+		goto error;
+	}
+
+	parcel_init(rilp);
+	parcel_w_int32(rilp, SET_FACILITY_LOCK_PARAMS);
+
+	parcel_w_string(rilp, lock_type);
+
+	if (req->enable)
+		parcel_w_string(rilp, RIL_FACILITY_LOCK);
+	else
+		parcel_w_string(rilp, RIL_FACILITY_UNLOCK);
+
+	parcel_w_string(rilp, req->passwd);
+
+	/* TODO: make this a constant... */
+	parcel_w_string(rilp, "0");		/* class */
+
+	parcel_w_string(rilp, req->aid_str);
+
+	g_ril_append_print_buf(gril, "(%s,%d,%s,0,aid=%s)",
+				print_buf,
+				req->enable,
+				req->passwd,
+				req->aid_str);
+
+	return TRUE;
+
+error:
+	return FALSE;
+}
+
+void g_ril_request_pin_send_puk(GRil *gril,
+				const char *puk,
+				const char *passwd,
+				const gchar *aid_str,
+				struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, ENTER_SIM_PUK_PARAMS);
+	parcel_w_string(rilp, puk);
+	parcel_w_string(rilp, passwd);
+	parcel_w_string(rilp, aid_str);
+
+	g_ril_append_print_buf(gril, "(puk=%s,pin=%s,aid=%s)",
+				puk, passwd, aid_str);
+}
+
+void g_ril_request_change_passwd(GRil *gril,
+					const char *old_passwd,
+					const char *new_passwd,
+					const gchar *aid_str,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, CHANGE_SIM_PIN_PARAMS);
+	parcel_w_string(rilp, old_passwd);
+	parcel_w_string(rilp, new_passwd);
+	parcel_w_string(rilp, aid_str);
+
+	g_ril_append_print_buf(gril, "(old=%s,new=%s,aid=%s)",
+				old_passwd, new_passwd, aid_str);
+}
+
+void g_ril_request_sms_cmgs(GRil *gril,
+				const struct req_sms_cmgs *req,
+				struct parcel *rilp)
+{
+	int smsc_len;
+	char *tpdu;
+
+	parcel_init(rilp);
+	parcel_w_int32(rilp, 2);	/* Number of strings */
+
+	/*
+	 * SMSC address:
+	 *
+	 * smsc_len == 1, then zero-length SMSC was spec'd
+	 * RILD expects a NULL string in this case instead
+	 * of a zero-length string.
+	 */
+	smsc_len = req->pdu_len - req->tpdu_len;
+	/* TODO: encode SMSC & write to parcel */
+	if (smsc_len > 1)
+		ofono_error("SMSC address specified (smsc_len %d); "
+				"NOT-IMPLEMENTED", smsc_len);
+
+	parcel_w_string(rilp, NULL); /* SMSC address; NULL == default */
+
+	/*
+	 * TPDU:
+	 *
+	 * 'pdu' is a raw hexadecimal string
+	 *  encode_hex() turns it into an ASCII/hex UTF8 buffer
+	 *  parcel_w_string() encodes utf8 -> utf16
+	 */
+	tpdu = encode_hex(req->pdu + smsc_len, req->tpdu_len, 0);
+	parcel_w_string(rilp, tpdu);
+
+	g_ril_append_print_buf(gril, "(%s)", tpdu);
+
+	g_free(tpdu);
+}
+
+void g_ril_request_sms_acknowledge(GRil *gril,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+	parcel_w_int32(rilp, 2); /* Number of int32 values in array */
+	parcel_w_int32(rilp, 1); /* Successful receipt */
+	parcel_w_int32(rilp, 0); /* error code */
+
+	g_ril_append_print_buf(gril, "(1,0)");
+}
+
+void g_ril_request_set_smsc_address(GRil *gril,
+					const struct ofono_phone_number *sca,
+					struct parcel *rilp)
+{
+	char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 4];
+
+	if (sca->type == OFONO_NUMBER_TYPE_INTERNATIONAL)
+		snprintf(number, sizeof(number), "\"+%s\"", sca->number);
+	else
+		snprintf(number, sizeof(number), "\"%s\"", sca->number);
+
+	parcel_init(rilp);
+	parcel_w_string(rilp, number);
+
+	g_ril_append_print_buf(gril, "(%s)", number);
+}
+
+void g_ril_request_dial(GRil *gril,
+			const struct ofono_phone_number *ph,
+			enum ofono_clir_option clir,
+			struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	/* Number to dial */
+	parcel_w_string(rilp, phone_number_to_string(ph));
+	/* CLIR mode */
+	parcel_w_int32(rilp, clir);
+	/* USS, empty string */
+	/* TODO: Deal with USS properly */
+	parcel_w_int32(rilp, 0);
+	parcel_w_int32(rilp, 0);
+
+	g_ril_append_print_buf(gril, "(%s,%d,0,0)",
+				phone_number_to_string(ph),
+				clir);
+}
+
+void g_ril_request_hangup(GRil *gril,
+				unsigned call_id,
+				struct parcel *rilp)
+{
+	parcel_init(rilp);
+	parcel_w_int32(rilp, 1); /* Always 1 - AT+CHLD=1x */
+	parcel_w_int32(rilp, call_id);
+
+	g_ril_append_print_buf(gril, "(%u)", call_id);
+}
+
+void g_ril_request_dtmf(GRil *gril,
+			char dtmf_char,
+			struct parcel *rilp)
+{
+	char ril_dtmf[2];
+
+	parcel_init(rilp);
+	/* Ril wants just one character, but we need to send as string */
+	ril_dtmf[0] = dtmf_char;
+	ril_dtmf[1] = '\0';
+	parcel_w_string(rilp, ril_dtmf);
+
+	g_ril_append_print_buf(gril, "(%s)", ril_dtmf);
+}
+
+void g_ril_request_separate_conn(GRil *gril,
+					int call_id,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	/* Payload is an array that holds just one element */
+	parcel_w_int32(rilp, 1);
+	parcel_w_int32(rilp, call_id);
+
+	g_ril_append_print_buf(gril, "(%d)", call_id);
+}
+
+void g_ril_request_set_supp_svc_notif(GRil *gril,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+	parcel_w_int32(rilp, 1); /* size of array */
+	parcel_w_int32(rilp, 1); /* notifications enabled */
+
+	g_ril_append_print_buf(gril, "(1)");
+}
+
+void g_ril_request_set_mute(GRil *gril, int muted, struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, 1);
+	parcel_w_int32(rilp, muted);
+
+	g_ril_append_print_buf(gril, "(%d)", muted);
+}
+
+void g_ril_request_send_ussd(GRil *gril,
+				const char *ussd,
+				struct parcel *rilp)
+{
+	parcel_init(rilp);
+	parcel_w_string(rilp, ussd);
+
+	g_ril_append_print_buf(gril, "(%s)", ussd);
+}
+
+void g_ril_request_set_call_waiting(GRil *gril,
+					int enabled, int serviceclass,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, 2);	/* Number of params */
+	parcel_w_int32(rilp, enabled);	/* on/off */
+
+	/*
+	 * Modem seems to respond with error to all queries
+	 * or settings made with bearer class
+	 * BEARER_CLASS_DEFAULT. Design decision: If given
+	 * class is BEARER_CLASS_DEFAULT let's map it to
+	 * SERVICE_CLASS_VOICE effectively making it the
+	 * default bearer.
+	 */
+	if (serviceclass == BEARER_CLASS_DEFAULT)
+		serviceclass = BEARER_CLASS_VOICE;
+
+	parcel_w_int32(rilp, serviceclass);	/* Service class */
+
+	g_ril_append_print_buf(gril, "(%d, 0x%x)", enabled, serviceclass);
+}
+
+void g_ril_request_query_call_waiting(GRil *gril,
+					int serviceclass,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, 1);	/* Number of params */
+	/*
+	 * RILD expects service class to be 0 as certain carriers can reject the
+	 * query with specific service class
+	 */
+	parcel_w_int32(rilp, 0);
+
+	g_ril_append_print_buf(gril, "(0)");
+}
+
+void g_ril_request_set_clir(GRil *gril,
+				int mode,
+				struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, 1);	/* Number of params */
+	parcel_w_int32(rilp, mode);
+
+	g_ril_append_print_buf(gril, "(%d)", mode);
+}
+
+void g_ril_request_screen_state(GRil *gril,
+				int state,
+				struct parcel *rilp)
+{
+	parcel_init(rilp);
+	parcel_w_int32(rilp, 1);	/* Number of params */
+	parcel_w_int32(rilp, state);
+
+	g_ril_append_print_buf(gril, "(%d)", state);
+}
+
+void g_ril_request_call_fwd(GRil *gril,	const struct req_call_fwd *req,
+				struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, req->action);
+	parcel_w_int32(rilp, req->type);
+	parcel_w_int32(rilp, req->cls);
+
+	g_ril_append_print_buf(gril, "(type: %d cls: %d ", req->type, req->cls);
+
+	if (req->number != NULL) {
+		parcel_w_int32(rilp, req->number->type);
+		parcel_w_string(rilp, (char *) req->number->number);
+
+		g_ril_append_print_buf(gril, "%s number type: %d number: "
+					"%s time: %d) ", print_buf,
+					req->number->type, req->number->number,
+					req->time);
+	} else {
+		/*
+		 * The following values have no real meaning for
+		 * activation/deactivation/erasure actions, but
+		 * apparently rild expects them, so fields need to
+		 * be filled. Otherwise there is no response.
+		 */
+
+		parcel_w_int32(rilp, 0x81);		/* TOA unknown */
+		parcel_w_string(rilp, "1234567890");
+		g_ril_append_print_buf(gril, "%s number type: %d number: "
+					"%s time: %d) ", print_buf,
+					0x81, "1234567890",
+					req->time);
+
+	}
+
+	parcel_w_int32(rilp, req->time);
+}
+
+void g_ril_request_set_preferred_network_type(GRil *gril, int net_type,
+						struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, 1);	/* Number of params */
+	parcel_w_int32(rilp, net_type);
+
+	g_ril_append_print_buf(gril, "(%d)", net_type);
+}
+
+void g_ril_request_query_facility_lock(GRil *gril, const char *facility,
+					const char *password, int services,
+					struct parcel *rilp)
+{
+	char svcs_str[4];
+
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, 4);	/* # of strings */
+	parcel_w_string(rilp, facility);
+	parcel_w_string(rilp, password);
+	snprintf(svcs_str, sizeof(svcs_str), "%d", services);
+	parcel_w_string(rilp, svcs_str);
+	parcel_w_string(rilp, NULL);	/* AID (for FDN, not yet supported) */
+
+	g_ril_append_print_buf(gril, "(%s,%s,%s,(null))",
+				facility, password, svcs_str);
+}
+
+void g_ril_request_set_facility_lock(GRil *gril, const char *facility,
+					int enable, const char *passwd,
+					int services, struct parcel *rilp)
+{
+	char svcs_str[4];
+	const char *enable_str;
+
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, 5);	/* # of strings */
+	parcel_w_string(rilp, facility);
+	if (enable)
+		enable_str = "1";
+	else
+		enable_str = "0";
+	parcel_w_string(rilp, enable_str);
+	parcel_w_string(rilp, passwd);
+	snprintf(svcs_str, sizeof(svcs_str), "%d", services);
+	parcel_w_string(rilp, svcs_str);
+	parcel_w_string(rilp, NULL);	/* AID (for FDN, not yet supported) */
+
+	g_ril_append_print_buf(gril, "(%s,%s,%s,%s,(null))",
+				facility, enable_str, passwd, svcs_str);
+}
+
+void g_ril_request_change_barring_password(GRil *gril, const char *facility,
+						const char *old_passwd,
+						const char *new_passwd,
+						struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, 3);	/* # of strings */
+	parcel_w_string(rilp, facility);
+	parcel_w_string(rilp, old_passwd);
+	parcel_w_string(rilp, new_passwd);
+
+	g_ril_append_print_buf(gril, "(%s,%s,%s)",
+				facility, old_passwd, new_passwd);
+}
+
+void g_ril_request_oem_hook_raw(GRil *gril, const void *payload, size_t length,
+					struct parcel *rilp)
+{
+	char *hex_dump = NULL;
+
+	parcel_init(rilp);
+	parcel_w_raw(rilp, payload, length);
+
+	if (payload != NULL)
+		hex_dump = encode_hex(payload, length, '\0');
+
+	g_ril_append_print_buf(gril, "(%s)", hex_dump ? hex_dump : "(null)");
+	g_free(hex_dump);
+}
+
+void g_ril_request_oem_hook_strings(GRil *gril, const char **strs, int num_str,
+							struct parcel *rilp)
+{
+	int i;
+
+	parcel_init(rilp);
+	parcel_w_int32(rilp, num_str);
+
+	g_ril_append_print_buf(gril, "(");
+
+	for (i = 0; i < num_str; ++i) {
+		parcel_w_string(rilp, strs[i]);
+
+		if (i == num_str - 1)
+			g_ril_append_print_buf(gril, "%s%s)",
+							print_buf, strs[i]);
+		else
+			g_ril_append_print_buf(gril, "%s%s, ",
+							print_buf, strs[i]);
+	}
+}
+
+void g_ril_request_set_initial_attach_apn(GRil *gril, const char *apn,
+						int proto,
+						const char *user,
+						const char *passwd,
+						const char *mccmnc,
+						struct parcel *rilp)
+{
+	const char *proto_str;
+	const int auth_type = RIL_AUTH_ANY;
+
+	parcel_init(rilp);
+
+	parcel_w_string(rilp, apn);
+
+	proto_str = ril_ofono_protocol_to_ril_string(proto);
+	parcel_w_string(rilp, proto_str);
+
+	parcel_w_int32(rilp, auth_type);
+	parcel_w_string(rilp, user);
+	parcel_w_string(rilp, passwd);
+
+	g_ril_append_print_buf(gril, "(%s,%s,%s,%s,%s", apn, proto_str,
+				ril_authtype_to_string(auth_type),
+				user, passwd);
+
+	if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) {
+		parcel_w_string(rilp, mccmnc);
+		g_ril_append_print_buf(gril, "%s,%s)", print_buf, mccmnc);
+	} else {
+		g_ril_append_print_buf(gril, "%s)", print_buf);
+	}
+}
+
+void g_ril_request_set_uicc_subscription(GRil *gril, int slot_id,
+					int app_index,
+					int sub_id,
+					int sub_status,
+					struct parcel *rilp)
+{
+	parcel_init(rilp);
+
+	parcel_w_int32(rilp, slot_id);
+	parcel_w_int32(rilp, app_index);
+	parcel_w_int32(rilp, sub_id);
+	parcel_w_int32(rilp, sub_status);
+
+	g_ril_append_print_buf(gril, "(%d, %d, %d, %d(%s))",
+				slot_id,
+				app_index,
+				sub_id,
+				sub_status,
+				sub_status ? "ACTIVATE" : "DEACTIVATE");
+}
diff --git a/gril/grilrequest.h b/gril/grilrequest.h
new file mode 100644
index 0000000..a8ee38d
--- /dev/null
+++ b/gril/grilrequest.h
@@ -0,0 +1,293 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2014  Canonical Ltd.
+ *  Copyright (C) 2015 Ratchanan Srirattanamet.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GRILREQUEST_H
+#define __GRILREQUEST_H
+
+#include <ofono/types.h>
+#include <ofono/modem.h>
+#include <ofono/sim.h>
+
+#include "gril.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct req_call_fwd {
+	int action;
+	int type;
+	int cls;
+	const struct ofono_phone_number *number;
+	int time;
+};
+
+struct req_deactivate_data_call {
+	gint cid;
+	guint reason;
+};
+
+struct req_setup_data_call {
+	guint tech;
+	guint data_profile;
+	gchar *apn;
+	gchar *username;
+	gchar *password;
+	guint auth_type;
+	guint protocol;
+	unsigned req_cid;
+};
+
+struct req_sim_read_info {
+	guint app_type;
+	gchar *aid_str;
+	int fileid;
+	const unsigned char *path;
+	unsigned int path_len;
+};
+
+
+struct req_sim_read_binary {
+	guint app_type;
+	gchar *aid_str;
+	int fileid;
+	const unsigned char *path;
+	unsigned int path_len;
+	int start;
+	int length;
+};
+
+
+struct req_sim_read_record {
+	guint app_type;
+	gchar *aid_str;
+	int fileid;
+	const unsigned char *path;
+	unsigned int path_len;
+	int record;
+	int length;
+};
+
+struct req_sim_write_binary {
+	guint app_type;
+	gchar *aid_str;
+	int fileid;
+	const unsigned char *path;
+	unsigned int path_len;
+	int start;
+	int length;
+	const unsigned char *data;
+};
+
+enum req_record_access_mode {
+	GRIL_REC_ACCESS_MODE_CURRENT,
+	GRIL_REC_ACCESS_MODE_ABSOLUTE,
+	GRIL_REC_ACCESS_MODE_NEXT,
+	GRIL_REC_ACCESS_MODE_PREVIOUS,
+};
+
+struct req_sim_write_record {
+	guint app_type;
+	gchar *aid_str;
+	int fileid;
+	const unsigned char *path;
+	unsigned int path_len;
+	enum req_record_access_mode mode;
+	int record;
+	int length;
+	const unsigned char *data;
+};
+
+struct req_pin_change_state {
+	const gchar *aid_str;
+	enum ofono_sim_password_type passwd_type;
+	int enable;
+	const char *passwd;
+};
+
+struct req_sms_cmgs {
+	const unsigned char *pdu;
+	int pdu_len;
+	int tpdu_len;
+};
+
+gboolean g_ril_request_deactivate_data_call(GRil *gril,
+				const struct req_deactivate_data_call *req,
+				struct parcel *rilp,
+				struct ofono_error *error);
+
+void g_ril_request_power(GRil *gril,
+				gboolean power,
+				struct parcel *rilp);
+
+void g_ril_request_set_net_select_manual(GRil *gril,
+					const char *mccmnc,
+					struct parcel *rilp);
+
+gboolean g_ril_request_setup_data_call(GRil *gril,
+					const struct req_setup_data_call *req,
+					struct parcel *rilp,
+					struct ofono_error *error);
+
+gboolean g_ril_request_sim_read_info(GRil *gril,
+					const struct req_sim_read_info *req,
+					struct parcel *rilp);
+
+gboolean g_ril_request_sim_read_binary(GRil *gril,
+					const struct req_sim_read_binary *req,
+					struct parcel *rilp);
+
+gboolean g_ril_request_sim_read_record(GRil *gril,
+					const struct req_sim_read_record *req,
+					struct parcel *rilp);
+
+gboolean g_ril_request_sim_write_binary(GRil *gril,
+					const struct req_sim_write_binary *req,
+					struct parcel *rilp);
+
+gboolean g_ril_request_sim_write_record(GRil *gril,
+					const struct req_sim_write_record *req,
+					struct parcel *rilp);
+
+void g_ril_request_read_imsi(GRil *gril,
+				const gchar *aid_str,
+				struct parcel *rilp);
+
+void g_ril_request_pin_send(GRil *gril,
+				const char *passwd,
+				const gchar *aid_str,
+				struct parcel *rilp);
+
+gboolean g_ril_request_pin_change_state(GRil *gril,
+					const struct req_pin_change_state *req,
+					struct parcel *rilp);
+
+void g_ril_request_pin_send_puk(GRil *gril,
+				const char *puk,
+				const char *passwd,
+				const gchar *aid_str,
+				struct parcel *rilp);
+
+void g_ril_request_change_passwd(GRil *gril,
+					const char *old_passwd,
+					const char *new_passwd,
+					const gchar *aid_str,
+					struct parcel *rilp);
+
+void g_ril_request_sms_cmgs(GRil *gril,
+				const struct req_sms_cmgs *req,
+				struct parcel *rilp);
+
+void g_ril_request_sms_acknowledge(GRil *gril, struct parcel *rilp);
+
+void g_ril_request_set_smsc_address(GRil *gril,
+					const struct ofono_phone_number *sca,
+					struct parcel *rilp);
+
+void g_ril_request_dial(GRil *gril,
+			const struct ofono_phone_number *ph,
+			enum ofono_clir_option clir,
+			struct parcel *rilp);
+
+void g_ril_request_hangup(GRil *gril,
+				unsigned call_id,
+				struct parcel *rilp);
+
+void g_ril_request_dtmf(GRil *gril,
+			char dtmf_char,
+			struct parcel *rilp);
+
+void g_ril_request_separate_conn(GRil *gril,
+					int call_id,
+					struct parcel *rilp);
+
+void g_ril_request_set_supp_svc_notif(GRil *gril,
+					struct parcel *rilp);
+
+void g_ril_request_set_mute(GRil *gril,
+				int muted,
+				struct parcel *rilp);
+
+void g_ril_request_send_ussd(GRil *gril,
+				const char *ussd,
+				struct parcel *rilp);
+
+void g_ril_request_set_call_waiting(GRil *gril,
+					int enabled, int serviceclass,
+					struct parcel *rilp);
+
+void g_ril_request_query_call_waiting(GRil *gril,
+					int serviceclass,
+					struct parcel *rilp);
+
+void g_ril_request_set_clir(GRil *gril,
+				int mode,
+				struct parcel *rilp);
+
+void g_ril_request_screen_state(GRil *gril,
+				int state,
+				struct parcel *rilp);
+
+void g_ril_request_call_fwd(GRil *gril, const struct req_call_fwd *req,
+				struct parcel *rilp);
+
+void g_ril_request_set_preferred_network_type(GRil *gril, int net_type,
+						struct parcel *rilp);
+
+void g_ril_request_query_facility_lock(GRil *gril, const char *facility,
+					const char *password, int services,
+					struct parcel *rilp);
+
+void g_ril_request_set_facility_lock(GRil *gril, const char *facility,
+					int enable, const char *passwd,
+					int services, struct parcel *rilp);
+
+void g_ril_request_change_barring_password(GRil *gril, const char *facility,
+						const char *old_passwd,
+						const char *new_passwd,
+						struct parcel *rilp);
+
+void g_ril_request_oem_hook_raw(GRil *gril, const void *payload, size_t length,
+					struct parcel *rilp);
+
+void g_ril_request_oem_hook_strings(GRil *gril, const char **strs, int num_str,
+							struct parcel *rilp);
+
+void g_ril_request_set_initial_attach_apn(GRil *gril, const char *apn,
+						int proto,
+						const char *user,
+						const char *passwd,
+						const char *mccmnc,
+						struct parcel *rilp);
+
+void g_ril_request_set_uicc_subscription(GRil *gril, int slot_id,
+						int app_index,
+						int sub_id,
+						int sub_status,
+						struct parcel *rilp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRILREQUEST_H */
diff --git a/gril/grilunsol.c b/gril/grilunsol.c
new file mode 100644
index 0000000..9fd8900
--- /dev/null
+++ b/gril/grilunsol.c
@@ -0,0 +1,638 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2013  Canonical Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs-context.h>
+#include "util.h"
+
+#include "common.h"
+#include "grilunsol.h"
+
+/* Minimum size is two int32s version/number of calls */
+#define MIN_DATA_CALL_LIST_SIZE 8
+
+/*
+ * Minimum NITZ is: 'yy/mm/dd,hh:mm:ss'
+ * TZ '(+/-)tz,dt' are optional
+ */
+#define MIN_NITZ_SIZE 17
+
+static gint data_call_compare(gconstpointer a, gconstpointer b)
+{
+	const struct ril_data_call *ca = a;
+	const struct ril_data_call *cb = b;
+
+	if (ca->cid < cb->cid)
+		return -1;
+
+	if (ca->cid > cb->cid)
+		return 1;
+
+	return 0;
+}
+
+static void free_data_call(gpointer data, gpointer user_data)
+{
+	struct ril_data_call *call = data;
+
+	if (call) {
+		g_free(call->ifname);
+		g_free(call->ip_addr);
+		g_free(call->dns_addrs);
+		g_free(call->gateways);
+		g_free(call);
+	}
+}
+
+void g_ril_unsol_free_data_call_list(struct ril_data_call_list *call_list)
+{
+	if (call_list) {
+		g_slist_foreach(call_list->calls, (GFunc) free_data_call, NULL);
+		g_slist_free(call_list->calls);
+		g_free(call_list);
+	}
+}
+
+static gboolean handle_settings(struct ril_data_call *call, char *type,
+				char *ifname, char *raw_ip_addrs,
+				char *raw_dns, char *raw_gws)
+{
+	gboolean result = FALSE;
+	int protocol;
+	char **dns_addrs = NULL, **gateways = NULL;
+	char **ip_addrs = NULL, **split_ip_addr = NULL;
+
+	protocol = ril_protocol_string_to_ofono_protocol(type);
+	if (protocol < 0) {
+		ofono_error("%s: invalid type(protocol) specified: %s",
+				__func__, type);
+		goto done;
+	}
+
+	if (ifname == NULL || strlen(ifname) == 0) {
+		ofono_error("%s: no interface specified: %s",
+				__func__, ifname);
+		goto done;
+	}
+
+	/* Split DNS addresses */
+	if (raw_dns)
+		dns_addrs = g_strsplit(raw_dns, " ", 3);
+
+	/*
+	 * RILD can return multiple addresses; oFono only supports
+	 * setting a single IPv4 gateway.
+	 */
+	if (raw_gws)
+		gateways = g_strsplit(raw_gws, " ", 3);
+
+	if (gateways == NULL || g_strv_length(gateways) == 0) {
+		ofono_error("%s: no gateways: %s", __func__, raw_gws);
+		goto done;
+	}
+
+	/* TODO:
+	 * RILD can return multiple addresses; oFono only supports
+	 * setting a single IPv4 address.  At this time, we only
+	 * use the first address.  It's possible that a RIL may
+	 * just specify the end-points of the point-to-point
+	 * connection, in which case this code will need to
+	 * changed to handle such a device.
+	 *
+	 * For now split into a maximum of three, and only use
+	 * the first address for the remaining operations.
+	 */
+	if (raw_ip_addrs)
+		ip_addrs = g_strsplit(raw_ip_addrs, " ", 3);
+
+	if (ip_addrs == NULL || g_strv_length(ip_addrs) == 0) {
+		ofono_error("%s: no IP address: %s", __func__, raw_ip_addrs);
+		goto done;
+	}
+
+	DBG("num ip addrs is: %d", g_strv_length(ip_addrs));
+
+	if (g_strv_length(ip_addrs) > 1)
+		ofono_warn("%s: more than one IP addr returned: %s", __func__,
+				raw_ip_addrs);
+	/*
+	 * Note - the address may optionally include a prefix size
+	 * ( Eg. "/30" ).  As this confuses NetworkManager, we
+	 * explicitly strip any prefix after calculating the netmask.
+	 */
+	split_ip_addr = g_strsplit(ip_addrs[0], "/", 2);
+
+	if (split_ip_addr == NULL || g_strv_length(split_ip_addr) == 0) {
+		ofono_error("%s: invalid IP address field returned: %s",
+				__func__, ip_addrs[0]);
+		goto done;
+	}
+
+	call->protocol = protocol;
+	call->ifname = g_strdup(ifname);
+	call->ip_addr = g_strdup(split_ip_addr[0]);
+	call->dns_addrs = g_strdupv(dns_addrs);
+	call->gateways = g_strdupv(gateways);
+
+	result = TRUE;
+
+done:
+	if (dns_addrs)
+		g_strfreev(dns_addrs);
+
+	if (gateways)
+		g_strfreev(gateways);
+
+	if (ip_addrs)
+		g_strfreev(ip_addrs);
+
+	if (split_ip_addr)
+		g_strfreev(split_ip_addr);
+
+
+	return result;
+}
+
+/*
+ * This function handles RIL_UNSOL_DATA_CALL_LIST_CHANGED messages,
+ * as well as RIL_REQUEST_DATA_CALL_LIST/SETUP_DATA_CALL replies, as
+ * all have the same payload.
+ */
+struct ril_data_call_list *g_ril_unsol_parse_data_call_list(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct ril_data_call *call;
+	struct parcel rilp;
+	struct ril_data_call_list *reply = NULL;
+	unsigned int active, cid, i, num_calls, retry, status;
+	char *type = NULL, *ifname = NULL, *raw_addrs = NULL;
+	char *raw_dns = NULL, *raw_gws = NULL;
+
+	DBG("");
+
+	/* Can happen for RIL_REQUEST_DATA_CALL_LIST replies */
+	if (message->buf_len < MIN_DATA_CALL_LIST_SIZE) {
+		if (message->req == RIL_REQUEST_SETUP_DATA_CALL) {
+			ofono_error("%s: message too small: %d",
+					__func__,
+					(int) message->buf_len);
+			goto error;
+		} else {
+			g_ril_append_print_buf(gril, "{");
+			goto done;
+		}
+	}
+
+	reply = g_try_new0(struct ril_data_call_list, 1);
+	if (reply == NULL) {
+		ofono_error("%s: out of memory", __func__);
+		goto error;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	/*
+	 * ril.h documents the reply to a RIL_REQUEST_DATA_CALL_LIST
+	 * as being an array of  RIL_Data_Call_Response_v6 structs,
+	 * however in reality, the response also includes a version
+	 * to start.
+	 */
+	reply->version = parcel_r_int32(&rilp);
+	num_calls = parcel_r_int32(&rilp);
+
+	g_ril_append_print_buf(gril,
+				"{version=%d,num=%d",
+				reply->version,
+				num_calls);
+
+	for (i = 0; i < num_calls; i++) {
+		status = parcel_r_int32(&rilp);
+		retry = parcel_r_int32(&rilp);          /* ignore */
+		cid = parcel_r_int32(&rilp);
+		active = parcel_r_int32(&rilp);
+		type = parcel_r_string(&rilp);
+		ifname = parcel_r_string(&rilp);
+		raw_addrs = parcel_r_string(&rilp);
+		raw_dns = parcel_r_string(&rilp);
+		raw_gws = parcel_r_string(&rilp);
+
+		/* malformed check */
+		if (rilp.malformed) {
+			ofono_error("%s: malformed parcel received", __func__);
+			goto error;
+		}
+
+		g_ril_append_print_buf(gril,
+					"%s [status=%d,retry=%d,cid=%d,"
+					"active=%d,type=%s,ifname=%s,"
+					"address=%s,dns=%s,gateways=%s]",
+					print_buf,
+					status,
+					retry,
+					cid,
+					active,
+					type,
+					ifname,
+					raw_addrs,
+					raw_dns,
+					raw_gws);
+
+		call = g_try_new0(struct ril_data_call, 1);
+		if (call == NULL) {
+			ofono_error("%s: out of memory", __func__);
+			goto error;
+		}
+
+		call->status = status;
+		call->cid = cid;
+		call->active = active;
+
+		if (message->req == RIL_REQUEST_SETUP_DATA_CALL &&
+			status == PDP_FAIL_NONE &&
+			handle_settings(call, type, ifname, raw_addrs,
+					raw_dns, raw_gws) == FALSE)
+			goto error;
+
+		g_free(type);
+		g_free(ifname);
+		g_free(raw_addrs);
+		g_free(raw_dns);
+		g_free(raw_gws);
+
+		reply->calls =
+			g_slist_insert_sorted(reply->calls, call,
+						data_call_compare);
+	}
+
+done:
+	g_ril_append_print_buf(gril, "%s}", print_buf);
+
+	if (message->unsolicited)
+		g_ril_print_unsol(gril, message);
+	else
+		g_ril_print_response(gril, message);
+
+	return reply;
+
+error:
+	g_free(type);
+	g_free(ifname);
+	g_free(raw_addrs);
+	g_free(raw_dns);
+	g_free(raw_gws);
+	g_ril_unsol_free_data_call_list(reply);
+
+	return NULL;
+}
+
+char *g_ril_unsol_parse_nitz(GRil *gril, const struct ril_msg *message)
+{
+	struct parcel rilp;
+	gchar *nitz = NULL;
+
+	DBG("");
+
+	if (message->buf_len < MIN_NITZ_SIZE) {
+		ofono_error("%s: NITZ too small: %d",
+				__func__,
+				(int) message->buf_len);
+		goto error;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	nitz = parcel_r_string(&rilp);
+
+	g_ril_append_print_buf(gril, "(%s)", nitz);
+	g_ril_print_unsol(gril, message);
+
+error:
+	return nitz;
+}
+
+void g_ril_unsol_free_sms_data(struct unsol_sms_data *unsol)
+{
+	if (unsol != NULL) {
+		g_free(unsol->data);
+		g_free(unsol);
+	}
+}
+
+struct unsol_sms_data *g_ril_unsol_parse_new_sms(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	char *ril_pdu;
+	size_t ril_pdu_len;
+	struct unsol_sms_data *sms_data;
+
+	sms_data = g_new0(struct unsol_sms_data, 1);
+	if (sms_data == NULL) {
+		ofono_error("%s out of memory", __func__);
+		goto error;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	ril_pdu = parcel_r_string(&rilp);
+	if (ril_pdu == NULL) {
+		ofono_error("%s Unable to parse notification", __func__);
+		goto error;
+	}
+
+	ril_pdu_len = strlen(ril_pdu);
+
+	sms_data->data = decode_hex(ril_pdu, ril_pdu_len,
+					&sms_data->length, -1);
+	if (sms_data->data == NULL) {
+		ofono_error("%s Unable to decode notification", __func__);
+		goto error_dec;
+	}
+
+	g_ril_append_print_buf(gril, "{%s}", ril_pdu);
+	g_ril_print_unsol(gril, message);
+
+	g_free(ril_pdu);
+
+	return sms_data;
+
+error_dec:
+	g_free(ril_pdu);
+error:
+	g_ril_unsol_free_sms_data(sms_data);
+	return NULL;
+}
+
+int g_ril_unsol_parse_radio_state_changed(GRil *gril,
+						const struct ril_msg *message)
+{
+	struct parcel rilp;
+	int radio_state;
+
+	g_ril_init_parcel(message, &rilp);
+
+	radio_state = parcel_r_int32(&rilp);
+
+	if (rilp.malformed) {
+		ofono_error("%s: malformed parcel received", __func__);
+		radio_state = -1;
+	}
+
+	g_ril_append_print_buf(gril, "(state: %s)",
+				ril_radio_state_to_string(radio_state));
+
+	g_ril_print_unsol(gril, message);
+
+	return radio_state;
+}
+
+/*
+ * This function makes a similar processing to was is done by validateInput()
+ * and getLteLevel() in $AOSP/frameworks/base/telephony/java/android/telephony/
+ * SignalStrength.java. The main difference is that we linearly transform the
+ * ranges to ofono's one, while AOSP gives number of bars in a non-linear way
+ * (bins for each bar have different size). We rely on the indicator to obtain
+ * a translation to bars that makes sense for humans.
+ */
+static int get_lte_strength(int signal, int rsrp, int rssnr)
+{
+	int s_rsrp = -1, s_rssnr = -1, s_signal = -1;
+
+	/*
+	 * The range of signal is specified to be [0, 31] by ril.h, but the code
+	 * in SignalStrength.java contradicts this: valid values are (0-63, 99)
+	 * as defined in TS 36.331 for E-UTRA rssi.
+	 */
+	signal = (signal >= 0 && signal <= 63) ? signal : INT_MAX;
+	rsrp = (rsrp >= 44 && rsrp <= 140) ? -rsrp : INT_MAX;
+	rssnr = (rssnr >= -200 && rssnr <= 300) ? rssnr : INT_MAX;
+
+	/* Linearly transform [-140, -44] to [0, 100] */
+	if (rsrp != INT_MAX)
+		s_rsrp = (25 * rsrp + 3500) / 24;
+
+	/* Linearly transform [-200, 300] to [0, 100] */
+	if (rssnr != INT_MAX)
+		s_rssnr = (rssnr + 200) / 5;
+
+	if (s_rsrp != -1 && s_rssnr != -1)
+		return s_rsrp < s_rssnr ? s_rsrp : s_rssnr;
+
+	if (s_rssnr != -1)
+		return s_rssnr;
+
+	if (s_rsrp != -1)
+		return s_rsrp;
+
+	/* Linearly transform [0, 63] to [0, 100] */
+	if (signal != INT_MAX)
+		s_signal = (100 * signal) / 63;
+
+	return s_signal;
+}
+
+/*
+ * Comments to get_lte_strength() apply here also, changing getLteLevel() with
+ * getGsmLevel(). The atmodem driver does exactly the same transformation with
+ * the rssi from AT+CSQ command.
+ */
+static int get_gsm_strength(int signal)
+{
+	/* Checking the range contemplates also the case signal=99 (invalid) */
+	if (signal >= 0 && signal <= 31)
+		return (signal * 100) / 31;
+	else
+		return -1;
+}
+
+int g_ril_unsol_parse_signal_strength(GRil *gril, const struct ril_msg *message,
+					int ril_tech)
+{
+	struct parcel rilp;
+	int gw_sigstr, gw_signal, cdma_dbm, evdo_dbm;
+	int lte_sigstr = -1, lte_rsrp = -1, lte_rssnr = -1;
+	int lte_signal;
+	int signal;
+
+	g_ril_init_parcel(message, &rilp);
+
+	/* RIL_SignalStrength_v5 */
+	/* GW_SignalStrength */
+	gw_sigstr = parcel_r_int32(&rilp);
+	gw_signal = get_gsm_strength(gw_sigstr);
+	parcel_r_int32(&rilp); /* bitErrorRate */
+
+	/*
+	 * CDMA/EVDO values are not processed as CDMA is not supported
+	 */
+
+	/* CDMA_SignalStrength */
+	cdma_dbm = parcel_r_int32(&rilp);
+	parcel_r_int32(&rilp); /* ecio */
+
+	/* EVDO_SignalStrength */
+	evdo_dbm = parcel_r_int32(&rilp);
+	parcel_r_int32(&rilp); /* ecio */
+	parcel_r_int32(&rilp); /* signalNoiseRatio */
+
+	/* Present only for RIL_SignalStrength_v6 or newer */
+	if (parcel_data_avail(&rilp) > 0) {
+		/* LTE_SignalStrength */
+		lte_sigstr = parcel_r_int32(&rilp);
+		lte_rsrp = parcel_r_int32(&rilp);
+		parcel_r_int32(&rilp); /* rsrq */
+		lte_rssnr = parcel_r_int32(&rilp);
+		parcel_r_int32(&rilp); /* cqi */
+		lte_signal = get_lte_strength(lte_sigstr, lte_rsrp, lte_rssnr);
+	} else {
+		lte_signal = -1;
+	}
+
+	g_ril_append_print_buf(gril,
+				"{gw: %d, cdma: %d, evdo: %d, lte: %d %d %d}",
+				gw_sigstr, cdma_dbm, evdo_dbm, lte_sigstr,
+				lte_rsrp, lte_rssnr);
+
+	if (message->unsolicited)
+		g_ril_print_unsol(gril, message);
+	else
+		g_ril_print_response(gril, message);
+
+	/* Return the first valid one */
+	if (gw_signal != -1 && lte_signal != -1)
+		if (ril_tech == RADIO_TECH_LTE)
+			signal = lte_signal;
+		else
+			signal = gw_signal;
+	else if (gw_signal != -1)
+		signal = gw_signal;
+	else if (lte_signal != -1)
+		signal = lte_signal;
+	else
+		signal = -1;
+
+	return signal;
+}
+
+void g_ril_unsol_free_supp_svc_notif(struct unsol_supp_svc_notif *unsol)
+{
+	g_free(unsol);
+}
+
+struct unsol_supp_svc_notif *g_ril_unsol_parse_supp_svc_notif(GRil *gril,
+						struct ril_msg *message)
+{
+	struct parcel rilp;
+	char *tmp_number;
+	int type;
+	struct unsol_supp_svc_notif *unsol =
+		g_new0(struct unsol_supp_svc_notif, 1);
+
+	g_ril_init_parcel(message, &rilp);
+
+	unsol->notif_type = parcel_r_int32(&rilp);
+	unsol->code = parcel_r_int32(&rilp);
+	unsol->index = parcel_r_int32(&rilp);
+	type = parcel_r_int32(&rilp);
+	tmp_number = parcel_r_string(&rilp);
+
+	if (tmp_number != NULL) {
+		strncpy(unsol->number.number, tmp_number,
+			OFONO_MAX_PHONE_NUMBER_LENGTH);
+		unsol->number.type = type;
+		g_free(tmp_number);
+	}
+
+	g_ril_append_print_buf(gril, "{%d,%d,%d,%d,%s}",
+				unsol->notif_type, unsol->code, unsol->index,
+				type, tmp_number);
+	g_ril_print_unsol(gril, message);
+
+	return unsol;
+}
+
+void g_ril_unsol_free_ussd(struct unsol_ussd *unsol)
+{
+	if (unsol != NULL) {
+		g_free(unsol->message);
+		g_free(unsol);
+	}
+}
+
+struct unsol_ussd *g_ril_unsol_parse_ussd(GRil *gril, struct ril_msg *message)
+{
+	struct parcel rilp;
+	struct unsol_ussd *ussd;
+	char *typestr = NULL;
+	int numstr;
+
+	ussd = g_try_malloc0(sizeof(*ussd));
+	if (ussd == NULL) {
+		ofono_error("%s out of memory", __func__);
+		goto error;
+	}
+
+	g_ril_init_parcel(message, &rilp);
+
+	numstr = parcel_r_int32(&rilp);
+	if (numstr < 1) {
+		ofono_error("%s malformed parcel", __func__);
+		goto error;
+	}
+
+	typestr = parcel_r_string(&rilp);
+	if (typestr == NULL || *typestr == '\0') {
+		ofono_error("%s wrong type", __func__);
+		goto error;
+	}
+
+	ussd->type = *typestr - '0';
+
+	g_free(typestr);
+
+	if (numstr > 1)
+		ussd->message = parcel_r_string(&rilp);
+
+	g_ril_append_print_buf(gril, "{%d,%s}", ussd->type, ussd->message);
+
+	g_ril_print_unsol(gril, message);
+
+	return ussd;
+
+error:
+	g_free(typestr);
+	g_free(ussd);
+
+	return NULL;
+}
diff --git a/gril/grilunsol.h b/gril/grilunsol.h
new file mode 100644
index 0000000..a7ddfc9
--- /dev/null
+++ b/gril/grilunsol.h
@@ -0,0 +1,99 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2013  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GRILUNSOL_H
+#define __GRILUNSOL_H
+
+#include <ofono/types.h>
+
+#include "gril.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ril_data_call {
+	guint status;
+	gint cid;
+	guint active;
+	guint protocol;
+	char *ifname;
+	gchar *ip_addr;
+	gchar **dns_addrs;
+	gchar **gateways;
+};
+
+struct ril_data_call_list {
+	guint version;
+	GSList *calls;
+};
+
+struct unsol_sms_data {
+	long length;
+	unsigned char *data;
+};
+
+struct unsol_supp_svc_notif {
+	int notif_type;
+	int code;
+	int index;
+	struct ofono_phone_number number;
+};
+
+struct unsol_ussd {
+	int type;
+	char *message;
+};
+
+void g_ril_unsol_free_data_call_list(struct ril_data_call_list *data_call_list);
+
+
+struct ril_data_call_list *g_ril_unsol_parse_data_call_list(GRil *gril,
+						const struct ril_msg *message);
+
+char *g_ril_unsol_parse_nitz(GRil *gril, const struct ril_msg *message);
+
+void g_ril_unsol_free_sms_data(struct unsol_sms_data *unsol);
+
+struct unsol_sms_data *g_ril_unsol_parse_new_sms(GRil *gril,
+						const struct ril_msg *message);
+
+int g_ril_unsol_parse_radio_state_changed(GRil *gril,
+					const struct ril_msg *message);
+
+int g_ril_unsol_parse_signal_strength(GRil *gril, const struct ril_msg *message,
+					int ril_tech);
+
+void g_ril_unsol_free_supp_svc_notif(struct unsol_supp_svc_notif *unsol);
+
+struct unsol_supp_svc_notif *g_ril_unsol_parse_supp_svc_notif(GRil *gril,
+						struct ril_msg *message);
+
+void g_ril_unsol_free_ussd(struct unsol_ussd *unsol);
+
+struct unsol_ussd *g_ril_unsol_parse_ussd(GRil *gril, struct ril_msg *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRILUNSOL_H */
diff --git a/gril/grilutil.c b/gril/grilutil.c
new file mode 100644
index 0000000..ce51e0a
--- /dev/null
+++ b/gril/grilutil.c
@@ -0,0 +1,830 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  Canonical Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <ofono/modem.h>
+#include <ofono/gprs-context.h>
+#include <ofono/types.h>
+
+#include "grilutil.h"
+#include "parcel.h"
+#include "ril_constants.h"
+
+/* Constants used by CALL_LIST, and SETUP_DATA_CALL RIL requests */
+#define PROTO_IP_STR "IP"
+#define PROTO_IPV6_STR "IPV6"
+#define PROTO_IPV4V6_STR "IPV4V6"
+
+static char temp_str[32];
+
+const char *ril_ofono_protocol_to_ril_string(guint protocol)
+{
+	char *result;
+
+	switch (protocol) {
+	case OFONO_GPRS_PROTO_IPV6:
+		result = PROTO_IPV6_STR;
+		break;
+	case OFONO_GPRS_PROTO_IPV4V6:
+		result = PROTO_IPV4V6_STR;
+		break;
+	case OFONO_GPRS_PROTO_IP:
+		result = PROTO_IP_STR;
+		break;
+	default:
+		result = NULL;
+	}
+
+	return result;
+}
+
+int ril_protocol_string_to_ofono_protocol(gchar *protocol_str)
+{
+	int result;
+
+	if (g_strcmp0(protocol_str, PROTO_IPV6_STR) == 0)
+		result = OFONO_GPRS_PROTO_IPV6;
+	else if (g_strcmp0(protocol_str, PROTO_IPV4V6_STR) == 0)
+		result = OFONO_GPRS_PROTO_IPV4V6;
+	else if (g_strcmp0(protocol_str, PROTO_IP_STR) == 0)
+		result = OFONO_GPRS_PROTO_IP;
+	else
+		result = -1;
+
+	return result;
+}
+
+const char *ril_appstate_to_string(int app_state)
+{
+	switch (app_state) {
+	case RIL_APPSTATE_UNKNOWN:
+		return "UNKNOWN";
+	case RIL_APPSTATE_DETECTED:
+		return "DETECTED";
+	case RIL_APPSTATE_PIN:
+		return "PIN";
+	case RIL_APPSTATE_PUK:
+		return "PUK";
+	case RIL_APPSTATE_SUBSCRIPTION_PERSO:
+		return "";
+	case RIL_APPSTATE_READY:
+		return "READY";
+	default:
+		return "<INVALID>";
+	}
+}
+
+const char *ril_apptype_to_string(int app_type)
+{
+
+	switch (app_type) {
+	case RIL_APPTYPE_UNKNOWN:
+		return "UNKNOWN";
+	case RIL_APPTYPE_SIM:
+		return "SIM";
+	case RIL_APPTYPE_USIM:
+		return "USIM";
+	case RIL_APPTYPE_RUIM:
+		return "RUIM";
+	case RIL_APPTYPE_CSIM:
+		return "CSIM";
+	case RIL_APPTYPE_ISIM:
+		return "ISIM";
+	default:
+		return "<INVALID>";
+	}
+}
+
+const char *ril_authtype_to_string(int auth_type)
+{
+	switch (auth_type) {
+	case RIL_AUTH_NONE:
+		return "NONE";
+	case RIL_AUTH_PAP:
+		return "PAP";
+	case RIL_AUTH_CHAP:
+		return "CHAP";
+	case RIL_AUTH_BOTH:
+		return "BOTH";
+	case RIL_AUTH_ANY:
+		return "ANY";
+	default:
+		return "<INVALID>";
+	}
+}
+
+const char *ril_cardstate_to_string(int card_state)
+{
+	switch (card_state) {
+	case RIL_CARDSTATE_ABSENT:
+		return "ABSENT";
+	case RIL_CARDSTATE_PRESENT:
+		return "PRESENT";
+	case RIL_CARDSTATE_ERROR:
+		return "ERROR";
+	default:
+		return "<INVALID>";
+	}
+}
+
+const char *ril_error_to_string(int error)
+{
+	switch (error) {
+	case RIL_E_SUCCESS: return "SUCCESS";
+	case RIL_E_RADIO_NOT_AVAILABLE: return "RADIO_NOT_AVAILABLE";
+	case RIL_E_GENERIC_FAILURE: return "GENERIC_FAILURE";
+	case RIL_E_PASSWORD_INCORRECT: return "PASSWORD_INCORRECT";
+	case RIL_E_SIM_PIN2: return "SIM_PIN2";
+	case RIL_E_SIM_PUK2: return "SIM_PUK2";
+	case RIL_E_REQUEST_NOT_SUPPORTED: return "REQUEST_NOT_SUPPORTED";
+	case RIL_E_CANCELLED: return "CANCELLED";
+	case RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL:
+		return "OP_NOT_ALLOWED_DURING_VOICE_CALL";
+	case RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW:
+		return "OP_NOT_ALLOWED_BEFORE_REG_TO_NW";
+	case RIL_E_SMS_SEND_FAIL_RETRY: return "SMS_SEND_FAIL_RETRY";
+	case RIL_E_SIM_ABSENT: return "SIM_ABSENT";
+	case RIL_E_SUBSCRIPTION_NOT_AVAILABLE:
+		return "SUBSCRIPTION_NOT_AVAILABLE";
+	case RIL_E_MODE_NOT_SUPPORTED: return "MODE_NOT_SUPPORTED";
+	case RIL_E_FDN_CHECK_FAILURE: return "FDN_CHECK_FAILURE";
+	case RIL_E_ILLEGAL_SIM_OR_ME: return "ILLEGAL_SIM_OR_ME";
+	case RIL_E_DIAL_MODIFIED_TO_USSD: return "DIAL_MODIFIED_TO_USSD";
+	case RIL_E_DIAL_MODIFIED_TO_SS: return "DIAL_MODIFIED_TO_SS";
+	case RIL_E_DIAL_MODIFIED_TO_DIAL: return "DIAL_MODIFIED_TO_DIAL";
+	case RIL_E_USSD_MODIFIED_TO_DIAL: return "USSD_MODIFIED_TO_DIAL";
+	case RIL_E_USSD_MODIFIED_TO_SS: return "USSD_MODIFIED_TO_SS";
+	case RIL_E_USSD_MODIFIED_TO_USSD: return "USSD_MODIFIED_TO_USSD";
+	case RIL_E_SS_MODIFIED_TO_DIAL: return "SS_MODIFIED_TO_DIAL";
+	case RIL_E_SS_MODIFIED_TO_USSD: return "SS_MODIFIED_TO_USSD";
+	case RIL_E_SS_MODIFIED_TO_SS: return "SS_MODIFIED_TO_SS";
+	case RIL_E_SUBSCRIPTION_NOT_SUPPORTED:
+		return "SUBSCRIPTION_NOT_SUPPORTED";
+	default: return "<unknown errno>";
+	}
+}
+
+const char *ril_pinstate_to_string(int pin_state)
+{
+	switch (pin_state) {
+	case RIL_PINSTATE_UNKNOWN:
+		return "UNKNOWN";
+	case RIL_PINSTATE_ENABLED_NOT_VERIFIED:
+		return "ENABLED_NOT_VERIFIED";
+	case RIL_PINSTATE_ENABLED_VERIFIED:
+		return "ENABLED_VERIFIED";
+	case RIL_PINSTATE_DISABLED:
+		return "DISABLED";
+	case RIL_PINSTATE_ENABLED_BLOCKED:
+		return "ENABLED_BLOCKED";
+	case RIL_PINSTATE_ENABLED_PERM_BLOCKED:
+		return "ENABLED_PERM_BLOCKED";
+	default:
+		return "<INVALID>";
+	}
+}
+
+const char *ril_radio_state_to_string(int radio_state)
+{
+	switch (radio_state) {
+	case RADIO_STATE_OFF:
+		return "OFF";
+	case RADIO_STATE_UNAVAILABLE:
+		return "UNAVAILABLE";
+	case RADIO_STATE_SIM_NOT_READY:
+		return "SIM_NOT_READY";
+	case RADIO_STATE_SIM_LOCKED_OR_ABSENT:
+		return "SIM_LOCKED_OR_ABSENT";
+	case RADIO_STATE_SIM_READY:
+		return "SIM_READY";
+	case RADIO_STATE_ON:
+		return "ON";
+	default:
+		return "<INVALID>";
+	}
+}
+
+const char *ril_radio_tech_to_string(int radio_tech)
+{
+	switch (radio_tech) {
+	case RADIO_TECH_UNKNOWN:
+		return "UNKNOWN";
+	case RADIO_TECH_GPRS:
+		return "GPRS";
+	case RADIO_TECH_EDGE:
+		return	"EDGE";
+	case RADIO_TECH_UMTS:
+		return "UMTS";
+	case RADIO_TECH_IS95A:
+		return "IS95A";
+	case RADIO_TECH_IS95B:
+		return "IS95B";
+	case RADIO_TECH_1xRTT:
+		return "1xRTT";
+	case RADIO_TECH_EVDO_0:
+		return "EVDO_0";
+	case RADIO_TECH_EVDO_A:
+		return "EVDO_A";
+	case RADIO_TECH_HSDPA:
+		return "HSDPA";
+	case RADIO_TECH_HSUPA:
+		return "HSUPA";
+	case RADIO_TECH_HSPA:
+		return "HSPA";
+	case RADIO_TECH_EVDO_B:
+		return "EVDO_B";
+	case RADIO_TECH_EHRPD:
+		return "EHRPD";
+	case RADIO_TECH_LTE:
+		return "LTE";
+	case RADIO_TECH_HSPAP:
+		return "HSPAP";
+	case RADIO_TECH_GSM:
+		return "GSM";
+	case MTK_RADIO_TECH_HSDPAP:
+		return "MTK_HSDPAP";
+	case MTK_RADIO_TECH_HSDPAP_UPA:
+		return "MTK_HSDPAP_UPA";
+	case MTK_RADIO_TECH_HSUPAP:
+		return "MTK_HSUPAP";
+	case MTK_RADIO_TECH_HSUPAP_DPA:
+		return "MTK_HSUPAP_DPA";
+	case MTK_RADIO_TECH_DC_DPA:
+		return "MTK_DC_DPA";
+	case MTK_RADIO_TECH_DC_UPA:
+		return "MTK_DC_UPA";
+	case MTK_RADIO_TECH_DC_HSDPAP:
+		return "MTK_DC_HSDPAP";
+	case MTK_RADIO_TECH_DC_HSDPAP_UPA:
+		return "MTK_DC_HSDPAP_UPA";
+	case MTK_RADIO_TECH_DC_HSDPAP_DPA:
+		return "MTK_DC_HSDPAP_DPA";
+	case MTK_RADIO_TECH_DC_HSPAP:
+		return "MTK_DC_HSPAP";
+	default:
+		if (g_snprintf(temp_str, sizeof(temp_str),
+				"<INVALID (%d)>",
+				radio_tech))
+			return temp_str;
+		else
+			return "<INVALID>";
+	}
+}
+
+const char *ril_request_id_to_string(int req)
+{
+	switch (req) {
+	case RIL_REQUEST_GET_SIM_STATUS:
+		return "RIL_REQUEST_GET_SIM_STATUS";
+	case RIL_REQUEST_ENTER_SIM_PIN:
+		return "RIL_REQUEST_ENTER_SIM_PIN";
+	case RIL_REQUEST_ENTER_SIM_PUK:
+		return "RIL_REQUEST_ENTER_SIM_PUK";
+	case RIL_REQUEST_ENTER_SIM_PIN2:
+		return "RIL_REQUEST_ENTER_SIM_PIN2";
+	case RIL_REQUEST_ENTER_SIM_PUK2:
+		return "RIL_REQUEST_ENTER_SIM_PUK2";
+	case RIL_REQUEST_CHANGE_SIM_PIN:
+		return "RIL_REQUEST_CHANGE_SIM_PIN";
+	case RIL_REQUEST_CHANGE_SIM_PIN2:
+		return "RIL_REQUEST_CHANGE_SIM_PIN2";
+	case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
+		return "RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION";
+	case RIL_REQUEST_GET_CURRENT_CALLS:
+		return "RIL_REQUEST_GET_CURRENT_CALLS";
+	case RIL_REQUEST_DIAL:
+		return "RIL_REQUEST_DIAL";
+	case RIL_REQUEST_GET_IMSI:
+		return "RIL_REQUEST_GET_IMSI";
+	case RIL_REQUEST_HANGUP:
+		return "RIL_REQUEST_HANGUP";
+	case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
+		return "RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND";
+	case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
+		return "RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND";
+	case RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE:
+		return "RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE";
+	case RIL_REQUEST_CONFERENCE:
+		return "RIL_REQUEST_CONFERENCE";
+	case RIL_REQUEST_UDUB:
+		return "RIL_REQUEST_UDUB";
+	case RIL_REQUEST_LAST_CALL_FAIL_CAUSE:
+		return "RIL_REQUEST_LAST_CALL_FAIL_CAUSE";
+	case RIL_REQUEST_SIGNAL_STRENGTH:
+		return "RIL_REQUEST_SIGNAL_STRENGTH";
+	case RIL_REQUEST_VOICE_REGISTRATION_STATE:
+		return "RIL_REQUEST_VOICE_REGISTRATION_STATE";
+	case RIL_REQUEST_DATA_REGISTRATION_STATE:
+		return "RIL_REQUEST_DATA_REGISTRATION_STATE";
+	case RIL_REQUEST_OPERATOR:
+		return "RIL_REQUEST_OPERATOR";
+	case RIL_REQUEST_RADIO_POWER:
+		return "RIL_REQUEST_RADIO_POWER";
+	case RIL_REQUEST_DTMF:
+		return "RIL_REQUEST_DTMF";
+	case RIL_REQUEST_SEND_SMS:
+		return "RIL_REQUEST_SEND_SMS";
+	case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
+		return "RIL_REQUEST_SEND_SMS_EXPECT_MORE";
+	case RIL_REQUEST_SETUP_DATA_CALL:
+		return "RIL_REQUEST_SETUP_DATA_CALL";
+	case RIL_REQUEST_SIM_IO:
+		return "RIL_REQUEST_SIM_IO";
+	case RIL_REQUEST_SEND_USSD:
+		return "RIL_REQUEST_SEND_USSD";
+	case RIL_REQUEST_CANCEL_USSD:
+		return "RIL_REQUEST_CANCEL_USSD";
+	case RIL_REQUEST_GET_CLIR:
+		return "RIL_REQUEST_GET_CLIR";
+	case RIL_REQUEST_SET_CLIR:
+		return "RIL_REQUEST_SET_CLIR";
+	case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS:
+		return "RIL_REQUEST_QUERY_CALL_FORWARD_STATUS";
+	case RIL_REQUEST_SET_CALL_FORWARD:
+		return "RIL_REQUEST_SET_CALL_FORWARD";
+	case RIL_REQUEST_QUERY_CALL_WAITING:
+		return "RIL_REQUEST_QUERY_CALL_WAITING";
+	case RIL_REQUEST_SET_CALL_WAITING:
+		return "RIL_REQUEST_SET_CALL_WAITING";
+	case RIL_REQUEST_SMS_ACKNOWLEDGE:
+		return "RIL_REQUEST_SMS_ACKNOWLEDGE ";
+	case RIL_REQUEST_GET_IMEI:
+		return "RIL_REQUEST_GET_IMEI";
+	case RIL_REQUEST_GET_IMEISV:
+		return "RIL_REQUEST_GET_IMEISV";
+	case RIL_REQUEST_ANSWER:
+		return "RIL_REQUEST_ANSWER";
+	case RIL_REQUEST_DEACTIVATE_DATA_CALL:
+		return "RIL_REQUEST_DEACTIVATE_DATA_CALL";
+	case RIL_REQUEST_QUERY_FACILITY_LOCK:
+		return "RIL_REQUEST_QUERY_FACILITY_LOCK";
+	case RIL_REQUEST_SET_FACILITY_LOCK:
+		return "RIL_REQUEST_SET_FACILITY_LOCK";
+	case RIL_REQUEST_CHANGE_BARRING_PASSWORD:
+		return "RIL_REQUEST_CHANGE_BARRING_PASSWORD";
+	case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
+		return "RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE";
+	case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
+		return "RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC";
+	case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL:
+		return "RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL";
+	case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS:
+		return "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS";
+	case RIL_REQUEST_DTMF_START:
+		return "RIL_REQUEST_DTMF_START";
+	case RIL_REQUEST_DTMF_STOP:
+		return "RIL_REQUEST_DTMF_STOP";
+	case RIL_REQUEST_BASEBAND_VERSION:
+		return "RIL_REQUEST_BASEBAND_VERSION";
+	case RIL_REQUEST_SEPARATE_CONNECTION:
+		return "RIL_REQUEST_SEPARATE_CONNECTION";
+	case RIL_REQUEST_SET_MUTE:
+		return "RIL_REQUEST_SET_MUTE";
+	case RIL_REQUEST_GET_MUTE:
+		return "RIL_REQUEST_GET_MUTE";
+	case RIL_REQUEST_QUERY_CLIP:
+		return "RIL_REQUEST_QUERY_CLIP";
+	case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE:
+		return "RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE";
+	case RIL_REQUEST_DATA_CALL_LIST:
+		return "RIL_REQUEST_DATA_CALL_LIST";
+	case RIL_REQUEST_RESET_RADIO:
+		return "RIL_REQUEST_RESET_RADIO";
+	case RIL_REQUEST_OEM_HOOK_RAW:
+		return "RIL_REQUEST_OEM_HOOK_RAW";
+	case RIL_REQUEST_OEM_HOOK_STRINGS:
+		return "RIL_REQUEST_OEM_HOOK_STRINGS";
+	case RIL_REQUEST_SCREEN_STATE:
+		return "RIL_REQUEST_SCREEN_STATE";
+	case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
+		return "RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION";
+	case RIL_REQUEST_WRITE_SMS_TO_SIM:
+		return "RIL_REQUEST_WRITE_SMS_TO_SIM";
+	case RIL_REQUEST_DELETE_SMS_ON_SIM:
+		return "RIL_REQUEST_DELETE_SMS_ON_SIM";
+	case RIL_REQUEST_SET_BAND_MODE:
+		return "RIL_REQUEST_SET_BAND_MODE";
+	case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE:
+		return "RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE";
+	case RIL_REQUEST_STK_GET_PROFILE:
+		return "RIL_REQUEST_STK_GET_PROFILE";
+	case RIL_REQUEST_STK_SET_PROFILE:
+		return "RIL_REQUEST_STK_SET_PROFILE";
+	case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND:
+		return "RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND";
+	case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE:
+		return "RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE";
+	case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM:
+		return "RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM";
+	case RIL_REQUEST_EXPLICIT_CALL_TRANSFER:
+		return "RIL_REQUEST_EXPLICIT_CALL_TRANSFER";
+	case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
+		return "RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE";
+	case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
+		return "RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE";
+	case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
+		return "RIL_REQUEST_GET_NEIGHBORING_CELL_IDS";
+	case RIL_REQUEST_SET_LOCATION_UPDATES:
+		return "RIL_REQUEST_SET_LOCATION_UPDATES";
+	case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
+		return "RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE";
+	case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
+		return "RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE";
+	case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
+		return "RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE";
+	case RIL_REQUEST_SET_TTY_MODE:
+		return "RIL_REQUEST_SET_TTY_MODE";
+	case RIL_REQUEST_QUERY_TTY_MODE:
+		return "RIL_REQUEST_QUERY_TTY_MODE";
+	case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE:
+		return "RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE";
+	case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE:
+		return "RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE";
+	case RIL_REQUEST_CDMA_FLASH:
+		return "RIL_REQUEST_CDMA_FLASH";
+	case RIL_REQUEST_CDMA_BURST_DTMF:
+		return "RIL_REQUEST_CDMA_BURST_DTMF";
+	case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY:
+		return "RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY";
+	case RIL_REQUEST_CDMA_SEND_SMS:
+		return "RIL_REQUEST_CDMA_SEND_SMS";
+	case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE:
+		return "RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE";
+	case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
+		return "RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG";
+	case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
+		return "RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG";
+	case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:
+		return "RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION";
+	case RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG:
+		return "RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG";
+	case RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG:
+		return "RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG";
+	case RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION:
+		return "RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION";
+	case RIL_REQUEST_CDMA_SUBSCRIPTION:
+		return "RIL_REQUEST_CDMA_SUBSCRIPTION";
+	case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM:
+		return "RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM";
+	case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM:
+		return "RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM";
+	case RIL_REQUEST_DEVICE_IDENTITY:
+		return "RIL_REQUEST_DEVICE_IDENTITY";
+	case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
+		return "RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE";
+	case RIL_REQUEST_GET_SMSC_ADDRESS:
+		return "RIL_REQUEST_GET_SMSC_ADDRESS";
+	case RIL_REQUEST_SET_SMSC_ADDRESS:
+		return "RIL_REQUEST_SET_SMSC_ADDRESS";
+	case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS:
+		return "RIL_REQUEST_REPORT_SMS_MEMORY_STATUS";
+	case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING:
+		return "RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING";
+	case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
+		return "RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE";
+	case RIL_REQUEST_ISIM_AUTHENTICATION:
+		return "RIL_REQUEST_ISIM_AUTHENTICATION";
+	case RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU:
+		return "RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU";
+	case RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS:
+		return "RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS";
+	case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
+		return "RIL_REQUEST_SET_INITIAL_ATTACH_APN";
+	default:
+		return "<INVALID>";
+	}
+}
+
+const char *ril_unsol_request_to_string(int request)
+{
+	switch (request) {
+	case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
+		return "UNSOL_RESPONSE_RADIO_STATE_CHANGED";
+	case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
+		return "UNSOL_RESPONSE_CALL_STATE_CHANGED";
+	case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:
+		return "UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED";
+	case RIL_UNSOL_RESPONSE_NEW_SMS:
+		return "UNSOL_RESPONSE_NEW_SMS";
+	case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT:
+		return "UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT";
+	case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM:
+		return "UNSOL_RESPONSE_NEW_SMS_ON_SIM";
+	case RIL_UNSOL_ON_USSD:
+		return "UNSOL_ON_USSD";
+	case RIL_UNSOL_ON_USSD_REQUEST:
+		return "UNSOL_ON_USSD_REQUEST(obsolete)";
+	case RIL_UNSOL_NITZ_TIME_RECEIVED:
+		return "UNSOL_NITZ_TIME_RECEIVED";
+	case RIL_UNSOL_SIGNAL_STRENGTH:
+		return "UNSOL_SIGNAL_STRENGTH";
+	case RIL_UNSOL_SUPP_SVC_NOTIFICATION:
+		return "UNSOL_SUPP_SVC_NOTIFICATION";
+	case RIL_UNSOL_STK_SESSION_END:
+		return "UNSOL_STK_SESSION_END";
+	case RIL_UNSOL_STK_PROACTIVE_COMMAND:
+		return "UNSOL_STK_PROACTIVE_COMMAND";
+	case RIL_UNSOL_STK_EVENT_NOTIFY:
+		return "UNSOL_STK_EVENT_NOTIFY";
+	case RIL_UNSOL_STK_CALL_SETUP:
+		return "UNSOL_STK_CALL_SETUP";
+	case RIL_UNSOL_SIM_SMS_STORAGE_FULL:
+		return "UNSOL_SIM_SMS_STORAGE_FUL";
+	case RIL_UNSOL_SIM_REFRESH:
+		return "UNSOL_SIM_REFRESH";
+	case RIL_UNSOL_DATA_CALL_LIST_CHANGED:
+		return "UNSOL_DATA_CALL_LIST_CHANGED";
+	case RIL_UNSOL_CALL_RING:
+		return "UNSOL_CALL_RING";
+	case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
+		return "UNSOL_RESPONSE_SIM_STATUS_CHANGED";
+	case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:
+		return "UNSOL_NEW_CDMA_SMS";
+	case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:
+		return "UNSOL_NEW_BROADCAST_SMS";
+	case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL:
+		return "UNSOL_CDMA_RUIM_SMS_STORAGE_FULL";
+	case RIL_UNSOL_RESTRICTED_STATE_CHANGED:
+		return "UNSOL_RESTRICTED_STATE_CHANGED";
+	case RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE:
+		return "UNSOL_ENTER_EMERGENCY_CALLBACK_MODE";
+	case RIL_UNSOL_CDMA_CALL_WAITING:
+		return "UNSOL_CDMA_CALL_WAITING";
+	case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS:
+		return "UNSOL_CDMA_OTA_PROVISION_STATUS";
+	case RIL_UNSOL_CDMA_INFO_REC:
+		return "UNSOL_CDMA_INFO_REC";
+	case RIL_UNSOL_OEM_HOOK_RAW:
+		return "UNSOL_OEM_HOOK_RAW";
+	case RIL_UNSOL_RINGBACK_TONE:
+		return "UNSOL_RINGBACK_TONE";
+	case RIL_UNSOL_RESEND_INCALL_MUTE:
+		return "UNSOL_RESEND_INCALL_MUTE";
+	case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
+		return "UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED";
+	case RIL_UNSOL_CDMA_PRL_CHANGED:
+		return "UNSOL_CDMA_PRL_CHANGED";
+	case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE:
+		return "UNSOL_EXIT_EMERGENCY_CALLBACK_MODE";
+	case RIL_UNSOL_RIL_CONNECTED:
+		return "UNSOL_RIL_CONNECTED";
+	default:
+		return "<unknown request>";
+	}
+}
+
+const char *ril_pdp_fail_to_string(int status)
+{
+	switch (status) {
+	case PDP_FAIL_NONE:
+		return "NONE";
+	case PDP_FAIL_OPERATOR_BARRED:
+		return "OPERATOR_BARRED";
+	case PDP_FAIL_INSUFFICIENT_RESOURCES:
+		return "INSUFFICIENT_RESOURCES";
+	case PDP_FAIL_MISSING_UKNOWN_APN:
+		return "MISSING_UKNOWN_APN";
+	case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
+		return "UNKNOWN_PDP_ADDRESS_TYPE";
+	case PDP_FAIL_USER_AUTHENTICATION:
+		return "USER_AUTHENTICATION";
+	case PDP_FAIL_ACTIVATION_REJECT_GGSN:
+		return "ACTIVATION_REJECT_GGSN";
+	case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED:
+		return "ACTIVATION_REJECT_UNSPECIFIED";
+	case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED:
+		return "SERVICE_OPTION_NOT_SUPPORTED";
+	case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED:
+		return "SERVICE_OPTION_NOT_SUBSCRIBED";
+	case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER:
+		return "SERVICE_OPTION_OUT_OF_ORDER";
+	case PDP_FAIL_NSAPI_IN_USE:
+		return "NSAPI_IN_USE";
+	case PDP_FAIL_REGULAR_DEACTIVATION:
+		return "REGULAR_DEACTIVATION";
+	case PDP_FAIL_ONLY_IPV4_ALLOWED:
+		return "ONLY_IPV4_ALLOWED";
+	case PDP_FAIL_ONLY_IPV6_ALLOWED:
+		return "ONLY_IPV6_ALLOWED";
+	case PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED:
+		return "ONLY_SINGLE_BEARER_ALLOWED";
+	case PDP_FAIL_PROTOCOL_ERRORS:
+		return "PROTOCOL_ERRORS";
+	case PDP_FAIL_VOICE_REGISTRATION_FAIL:
+		return "VOICE_REGISTRATION_FAIL";
+	case PDP_FAIL_DATA_REGISTRATION_FAIL:
+		return "DATA_REGISTRATION_FAIL";
+	case PDP_FAIL_SIGNAL_LOST:
+		return "SIGNAL_LOST";
+	case PDP_FAIL_PREF_RADIO_TECH_CHANGED:
+		return "PREF_RADIO_TECH_CHANGED";
+	case PDP_FAIL_RADIO_POWER_OFF:
+		return "RADIO_POWER_OFF";
+	case PDP_FAIL_TETHERED_CALL_ACTIVE:
+		return "TETHERED_CALL_ACTIVE";
+	case PDP_FAIL_ERROR_UNSPECIFIED:
+		return "ERROR_UNSPECIFIED";
+	default:
+		if (g_snprintf(temp_str, sizeof(temp_str),
+				"<UNKNOWN (%d)>", status))
+			return temp_str;
+		else
+			return "<UNKNOWN>";
+	}
+}
+
+void g_ril_util_debug_chat(gboolean in, const char *str, gsize len,
+				GRilDebugFunc debugf, gpointer user_data)
+{
+	char type = in ? '<' : '>';
+	gsize escaped = 2; /* Enough for '<', ' ' */
+	char *escaped_str;
+	const char *esc = "<ESC>";
+	gsize esc_size = strlen(esc);
+	const char *ctrlz = "<CtrlZ>";
+	gsize ctrlz_size = strlen(ctrlz);
+	gsize i;
+
+	if (debugf == NULL || !len)
+		return;
+
+	for (i = 0; i < len; i++) {
+		char c = str[i];
+
+		if (g_ascii_isprint(c))
+			escaped += 1;
+		else if (c == '\r' || c == '\t' || c == '\n')
+			escaped += 2;
+		else if (c == 26)
+			escaped += ctrlz_size;
+		else if (c == 25)
+			escaped += esc_size;
+		else
+			escaped += 4;
+	}
+
+	escaped_str = g_try_malloc(escaped + 1);
+	if (escaped_str == NULL)
+		return;
+
+	escaped_str[0] = type;
+	escaped_str[1] = ' ';
+	escaped_str[2] = '\0';
+	escaped_str[escaped] = '\0';
+
+	for (escaped = 2, i = 0; i < len; i++) {
+		unsigned char c = str[i];
+
+		switch (c) {
+		case '\r':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 'r';
+			break;
+		case '\t':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 't';
+			break;
+		case '\n':
+			escaped_str[escaped++] = '\\';
+			escaped_str[escaped++] = 'n';
+			break;
+		case 26:
+			strncpy(&escaped_str[escaped], ctrlz, ctrlz_size);
+			escaped += ctrlz_size;
+			break;
+		case 25:
+			strncpy(&escaped_str[escaped], esc, esc_size);
+			escaped += esc_size;
+			break;
+		default:
+			if (g_ascii_isprint(c))
+				escaped_str[escaped++] = c;
+			else {
+				escaped_str[escaped++] = '\\';
+				escaped_str[escaped++] = '0' + ((c >> 6) & 07);
+				escaped_str[escaped++] = '0' + ((c >> 3) & 07);
+				escaped_str[escaped++] = '0' + (c & 07);
+			}
+		}
+	}
+
+	debugf(escaped_str, user_data);
+	g_free(escaped_str);
+}
+
+void g_ril_util_debug_dump(gboolean in, const unsigned char *buf, gsize len,
+				GRilDebugFunc debugf, gpointer user_data)
+{
+	char type = in ? '<' : '>';
+	GString *str;
+	gsize i;
+
+	if (debugf == NULL || !len)
+		return;
+
+	str = g_string_sized_new(1 + (len * 2));
+	if (str == NULL)
+		return;
+
+	g_string_append_c(str, type);
+
+	for (i = 0; i < len; i++)
+		g_string_append_printf(str, " %02x", buf[i]);
+
+	debugf(str->str, user_data);
+	g_string_free(str, TRUE);
+}
+
+void g_ril_util_debug_hexdump(gboolean in, const unsigned char *buf, gsize len,
+				GRilDebugFunc debugf, gpointer user_data)
+{
+	static const char hexdigits[] = "0123456789abcdef";
+	char str[68];
+	gsize i;
+
+	if (debugf == NULL || !len)
+		return;
+
+	str[0] = in ? '<' : '>';
+
+	for (i = 0; i < len; i++) {
+		str[((i % 16) * 3) + 1] = ' ';
+		str[((i % 16) * 3) + 2] = hexdigits[buf[i] >> 4];
+		str[((i % 16) * 3) + 3] = hexdigits[buf[i] & 0xf];
+		str[(i % 16) + 51] = g_ascii_isprint(buf[i]) ? buf[i] : '.';
+
+		if ((i + 1) % 16 == 0) {
+			str[49] = ' ';
+			str[50] = ' ';
+			str[67] = '\0';
+			debugf(str, user_data);
+			str[0] = ' ';
+		}
+	}
+
+	if (i % 16 > 0) {
+		gsize j;
+		for (j = (i % 16); j < 16; j++) {
+			str[(j * 3) + 1] = ' ';
+			str[(j * 3) + 2] = ' ';
+			str[(j * 3) + 3] = ' ';
+			str[j + 51] = ' ';
+		}
+		str[49] = ' ';
+		str[50] = ' ';
+		str[67] = '\0';
+		debugf(str, user_data);
+	}
+}
+
+gboolean g_ril_util_setup_io(GIOChannel *io, GIOFlags flags)
+{
+	GIOFlags io_flags;
+
+	if (g_io_channel_set_encoding(io, NULL, NULL) != G_IO_STATUS_NORMAL)
+		return FALSE;
+
+	g_io_channel_set_buffered(io, FALSE);
+
+	if (flags & G_IO_FLAG_SET_MASK) {
+		io_flags = g_io_channel_get_flags(io);
+
+		io_flags |= (flags & G_IO_FLAG_SET_MASK);
+
+		if (g_io_channel_set_flags(io, io_flags, NULL) !=
+							G_IO_STATUS_NORMAL)
+			return FALSE;
+	}
+
+	g_io_channel_set_close_on_unref(io, TRUE);
+
+	return TRUE;
+}
diff --git a/gril/grilutil.h b/gril/grilutil.h
new file mode 100644
index 0000000..be59366
--- /dev/null
+++ b/gril/grilutil.h
@@ -0,0 +1,63 @@
+/*
+ *
+ *  RIL library with GLib integration
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GRILUTIL_H
+#define __GRILUTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gfunc.h"
+#include "parcel.h"
+#include "gril.h"
+
+const char *ril_ofono_protocol_to_ril_string(guint protocol);
+int ril_protocol_string_to_ofono_protocol(gchar *protocol_str);
+const char *ril_appstate_to_string(int app_state);
+const char *ril_apptype_to_string(int app_type);
+const char *ril_authtype_to_string(int auth_type);
+const char *ril_cardstate_to_string(int card_state);
+const char *ril_error_to_string(int error);
+const char *ril_pinstate_to_string(int pin_state);
+const char *ril_radio_state_to_string(int radio_state);
+const char *ril_radio_tech_to_string(int radio_tech);
+const char *ril_request_id_to_string(int req);
+const char *ril_unsol_request_to_string(int request);
+const char *ril_pdp_fail_to_string(int status);
+
+void g_ril_util_debug_chat(gboolean in, const char *str, gsize len,
+				GRilDebugFunc debugf, gpointer user_data);
+
+void g_ril_util_debug_dump(gboolean in, const unsigned char *buf, gsize len,
+				GRilDebugFunc debugf, gpointer user_data);
+
+void g_ril_util_debug_hexdump(gboolean in, const unsigned char *buf, gsize len,
+				GRilDebugFunc debugf, gpointer user_data);
+
+gboolean g_ril_util_setup_io(GIOChannel *io, GIOFlags flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GRILUTIL_H */
diff --git a/gril/parcel.c b/gril/parcel.c
new file mode 100644
index 0000000..1cd8c8e
--- /dev/null
+++ b/gril/parcel.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2011 Joel Armstrong <jcarmst@sandia.gov>
+ * Copyright (C) 2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (`GPL') as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based on parcel implementation from https://bitbucket.org/floren/inferno
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+
+/* Parcel-handling code */
+#include <sys/types.h>
+#include <string.h>
+#include <endian.h>
+#include <stdint.h>
+#include <limits.h>
+
+#include "parcel.h"
+
+#define PAD_SIZE(s) (((s)+3)&~3)
+
+typedef uint16_t char16_t;
+
+void parcel_init(struct parcel *p)
+{
+	p->data = g_malloc0(sizeof(int32_t));
+	p->size = 0;
+	p->capacity = sizeof(int32_t);
+	p->offset = 0;
+	p->malformed = 0;
+}
+
+void parcel_grow(struct parcel *p, size_t size)
+{
+	char *new = g_realloc(p->data, p->capacity + size);
+	p->data = new;
+	p->capacity += size;
+}
+
+void parcel_free(struct parcel *p)
+{
+	g_free(p->data);
+	p->size = 0;
+	p->capacity = 0;
+	p->offset = 0;
+}
+
+int32_t parcel_r_int32(struct parcel *p)
+{
+	int32_t ret;
+
+	if (p->malformed)
+		return 0;
+
+	if (p->offset + sizeof(int32_t) > p->size) {
+		ofono_error("%s: parcel is too small", __func__);
+		p->malformed = 1;
+		return 0;
+	}
+
+	ret = *((int32_t *) (void *) (p->data + p->offset));
+	p->offset += sizeof(int32_t);
+	return ret;
+}
+
+int parcel_w_int32(struct parcel *p, int32_t val)
+{
+	for (;;) {
+
+		if (p->offset + sizeof(int32_t) < p->capacity) {
+			/* There's enough space */
+			*((int32_t *) (void *) (p->data + p->offset)) = val;
+			p->offset += sizeof(int32_t);
+			p->size += sizeof(int32_t);
+			break;
+		} else {
+			/* Grow data and retry */
+			parcel_grow(p, sizeof(int32_t));
+		}
+	}
+	return 0;
+}
+
+int parcel_w_string(struct parcel *p, const char *str)
+{
+	gunichar2 *gs16;
+	glong gs16_len;
+	size_t len;
+	size_t gs16_size;
+
+	if (str == NULL) {
+		parcel_w_int32(p, -1);
+		return 0;
+	}
+
+	gs16 = g_utf8_to_utf16(str, -1, NULL, &gs16_len, NULL);
+
+	if (parcel_w_int32(p, gs16_len) == -1)
+		return -1;
+
+	gs16_size = gs16_len * sizeof(char16_t);
+	len = gs16_size + sizeof(char16_t);
+	for (;;) {
+		size_t padded = PAD_SIZE(len);
+
+		if (p->offset + len < p->capacity) {
+			/* There's enough space */
+			memcpy(p->data + p->offset, gs16, gs16_size);
+			*((char16_t *) (void *)
+				(p->data + p->offset + gs16_size)) = 0;
+			p->offset += padded;
+			p->size += padded;
+			if (padded != len) {
+
+#if BYTE_ORDER == BIG_ENDIAN
+				static const uint32_t mask[4] = {
+					0x00000000, 0xffffff00,
+					0xffff0000, 0xff000000
+				};
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+				static const uint32_t mask[4] = {
+					0x00000000, 0x00ffffff,
+					0x0000ffff, 0x000000ff
+				};
+#endif
+
+				*((uint32_t *) (void *)
+					(p->data + p->offset - 4)) &=
+							mask[padded - len];
+			}
+			break;
+
+		} else {
+			/* Grow data and retry */
+			parcel_grow(p, padded);
+		}
+	}
+
+	g_free(gs16);
+	return 0;
+}
+
+char *parcel_r_string(struct parcel *p)
+{
+	char *ret;
+	int len16 = parcel_r_int32(p);
+	int strbytes;
+
+	if (p->malformed)
+		return NULL;
+
+	/* This is how a null string is sent */
+	if (len16 < 0)
+		return NULL;
+
+	strbytes = PAD_SIZE((len16 + 1) * sizeof(char16_t));
+	if (p->offset + strbytes > p->size) {
+		ofono_error("%s: parcel is too small", __func__);
+		p->malformed = 1;
+		return NULL;
+	}
+
+	ret = g_utf16_to_utf8((gunichar2 *) (void *) (p->data + p->offset),
+				len16, NULL, NULL, NULL);
+	if (ret == NULL) {
+		ofono_error("%s: wrong UTF16 coding", __func__);
+		p->malformed = 1;
+		return NULL;
+	}
+
+	p->offset += strbytes;
+
+	return ret;
+}
+
+int parcel_w_raw(struct parcel *p, const void *data, size_t len)
+{
+	if (data == NULL) {
+		parcel_w_int32(p, -1);
+		return 0;
+	}
+
+	parcel_w_int32(p, len);
+
+	for (;;) {
+
+		if (p->offset + len < p->capacity) {
+			/* There's enough space */
+			memcpy(p->data + p->offset, data, len);
+			p->offset += len;
+			p->size += len;
+			break;
+		} else {
+			/* Grow data and retry */
+			parcel_grow(p, len);
+		}
+	}
+	return 0;
+}
+
+void *parcel_r_raw(struct parcel *p, int *len)
+{
+	char *ret;
+
+	*len = parcel_r_int32(p);
+
+	if (p->malformed || *len <= 0)
+		return NULL;
+
+	if (p->offset + *len > p->size) {
+		ofono_error("%s: parcel is too small", __func__);
+		p->malformed = 1;
+		return NULL;
+	}
+
+	ret = g_try_malloc0(*len);
+	if (ret == NULL) {
+		ofono_error("%s: out of memory (%d bytes)", __func__, *len);
+		return NULL;
+	}
+
+	memcpy(ret, p->data + p->offset, *len);
+	p->offset += *len;
+
+	return ret;
+}
+
+size_t parcel_data_avail(struct parcel *p)
+{
+	return p->size - p->offset;
+}
+
+struct parcel_str_array *parcel_r_str_array(struct parcel *p)
+{
+	int i;
+	struct parcel_str_array *str_arr;
+	int num_str = parcel_r_int32(p);
+
+	if (p->malformed || num_str <= 0)
+		return NULL;
+
+	str_arr = g_try_malloc0(sizeof(*str_arr) + num_str * sizeof(char *));
+	if (str_arr == NULL)
+		return NULL;
+
+	str_arr->num_str = num_str;
+	for (i = 0; i < num_str; ++i)
+		str_arr->str[i] = parcel_r_string(p);
+
+	if (p->malformed) {
+		parcel_free_str_array(str_arr);
+		return NULL;
+	}
+
+	return str_arr;
+}
+
+void parcel_free_str_array(struct parcel_str_array *str_arr)
+{
+	if (str_arr) {
+		int i;
+		for (i = 0; i < str_arr->num_str; ++i)
+			g_free(str_arr->str[i]);
+		g_free(str_arr);
+	}
+}
diff --git a/gril/parcel.h b/gril/parcel.h
new file mode 100644
index 0000000..fd44811
--- /dev/null
+++ b/gril/parcel.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2011 Joel Armstrong <jcarmst@sandia.gov>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (`GPL') as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based on parcel implementation from https://bitbucket.org/floren/inferno
+ *
+ */
+
+#ifndef __PARCEL_H
+#define __PARCEL_H
+
+#include <stdlib.h>
+
+struct parcel {
+	char *data;
+	size_t offset;
+	size_t capacity;
+	size_t size;
+	int malformed;
+};
+
+struct parcel_str_array {
+	int num_str;
+	char *str[];
+};
+
+void parcel_init(struct parcel *p);
+void parcel_grow(struct parcel *p, size_t size);
+void parcel_free(struct parcel *p);
+int32_t parcel_r_int32(struct parcel *p);
+int parcel_w_int32(struct parcel *p, int32_t val);
+int parcel_w_string(struct parcel *p, const char *str);
+char *parcel_r_string(struct parcel *p);
+int parcel_w_raw(struct parcel *p, const void *data, size_t len);
+void *parcel_r_raw(struct parcel *p,  int *len);
+size_t parcel_data_avail(struct parcel *p);
+struct parcel_str_array *parcel_r_str_array(struct parcel *p);
+void parcel_free_str_array(struct parcel_str_array *str_arr);
+
+#endif
diff --git a/gril/ril_constants.h b/gril/ril_constants.h
new file mode 100644
index 0000000..f5b5cad
--- /dev/null
+++ b/gril/ril_constants.h
@@ -0,0 +1,429 @@
+/*
+ *
+ *  RIL constants adopted from AOSP's header:
+ *
+ *  /hardware/ril/reference_ril/ril.h
+ *
+ *  Copyright (C) 2013 Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+#ifndef __RIL_CONSTANTS_H
+#define __RIL_CONSTANTS_H 1
+#define RIL_VERSION 7
+
+/* Error Codes */
+#define RIL_E_SUCCESS 0
+#define RIL_E_RADIO_NOT_AVAILABLE 1
+#define RIL_E_GENERIC_FAILURE 2
+#define RIL_E_PASSWORD_INCORRECT 3
+#define RIL_E_SIM_PIN2 4
+#define RIL_E_SIM_PUK2 5
+#define RIL_E_REQUEST_NOT_SUPPORTED 6
+#define RIL_E_CANCELLED 7
+#define RIL_E_OP_NOT_ALLOWED_DURING_VOICE_CALL 8
+#define RIL_E_OP_NOT_ALLOWED_BEFORE_REG_TO_NW 9
+#define RIL_E_SMS_SEND_FAIL_RETRY 10
+#define RIL_E_SIM_ABSENT 11
+#define RIL_E_SUBSCRIPTION_NOT_AVAILABLE 12
+#define RIL_E_MODE_NOT_SUPPORTED 13
+#define RIL_E_FDN_CHECK_FAILURE 14
+#define RIL_E_ILLEGAL_SIM_OR_ME 15
+/*
+ * Following error codes are actually Qualcomm-specific, but as they are used by
+ * our reference platform, we consider them valid for vendor
+ * OFONO_RIL_VENDOR_AOSP. The definition comes from cyanogenmod ril.h, which in
+ * turn copied it from codeaurora.
+ */
+#define RIL_E_DIAL_MODIFIED_TO_USSD 17
+#define RIL_E_DIAL_MODIFIED_TO_SS 18
+#define RIL_E_DIAL_MODIFIED_TO_DIAL 19
+#define RIL_E_USSD_MODIFIED_TO_DIAL 20
+#define RIL_E_USSD_MODIFIED_TO_SS 21
+#define RIL_E_USSD_MODIFIED_TO_USSD 22
+#define RIL_E_SS_MODIFIED_TO_DIAL 23
+#define RIL_E_SS_MODIFIED_TO_USSD 24
+#define RIL_E_SS_MODIFIED_TO_SS 25
+#define RIL_E_SUBSCRIPTION_NOT_SUPPORTED 26
+
+/* Preferred network types */
+#define PREF_NET_TYPE_GSM_WCDMA 0
+#define PREF_NET_TYPE_GSM_ONLY 1
+#define PREF_NET_TYPE_WCDMA 2
+#define PREF_NET_TYPE_GSM_WCDMA_AUTO 3
+#define PREF_NET_TYPE_CDMA_EVDO_AUTO 4
+#define PREF_NET_TYPE_CDMA_ONLY 5
+#define PREF_NET_TYPE_EVDO_ONLY 6
+#define PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO 7
+#define PREF_NET_TYPE_LTE_CDMA_EVDO 8
+#define PREF_NET_TYPE_LTE_GSM_WCDMA 9
+#define PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA 10
+#define PREF_NET_TYPE_LTE_ONLY 11
+#define PREF_NET_TYPE_LTE_WCDMA 12
+/* MTK specific network types */
+#define MTK_PREF_NET_TYPE_BASE 30
+#define MTK_PREF_NET_TYPE_LTE_GSM_WCDMA (MTK_PREF_NET_TYPE_BASE + 1)
+#define MTK_PREF_NET_TYPE_LTE_GSM_WCDMA_MMDC (MTK_PREF_NET_TYPE_BASE + 2)
+#define MTK_PREF_NET_TYPE_GSM_WCDMA_LTE (MTK_PREF_NET_TYPE_BASE + 3)
+#define MTK_PREF_NET_TYPE_GSM_WCDMA_LTE_MMDC (MTK_PREF_NET_TYPE_BASE + 4)
+#define MTK_PREF_NET_TYPE_LTE_GSM_TYPE (MTK_PREF_NET_TYPE_BASE + 5)
+#define MTK_PREF_NET_TYPE_LTE_GSM_MMDC_TYPE (MTK_PREF_NET_TYPE_BASE + 6)
+
+/*
+ * Data Call Failure causes ( see TS 24.008 )
+ * section 6.1.3.1.3 or TS 24.301 Release 8+ Annex B.
+ */
+#define PDP_FAIL_NONE 0
+#define PDP_FAIL_OPERATOR_BARRED 0x08
+#define PDP_FAIL_INSUFFICIENT_RESOURCES 0x1A
+#define PDP_FAIL_MISSING_UKNOWN_APN 0x1B
+#define PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE 0x1C
+#define PDP_FAIL_USER_AUTHENTICATION 0x1D
+#define PDP_FAIL_ACTIVATION_REJECT_GGSN 0x1E
+#define PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED 0x1F
+#define PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED 0x20
+#define PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED 0x21
+#define PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER 0x22
+#define PDP_FAIL_NSAPI_IN_USE 0x23
+#define PDP_FAIL_REGULAR_DEACTIVATION 0x24  /* restart radio */
+#define PDP_FAIL_ONLY_IPV4_ALLOWED 0x32
+#define PDP_FAIL_ONLY_IPV6_ALLOWED 0x33
+#define PDP_FAIL_ONLY_SINGLE_BEARER_ALLOWED 0x34
+#define PDP_FAIL_PROTOCOL_ERRORS 0x6F
+#define PDP_FAIL_VOICE_REGISTRATION_FAIL -1
+#define PDP_FAIL_DATA_REGISTRATION_FAIL -2
+#define PDP_FAIL_SIGNAL_LOST -3
+#define PDP_FAIL_PREF_RADIO_TECH_CHANGED -4
+#define PDP_FAIL_RADIO_POWER_OFF -5
+#define PDP_FAIL_TETHERED_CALL_ACTIVE -6
+#define PDP_FAIL_ERROR_UNSPECIFIED 0xffff
+
+/* Radio States */
+#define RADIO_STATE_OFF 0
+#define RADIO_STATE_UNAVAILABLE 1
+#define RADIO_STATE_ON 10
+
+/* Deprecated, but still used by some modems */
+#define RADIO_STATE_SIM_NOT_READY 2
+#define RADIO_STATE_SIM_LOCKED_OR_ABSENT 3
+#define RADIO_STATE_SIM_READY 4
+
+/* Radio technologies */
+#define RADIO_TECH_UNKNOWN 0
+#define RADIO_TECH_GPRS 1
+#define RADIO_TECH_EDGE 2
+#define RADIO_TECH_UMTS 3
+#define RADIO_TECH_IS95A 4
+#define RADIO_TECH_IS95B 5
+#define RADIO_TECH_1xRTT 6
+#define RADIO_TECH_EVDO_0 7
+#define RADIO_TECH_EVDO_A 8
+#define RADIO_TECH_HSDPA 9
+#define RADIO_TECH_HSUPA 10
+#define RADIO_TECH_HSPA 11
+#define RADIO_TECH_EVDO_B 12
+#define RADIO_TECH_EHRPD 13
+#define RADIO_TECH_LTE 14
+#define RADIO_TECH_HSPAP 15
+#define RADIO_TECH_GSM 16
+/* MTK specific values for radio technologies */
+#define MTK_RADIO_TECH_BASE 128
+#define MTK_RADIO_TECH_HSDPAP (MTK_RADIO_TECH_BASE + 1)
+#define MTK_RADIO_TECH_HSDPAP_UPA (MTK_RADIO_TECH_BASE + 2)
+#define MTK_RADIO_TECH_HSUPAP (MTK_RADIO_TECH_BASE + 3)
+#define MTK_RADIO_TECH_HSUPAP_DPA (MTK_RADIO_TECH_BASE + 4)
+#define MTK_RADIO_TECH_DC_DPA (MTK_RADIO_TECH_BASE + 5)
+#define MTK_RADIO_TECH_DC_UPA (MTK_RADIO_TECH_BASE + 6)
+#define MTK_RADIO_TECH_DC_HSDPAP (MTK_RADIO_TECH_BASE + 7)
+#define MTK_RADIO_TECH_DC_HSDPAP_UPA (MTK_RADIO_TECH_BASE + 8)
+#define MTK_RADIO_TECH_DC_HSDPAP_DPA (MTK_RADIO_TECH_BASE + 9)
+#define MTK_RADIO_TECH_DC_HSPAP (MTK_RADIO_TECH_BASE + 10)
+
+/* See RIL_REQUEST_LAST_CALL_FAIL_CAUSE */
+#define CALL_FAIL_UNOBTAINABLE_NUMBER 1
+#define CALL_FAIL_NORMAL 16
+#define CALL_FAIL_BUSY 17
+#define CALL_FAIL_CONGESTION 34
+#define CALL_FAIL_ACM_LIMIT_EXCEEDED 68
+#define CALL_FAIL_CALL_BARRED 240
+#define CALL_FAIL_FDN_BLOCKED 241
+#define CALL_FAIL_IMSI_UNKNOWN_IN_VLR 242
+#define CALL_FAIL_IMEI_NOT_ACCEPTED 243
+#define CALL_FAIL_DIAL_MODIFIED_TO_USSD 244
+#define CALL_FAIL_DIAL_MODIFIED_TO_SS 245
+#define CALL_FAIL_DIAL_MODIFIED_TO_DIAL 246
+#define CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE 1000
+#define CALL_FAIL_CDMA_DROP 1001
+#define CALL_FAIL_CDMA_INTERCEPT 1002
+#define CALL_FAIL_CDMA_REORDER 1003
+#define CALL_FAIL_CDMA_SO_REJECT 1004
+#define CALL_FAIL_CDMA_RETRY_ORDER 1005
+#define CALL_FAIL_CDMA_ACCESS_FAILURE 1006
+#define CALL_FAIL_CDMA_PREEMPTED 1007
+#define CALL_FAIL_CDMA_NOT_EMERGENCY 1008
+#define CALL_FAIL_CDMA_ACCESS_BLOCKED 1009
+#define CALL_FAIL_ERROR_UNSPECIFIED 0xffff
+
+/* see RIL_REQUEST_DEACTIVATE_DATA_CALL parameter*/
+#define RIL_DEACTIVATE_DATA_CALL_NO_REASON 0
+#define RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN 1
+
+/* See RIL_REQUEST_SETUP_DATA_CALL */
+
+#define RIL_DATA_PROFILE_DEFAULT 0
+#define RIL_DATA_PROFILE_TETHERED 1
+#define RIL_DATA_PROFILE_IMS 2
+#define RIL_DATA_PROFILE_FOTA 3           /* FOTA = Firmware Over the Air */
+#define RIL_DATA_PROFILE_CBS 4
+#define RIL_DATA_PROFILE_OEM_BASE 1000    /* Start of OEM-specific profiles */
+/* MTK specific profile for MMS */
+#define RIL_DATA_PROFILE_MTK_MMS (RIL_DATA_PROFILE_OEM_BASE + 1)
+
+/*
+ * auth type -1 seems to mean 0 (RIL_AUTH_NONE) if no user/password is
+ * specified or 3 (RIL_AUTH_BOTH) otherwise. See $ANDROID/packages/
+ * providers/TelephonyProvider/src/com/android/providers/telephony/
+ * TelephonyProvider.java.
+ */
+#define RIL_AUTH_ANY -1
+#define RIL_AUTH_NONE 0
+#define RIL_AUTH_PAP 1
+#define RIL_AUTH_CHAP 2
+#define RIL_AUTH_BOTH 3
+
+/* SIM card states */
+#define RIL_CARDSTATE_ABSENT 0
+#define RIL_CARDSTATE_PRESENT 1
+#define RIL_CARDSTATE_ERROR 2
+
+/* SIM - App states */
+#define RIL_APPSTATE_UNKNOWN 0
+#define RIL_APPSTATE_DETECTED 1
+#define RIL_APPSTATE_PIN 2
+#define RIL_APPSTATE_PUK 3
+#define RIL_APPSTATE_SUBSCRIPTION_PERSO 4
+#define RIL_APPSTATE_READY 5
+
+/* SIM - PIN states */
+#define RIL_PINSTATE_UNKNOWN 0
+#define RIL_PINSTATE_ENABLED_NOT_VERIFIED 1
+#define RIL_PINSTATE_ENABLED_VERIFIED 2
+#define RIL_PINSTATE_DISABLED 3
+#define RIL_PINSTATE_ENABLED_BLOCKED 4
+#define RIL_PINSTATE_ENABLED_PERM_BLOCKED 5
+
+/* SIM - App types */
+#define RIL_APPTYPE_UNKNOWN 0
+#define RIL_APPTYPE_SIM 1
+#define RIL_APPTYPE_USIM 2
+#define RIL_APPTYPE_RUIM 3
+#define RIL_APPTYPE_CSIM 4
+#define RIL_APPTYPE_ISIM 5
+
+/* SIM - PersoSubstate */
+#define RIL_PERSOSUBSTATE_UNKNOWN 0
+#define RIL_PERSOSUBSTATE_IN_PROGRESS 1
+#define RIL_PERSOSUBSTATE_READY 2
+#define RIL_PERSOSUBSTATE_SIM_NETWORK 3
+#define RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET 4
+#define RIL_PERSOSUBSTATE_SIM_CORPORATE 5
+#define RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER 6
+#define RIL_PERSOSUBSTATE_SIM_SIM 7
+#define RIL_PERSOSUBSTATE_SIM_NETWORK_PUK 8
+#define RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK 9
+#define RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK 10
+#define RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK 11
+#define RIL_PERSOSUBSTATE_SIM_SIM_PUK 12
+#define RIL_PERSOSUBSTATE_RUIM_NETWORK1 13
+#define RIL_PERSOSUBSTATE_RUIM_NETWORK2 14
+#define RIL_PERSOSUBSTATE_RUIM_HRPD 15
+#define RIL_PERSOSUBSTATE_RUIM_CORPORATE 16
+#define RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER 17
+#define RIL_PERSOSUBSTATE_RUIM_RUIM 18
+#define RIL_PERSOSUBSTATE_RUIM_NETWORK1_PUK 19
+#define RIL_PERSOSUBSTATE_RUIM_NETWORK2_PUK 20
+#define RIL_PERSOSUBSTATE_RUIM_HRPD_PUK 21
+#define RIL_PERSOSUBSTATE_RUIM_CORPORATE_PUK 22
+#define RIL_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK 23
+#define RIL_PERSOSUBSTATE_RUIM_RUIM_PUK 24
+
+/* RIL Request Messages */
+#define RIL_REQUEST_GET_SIM_STATUS 1
+#define RIL_REQUEST_ENTER_SIM_PIN 2
+#define RIL_REQUEST_ENTER_SIM_PUK 3
+#define RIL_REQUEST_ENTER_SIM_PIN2 4
+#define RIL_REQUEST_ENTER_SIM_PUK2 5
+#define RIL_REQUEST_CHANGE_SIM_PIN 6
+#define RIL_REQUEST_CHANGE_SIM_PIN2 7
+#define RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION 8
+#define RIL_REQUEST_GET_CURRENT_CALLS 9
+#define RIL_REQUEST_DIAL 10
+#define RIL_REQUEST_GET_IMSI 11
+#define RIL_REQUEST_HANGUP 12
+#define RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND 13
+#define RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND 14
+#define RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE 15
+#define RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE 15
+#define RIL_REQUEST_CONFERENCE 16
+#define RIL_REQUEST_UDUB 17
+#define RIL_REQUEST_LAST_CALL_FAIL_CAUSE 18
+#define RIL_REQUEST_SIGNAL_STRENGTH 19
+#define RIL_REQUEST_VOICE_REGISTRATION_STATE 20
+#define RIL_REQUEST_DATA_REGISTRATION_STATE 21
+#define RIL_REQUEST_OPERATOR 22
+#define RIL_REQUEST_RADIO_POWER 23
+#define RIL_REQUEST_DTMF 24
+#define RIL_REQUEST_SEND_SMS 25
+#define RIL_REQUEST_SEND_SMS_EXPECT_MORE 26
+#define RIL_REQUEST_SETUP_DATA_CALL 27
+#define RIL_REQUEST_SIM_IO 28
+#define RIL_REQUEST_SEND_USSD 29
+#define RIL_REQUEST_CANCEL_USSD 30
+#define RIL_REQUEST_GET_CLIR 31
+#define RIL_REQUEST_SET_CLIR 32
+#define RIL_REQUEST_QUERY_CALL_FORWARD_STATUS 33
+#define RIL_REQUEST_SET_CALL_FORWARD 34
+#define RIL_REQUEST_QUERY_CALL_WAITING 35
+#define RIL_REQUEST_SET_CALL_WAITING 36
+#define RIL_REQUEST_SMS_ACKNOWLEDGE  37
+#define RIL_REQUEST_GET_IMEI 38
+#define RIL_REQUEST_GET_IMEISV 39
+#define RIL_REQUEST_ANSWER 40
+#define RIL_REQUEST_DEACTIVATE_DATA_CALL 41
+#define RIL_REQUEST_QUERY_FACILITY_LOCK 42
+#define RIL_REQUEST_SET_FACILITY_LOCK 43
+#define RIL_REQUEST_CHANGE_BARRING_PASSWORD 44
+#define RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE 45
+#define RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC 46
+#define RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL 47
+#define RIL_REQUEST_QUERY_AVAILABLE_NETWORKS 48
+#define RIL_REQUEST_DTMF_START 49
+#define RIL_REQUEST_DTMF_STOP 50
+#define RIL_REQUEST_BASEBAND_VERSION 51
+#define RIL_REQUEST_SEPARATE_CONNECTION 52
+#define RIL_REQUEST_SET_MUTE 53
+#define RIL_REQUEST_GET_MUTE 54
+#define RIL_REQUEST_QUERY_CLIP 55
+#define RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE 56
+#define RIL_REQUEST_DATA_CALL_LIST 57
+#define RIL_REQUEST_RESET_RADIO 58
+#define RIL_REQUEST_OEM_HOOK_RAW 59
+#define RIL_REQUEST_OEM_HOOK_STRINGS 60
+#define RIL_REQUEST_SCREEN_STATE 61
+#define RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION 62
+#define RIL_REQUEST_WRITE_SMS_TO_SIM 63
+#define RIL_REQUEST_DELETE_SMS_ON_SIM 64
+#define RIL_REQUEST_SET_BAND_MODE 65
+#define RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE 66
+#define RIL_REQUEST_STK_GET_PROFILE 67
+#define RIL_REQUEST_STK_SET_PROFILE 68
+#define RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND 69
+#define RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE 70
+#define RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM 71
+#define RIL_REQUEST_EXPLICIT_CALL_TRANSFER 72
+#define RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE 73
+#define RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE 74
+#define RIL_REQUEST_GET_NEIGHBORING_CELL_IDS 75
+#define RIL_REQUEST_SET_LOCATION_UPDATES 76
+#define RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE 77
+#define RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE 78
+#define RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE 79
+#define RIL_REQUEST_SET_TTY_MODE 80
+#define RIL_REQUEST_QUERY_TTY_MODE 81
+#define RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE 82
+#define RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE 83
+#define RIL_REQUEST_CDMA_FLASH 84
+#define RIL_REQUEST_CDMA_BURST_DTMF 85
+#define RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY 86
+#define RIL_REQUEST_CDMA_SEND_SMS 87
+#define RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE 88
+#define RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG 89
+#define RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG 90
+#define RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION 91
+#define RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG 92
+#define RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG 93
+#define RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION 94
+#define RIL_REQUEST_CDMA_SUBSCRIPTION 95
+#define RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 96
+#define RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 97
+#define RIL_REQUEST_DEVICE_IDENTITY 98
+#define RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE 99
+#define RIL_REQUEST_GET_SMSC_ADDRESS 100
+#define RIL_REQUEST_SET_SMSC_ADDRESS 101
+#define RIL_REQUEST_REPORT_SMS_MEMORY_STATUS 102
+#define RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING 103
+#define RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE 104
+#define RIL_REQUEST_ISIM_AUTHENTICATION 105
+#define RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU 106
+#define RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS 107
+#define RIL_REQUEST_VOICE_RADIO_TECH 108
+#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111
+
+/* RIL Unsolicited Messages */
+#define RIL_UNSOL_RESPONSE_BASE 1000
+#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000
+#define RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED 1001
+#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 1002
+#define RIL_UNSOL_RESPONSE_NEW_SMS 1003
+#define RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT 1004
+#define RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM 1005
+#define RIL_UNSOL_ON_USSD 1006
+#define RIL_UNSOL_ON_USSD_REQUEST 1007
+#define RIL_UNSOL_NITZ_TIME_RECEIVED  1008
+#define RIL_UNSOL_SIGNAL_STRENGTH  1009
+#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 1010
+#define RIL_UNSOL_SUPP_SVC_NOTIFICATION 1011
+#define RIL_UNSOL_STK_SESSION_END 1012
+#define RIL_UNSOL_STK_PROACTIVE_COMMAND 1013
+#define RIL_UNSOL_STK_EVENT_NOTIFY 1014
+#define RIL_UNSOL_STK_CALL_SETUP 1015
+#define RIL_UNSOL_SIM_SMS_STORAGE_FULL 1016
+#define RIL_UNSOL_SIM_REFRESH 1017
+#define RIL_UNSOL_CALL_RING 1018
+#define RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 1019
+#define RIL_UNSOL_RESPONSE_CDMA_NEW_SMS 1020
+#define RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS 1021
+#define RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL 1022
+#define RIL_UNSOL_RESTRICTED_STATE_CHANGED 1023
+#define RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE 1024
+#define RIL_UNSOL_CDMA_CALL_WAITING 1025
+#define RIL_UNSOL_CDMA_OTA_PROVISION_STATUS 1026
+#define RIL_UNSOL_CDMA_INFO_REC 1027
+#define RIL_UNSOL_OEM_HOOK_RAW 1028
+#define RIL_UNSOL_RINGBACK_TONE 1029
+#define RIL_UNSOL_RESEND_INCALL_MUTE 1030
+#define RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED 1031
+#define RIL_UNSOL_CDMA_PRL_CHANGED 1032
+#define RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE 1033
+#define RIL_UNSOL_RIL_CONNECTED 1034
+#define RIL_UNSOL_VOICE_RADIO_TECH_CHANGED 1035
+
+/* Suplementary services Service class*/
+#define SERVICE_CLASS_NONE 0
+
+/* Network registration states */
+#define RIL_REG_STATE_NOT_REGISTERED 0
+#define RIL_REG_STATE_REGISTERED 1
+#define RIL_REG_STATE_SEARCHING 2
+#define RIL_REG_STATE_DENIED 3
+#define RIL_REG_STATE_UNKNOWN 4
+#define RIL_REG_STATE_ROAMING 5
+#define RIL_REG_STATE_EMERGENCY_NOT_REGISTERED 10
+#define RIL_REG_STATE_EMERGENCY_SEARCHING 12
+#define RIL_REG_STATE_EMERGENCY_DENIED 13
+#define RIL_REG_STATE_EMERGENCY_UNKNOWN 14
+
+#endif /*__RIL_CONSTANTS_H*/
-- 
2.1.4


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

* [PATCH 4/9] rilmodem: driver for Android modems
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
                   ` (2 preceding siblings ...)
  2015-10-13 16:07 ` [PATCH 3/9] gril: Library to communicate with rild Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 5/9] ril: Plugin " Alfonso Sanchez-Beato
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

From: Tony Espy <espy@canonical.com>

Driver for modems that are accessed through the Android Radio Interface
Layer (RIL) for telephony, using the gril library. The driver is almost
feature complete with some exceptions, being CBS and SAT the most
prominent.

Co-authored-by: Tony Espy <espy@canonical.com>
Co-authored-by: Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
Co-authored-by: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
Co-authored-by: Islam Amer <islam.amer@jollamobile.com>
Co-authored-by: Jussi Kangas <jussi.kangas@tieto.com>
Co-authored-by: Juho Hämäläinen <juho.hamalainen@tieto.com>
Co-authored-by: Petri Takalokastari <petri.takalokastari@oss.tieto.com>
Co-authored-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
Co-authored-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
Co-authored-by: Miia Leinonen <miia.leinonen@oss.tieto.com>
Co-authored-by: Martti Piirainen <martti.piirainen@canonical.com>
Co-authored-by: You-Sheng Yang <vicamo.yang@canonical.com>
---
 drivers/rilmodem/call-barring.c         |  245 +++++++
 drivers/rilmodem/call-forwarding.c      |  327 +++++++++
 drivers/rilmodem/call-settings.c        |  286 ++++++++
 drivers/rilmodem/call-volume.c          |  182 +++++
 drivers/rilmodem/devinfo.c              |  218 ++++++
 drivers/rilmodem/gprs-context.c         |  585 +++++++++++++++
 drivers/rilmodem/gprs.c                 |  487 +++++++++++++
 drivers/rilmodem/gprs.h                 |   46 ++
 drivers/rilmodem/network-registration.c |  566 +++++++++++++++
 drivers/rilmodem/phonebook.c            | 1055 +++++++++++++++++++++++++++
 drivers/rilmodem/radio-settings.c       |  300 ++++++++
 drivers/rilmodem/radio-settings.h       |   47 ++
 drivers/rilmodem/rilmodem.c             |   78 ++
 drivers/rilmodem/rilmodem.h             |   71 ++
 drivers/rilmodem/rilutil.c              |  194 +++++
 drivers/rilmodem/rilutil.h              |  165 +++++
 drivers/rilmodem/sim.c                  | 1200 +++++++++++++++++++++++++++++++
 drivers/rilmodem/sms.c                  |  315 ++++++++
 drivers/rilmodem/ussd.c                 |  264 +++++++
 drivers/rilmodem/vendor.h               |   32 +
 drivers/rilmodem/voicecall.c            |  824 +++++++++++++++++++++
 drivers/rilmodem/voicecall.h            |   71 ++
 22 files changed, 7558 insertions(+)
 create mode 100644 drivers/rilmodem/call-barring.c
 create mode 100644 drivers/rilmodem/call-forwarding.c
 create mode 100644 drivers/rilmodem/call-settings.c
 create mode 100644 drivers/rilmodem/call-volume.c
 create mode 100644 drivers/rilmodem/devinfo.c
 create mode 100644 drivers/rilmodem/gprs-context.c
 create mode 100644 drivers/rilmodem/gprs.c
 create mode 100644 drivers/rilmodem/gprs.h
 create mode 100644 drivers/rilmodem/network-registration.c
 create mode 100644 drivers/rilmodem/phonebook.c
 create mode 100644 drivers/rilmodem/radio-settings.c
 create mode 100644 drivers/rilmodem/radio-settings.h
 create mode 100644 drivers/rilmodem/rilmodem.c
 create mode 100644 drivers/rilmodem/rilmodem.h
 create mode 100644 drivers/rilmodem/rilutil.c
 create mode 100644 drivers/rilmodem/rilutil.h
 create mode 100644 drivers/rilmodem/sim.c
 create mode 100644 drivers/rilmodem/sms.c
 create mode 100644 drivers/rilmodem/ussd.c
 create mode 100644 drivers/rilmodem/vendor.h
 create mode 100644 drivers/rilmodem/voicecall.c
 create mode 100644 drivers/rilmodem/voicecall.h

diff --git a/drivers/rilmodem/call-barring.c b/drivers/rilmodem/call-barring.c
new file mode 100644
index 0000000..6a19556
--- /dev/null
+++ b/drivers/rilmodem/call-barring.c
@@ -0,0 +1,245 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2014 Jolla Ltd
+ *  Contact: Miia Leinonen
+ *  Copyright (C) 2014  Canonical Ltd
+ *
+ *  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 <errno.h>
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+
+#include "common.h"
+#include "grilrequest.h"
+#include "grilreply.h"
+#include "call-barring.h"
+#include "rilmodem.h"
+#include "ril_constants.h"
+
+struct barring_data {
+	GRil *ril;
+};
+
+static void ril_call_barring_query_cb(struct ril_msg *message,
+					gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_call_barring_query_cb_t cb = cbd->cb;
+	struct barring_data *bd = cbd->user;
+	int bearer_class;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: query failed, err: %s", __func__,
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	bearer_class = g_ril_reply_parse_query_facility_lock(bd->ril, message);
+	if (bearer_class < 0)
+		goto error;
+
+	CALLBACK_WITH_SUCCESS(cb, bearer_class, cbd->data);
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
+
+static void ril_call_barring_query(struct ofono_call_barring *cb,
+					const char *lock, int cls,
+					ofono_call_barring_query_cb_t callback,
+					void *data)
+{
+	struct barring_data *bd = ofono_call_barring_get_data(cb);
+	struct cb_data *cbd = cb_data_new(callback, data, bd);
+	struct parcel rilp;
+
+	DBG("lock: %s, services to query: %d", lock, cls);
+
+	/*
+	 * RIL modems do not support 7 as default bearer class. According to
+	 * TS 22.030 Annex C: When service code is not given it corresponds to
+	 * "All tele and bearer services"
+	 */
+	if (cls == BEARER_CLASS_DEFAULT)
+		cls = SERVICE_CLASS_NONE;
+
+	/* ril.h: password should be empty string "" when not needed */
+	g_ril_request_query_facility_lock(bd->ril, lock, "", cls, &rilp);
+
+	if (g_ril_send(bd->ril, RIL_REQUEST_QUERY_FACILITY_LOCK, &rilp,
+				ril_call_barring_query_cb, cbd, g_free) <= 0) {
+		ofono_error("%s: sending failed", __func__);
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(callback, -1, data);
+	}
+}
+
+static void ril_call_barring_set_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_call_barring_set_cb_t cb = cbd->cb;
+	struct barring_data *bd = cbd->user;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: set failed, err: %s", __func__,
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	/* Just for printing return value */
+	g_ril_reply_parse_set_facility_lock(bd->ril, message);
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void ril_call_barring_set(struct ofono_call_barring *cb,
+				const char *lock, int enable,
+				const char *passwd, int cls,
+				ofono_call_barring_set_cb_t callback,
+				void *data)
+{
+	struct barring_data *bd = ofono_call_barring_get_data(cb);
+	struct cb_data *cbd = cb_data_new(callback, data, bd);
+	struct parcel rilp;
+
+	DBG("lock: %s, enable: %d, bearer class: %d", lock, enable, cls);
+
+	/*
+	 * RIL modem does not support 7 as default bearer class. According to
+	 * the 22.030 Annex C: When service code is not given it corresponds to
+	 * "All tele and bearer services"
+	 */
+	if (cls == BEARER_CLASS_DEFAULT)
+		cls = SERVICE_CLASS_NONE;
+
+	g_ril_request_set_facility_lock(bd->ril, lock, enable,
+					passwd, cls, &rilp);
+
+	if (g_ril_send(bd->ril, RIL_REQUEST_SET_FACILITY_LOCK, &rilp,
+			ril_call_barring_set_cb, cbd, g_free) <= 0) {
+		ofono_error("%s: sending failed", __func__);
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(callback, data);
+	}
+}
+
+static void ril_call_barring_set_passwd_cb(struct ril_msg *message,
+						gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_call_barring_set_cb_t cb = cbd->cb;
+	struct barring_data *bd = cbd->user;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: set password failed, err: %s", __func__,
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	g_ril_print_response_no_args(bd->ril, message);
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void ril_call_barring_set_passwd(struct ofono_call_barring *barr,
+					const char *lock,
+					const char *old_passwd,
+					const char *new_passwd,
+					ofono_call_barring_set_cb_t cb,
+					void *data)
+{
+	struct barring_data *bd = ofono_call_barring_get_data(barr);
+	struct cb_data *cbd = cb_data_new(cb, data, bd);
+	struct parcel rilp;
+
+	DBG("lock %s old %s new %s", lock, old_passwd, new_passwd);
+
+	g_ril_request_change_barring_password(bd->ril, lock, old_passwd,
+						new_passwd, &rilp);
+
+	if (g_ril_send(bd->ril, RIL_REQUEST_CHANGE_BARRING_PASSWORD, &rilp,
+			ril_call_barring_set_passwd_cb, cbd, g_free) <= 0) {
+		ofono_error("%s: sending failed", __func__);
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_call_barring *cb = user_data;
+
+	ofono_call_barring_register(cb);
+	return FALSE;
+}
+
+static int ril_call_barring_probe(struct ofono_call_barring *cb,
+					unsigned int vendor, void *user)
+{
+	GRil *ril = user;
+	struct barring_data *bd = g_try_new0(struct barring_data, 1);
+	if (bd == NULL)
+		return -ENOMEM;
+
+	bd->ril = g_ril_clone(ril);
+	ofono_call_barring_set_data(cb, bd);
+
+	g_idle_add(ril_delayed_register, cb);
+
+	return 0;
+}
+
+static void ril_call_barring_remove(struct ofono_call_barring *cb)
+{
+	struct barring_data *data = ofono_call_barring_get_data(cb);
+	ofono_call_barring_set_data(cb, NULL);
+
+	g_ril_unref(data->ril);
+	g_free(data);
+}
+
+static struct ofono_call_barring_driver driver = {
+	.name			= "rilmodem",
+	.probe			= ril_call_barring_probe,
+	.remove			= ril_call_barring_remove,
+	.query			= ril_call_barring_query,
+	.set			= ril_call_barring_set,
+	.set_passwd		= ril_call_barring_set_passwd
+};
+
+void ril_call_barring_init(void)
+{
+	ofono_call_barring_driver_register(&driver);
+}
+
+void ril_call_barring_exit(void)
+{
+	ofono_call_barring_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/call-forwarding.c b/drivers/rilmodem/call-forwarding.c
new file mode 100644
index 0000000..7965e7d
--- /dev/null
+++ b/drivers/rilmodem/call-forwarding.c
@@ -0,0 +1,327 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013 Jolla Ltd
+ *  Contact: Jussi Kangas <jussi.kangas@tieto.com>
+ *  Copyright (C) 2014 Canonical Ltd.
+ *
+ *  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 <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-forwarding.h>
+
+#include "gril.h"
+#include "grilrequest.h"
+#include "grilreply.h"
+#include "grilunsol.h"
+
+#include "rilmodem.h"
+
+#include "common.h"
+
+enum cf_action {
+	CF_ACTION_DISABLE,
+	CF_ACTION_ENABLE,
+	CF_ACTION_INTERROGATE,
+	CF_ACTION_REGISTRATION,
+	CF_ACTION_ERASURE,
+};
+
+struct forw_data {
+	GRil *ril;
+	enum cf_action last_action;
+	int last_cls;
+};
+
+static const char *cf_action_to_string(enum cf_action action)
+{
+	switch (action) {
+	case CF_ACTION_DISABLE:
+		return "DISABLE";
+	case CF_ACTION_ENABLE:
+		return "ENABLE";
+	case CF_ACTION_INTERROGATE:
+		return "INTERROGATE";
+	case CF_ACTION_REGISTRATION:
+		return "REGISTRATION";
+	case CF_ACTION_ERASURE:
+		return "ERASURE";
+	}
+
+	return NULL;
+}
+
+static void ril_query_call_fwd_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct forw_data *fd = ofono_call_forwarding_get_data(cbd->user);
+	ofono_call_forwarding_query_cb_t cb = cbd->cb;
+	struct ofono_call_forwarding_condition *list;
+	unsigned int list_size;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: rild error: %s", __func__,
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	list = g_ril_reply_parse_query_call_fwd(fd->ril, message, &list_size);
+	/*
+	 * From atmodem:
+	 *
+	 * Specification is really unclear about this
+	 * generate status=0 for all classes just in case
+	 */
+	if (list_size == 0) {
+		list = g_new0(struct ofono_call_forwarding_condition, 1);
+		list_size = 1;
+
+		list->status = 0;
+		list->cls = fd->last_cls;
+	} else if (list == NULL) {
+		goto error;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, (int) list_size, list, cbd->data);
+	g_free(list);
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+}
+
+static void ril_set_forward_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_call_forwarding_set_cb_t cb = cbd->cb;
+	struct forw_data *fd = ofono_call_forwarding_get_data(cbd->user);
+
+	if (message->error == RIL_E_SUCCESS) {
+		g_ril_print_response_no_args(fd->ril, message);
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	} else {
+		ofono_error("%s: CF %s failed; rild error: %s", __func__,
+				cf_action_to_string(fd->last_action),
+				ril_error_to_string(message->error));
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+}
+
+static int ril_send_forward_cmd(int type, int cls,
+				const struct ofono_phone_number *number,
+				int time,
+				struct cb_data *cbd,
+				enum cf_action action)
+{
+	struct ofono_call_forwarding *cf = cbd->user;
+	struct forw_data *fd = ofono_call_forwarding_get_data(cf);
+	struct parcel rilp;
+	struct req_call_fwd fwd_req;
+	int ret = 0, request;
+	GRilResponseFunc response_func;
+
+	if (action == CF_ACTION_INTERROGATE) {
+		request = RIL_REQUEST_QUERY_CALL_FORWARD_STATUS;
+		response_func = ril_query_call_fwd_cb;
+	} else {
+		request = RIL_REQUEST_SET_CALL_FORWARD;
+		response_func = ril_set_forward_cb;
+	}
+
+	DBG("%s - %s", ril_request_id_to_string(request),
+		cf_action_to_string(action));
+
+	/*
+	 * Modem seems to respond with error to all queries
+	 * or settings made with bearer class
+	 * BEARER_CLASS_DEFAULT. Design decision: If given
+	 * class is BEARER_CLASS_DEFAULT let's map it to
+	 * SERVICE_CLASS_NONE as with it e.g. ./send-ussd '*21*<phone_number>#'
+	 * returns cls:53 i.e. 1+4+16+32 as service class.
+	*/
+	if (cls == BEARER_CLASS_DEFAULT)
+		cls = SERVICE_CLASS_NONE;
+
+	fd->last_action = action;
+	fd->last_cls = cls;
+
+	fwd_req.action = (int) action;
+	fwd_req.type = type;
+	fwd_req.cls = cls;
+	fwd_req.number = number;
+
+	/*
+	 * time has no real meaing for action commands other
+	 * then registration, so if not needed, set arbitrary
+	 * 60s time so rild doesn't return an error.
+	 */
+	if (time == -1)
+		fwd_req.time = 60;
+	else
+		fwd_req.time = time;
+
+	g_ril_request_call_fwd(fd->ril, &fwd_req, &rilp);
+
+	ret = g_ril_send(fd->ril, request, &rilp, response_func, cbd, g_free);
+	if (ret == 0)
+		ofono_error("%s: CF action %s failed", __func__,
+				cf_action_to_string(action));
+	return ret;
+}
+
+static void ril_activate(struct ofono_call_forwarding *cf,
+				int type, int cls,
+				ofono_call_forwarding_set_cb_t cb, void *data)
+{
+	struct cb_data *cbd = cb_data_new(cb, data, cf);
+
+	if (ril_send_forward_cmd(type, cls, NULL, -1, cbd,
+					CF_ACTION_ENABLE) == 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+	}
+}
+
+static void ril_erasure(struct ofono_call_forwarding *cf,
+				int type, int cls,
+				ofono_call_forwarding_set_cb_t cb, void *data)
+{
+	struct cb_data *cbd = cb_data_new(cb, data, cf);
+
+	if (ril_send_forward_cmd(type, cls, NULL, -1, cbd,
+					CF_ACTION_ERASURE) == 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+	}
+}
+
+static void ril_deactivate(struct ofono_call_forwarding *cf,
+				int type, int cls,
+				ofono_call_forwarding_set_cb_t cb, void *data)
+{
+	struct cb_data *cbd = cb_data_new(cb, data, cf);
+
+	if (ril_send_forward_cmd(type, cls, NULL, -1, cbd,
+					CF_ACTION_DISABLE) == 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+	}
+}
+
+static void ril_registration(struct ofono_call_forwarding *cf, int type,
+				int cls,
+				const struct ofono_phone_number *number,
+				int time, ofono_call_forwarding_set_cb_t cb,
+				void *data)
+{
+	struct cb_data *cbd = cb_data_new(cb, data, cf);
+
+	if (ril_send_forward_cmd(type, cls, number, time, cbd,
+					CF_ACTION_REGISTRATION) == 0) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+	}
+}
+
+static void ril_query(struct ofono_call_forwarding *cf, int type, int cls,
+				ofono_call_forwarding_query_cb_t cb,
+				void *data)
+{
+	struct cb_data *cbd = cb_data_new(cb, data, cf);
+
+	if (ril_send_forward_cmd(type, cls, NULL, -1, cbd,
+					CF_ACTION_INTERROGATE) == 0) {
+		CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+		g_free(cbd);
+	}
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_call_forwarding *cf = user_data;
+
+	ofono_call_forwarding_register(cf);
+	return FALSE;
+}
+
+static int ril_call_forwarding_probe(struct ofono_call_forwarding *cf,
+					unsigned int vendor, void *user)
+{
+	GRil *ril = user;
+	struct forw_data *fd;
+
+	fd = g_try_new0(struct forw_data, 1);
+	if (fd == NULL)
+		return -ENOMEM;
+
+	fd->ril = g_ril_clone(ril);
+	ofono_call_forwarding_set_data(cf, fd);
+
+	/*
+	 * ofono_call_forwarding_register() needs to be called after
+	 * the driver has been set in ofono_call_forwarding_create(),
+	 * which calls this function.  Most other drivers make
+	 * some kind of capabilities query to the modem, and then
+	 * call register in the callback; we use an idle event instead.
+	 */
+	g_idle_add(ril_delayed_register, cf);
+
+	return 0;
+}
+
+static void ril_call_forwarding_remove(struct ofono_call_forwarding *cf)
+{
+	struct forw_data *data = ofono_call_forwarding_get_data(cf);
+	ofono_call_forwarding_set_data(cf, NULL);
+
+	g_ril_unref(data->ril);
+	g_free(data);
+}
+
+static struct ofono_call_forwarding_driver driver = {
+	.name			= RILMODEM,
+	.probe			= ril_call_forwarding_probe,
+	.remove			= ril_call_forwarding_remove,
+	.erasure		= ril_erasure,
+	.deactivation		= ril_deactivate,
+	.query			= ril_query,
+	.registration		= ril_registration,
+	.activation		= ril_activate
+};
+
+void ril_call_forwarding_init(void)
+{
+	ofono_call_forwarding_driver_register(&driver);
+}
+
+void ril_call_forwarding_exit(void)
+{
+	ofono_call_forwarding_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/call-settings.c b/drivers/rilmodem/call-settings.c
new file mode 100644
index 0000000..5603fbd
--- /dev/null
+++ b/drivers/rilmodem/call-settings.c
@@ -0,0 +1,286 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013 Jolla Ltd
+ *  Copyright (C) 2013 Canonical Ltd
+ *  Contact: Jussi Kangas <jussi.kangas@tieto.com>
+ *
+ *  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 <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-settings.h>
+
+#include "gril.h"
+#include "grilutil.h"
+#include "grilrequest.h"
+#include "grilreply.h"
+
+#include "rilmodem.h"
+#include "ril_constants.h"
+#include "common.h"
+
+struct settings_data {
+	GRil *ril;
+};
+
+static void ril_set_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_call_settings *cs = cbd->user;
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	ofono_call_settings_set_cb_t cb = cbd->cb;
+
+	if (message->error == RIL_E_SUCCESS) {
+		g_ril_print_response_no_args(sd->ril, message);
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	} else {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+}
+
+static void ril_cw_set(struct ofono_call_settings *cs, int mode, int cls,
+			ofono_call_settings_set_cb_t cb, void *data)
+{
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	struct cb_data *cbd = cb_data_new(cb, data, cs);
+	int ret;
+	struct parcel rilp;
+
+	g_ril_request_set_call_waiting(sd->ril, mode, cls, &rilp);
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_SET_CALL_WAITING, &rilp,
+				ril_set_cb, cbd, g_free);
+
+	/* In case of error free cbd and return the cb with failure */
+	if (ret <= 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void ril_cw_query_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_call_settings *cs = cbd->user;
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	ofono_call_settings_status_cb_t cb = cbd->cb;
+
+	if (message->error == RIL_E_SUCCESS) {
+		int res;
+
+		res = g_ril_reply_parse_query_call_waiting(sd->ril, message);
+
+		CALLBACK_WITH_SUCCESS(cb, res, cbd->data);
+	} else {
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+	}
+}
+
+static void ril_cw_query(struct ofono_call_settings *cs, int cls,
+				ofono_call_settings_status_cb_t cb, void *data)
+{
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	struct cb_data *cbd = cb_data_new(cb, data, cs);
+	int ret;
+	struct parcel rilp;
+
+	g_ril_request_query_call_waiting(sd->ril, cls, &rilp);
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_QUERY_CALL_WAITING, &rilp,
+				ril_cw_query_cb, cbd, g_free);
+
+	/* In case of error free cbd and return the cb with failure */
+	if (ret <= 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+	}
+}
+
+static void ril_clip_query_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_call_settings *cs = cbd->user;
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	ofono_call_settings_status_cb_t cb = cbd->cb;
+
+	if (message->error == RIL_E_SUCCESS) {
+		int res;
+
+		res = g_ril_reply_parse_query_clip(sd->ril, message);
+
+		CALLBACK_WITH_SUCCESS(cb, res, cbd->data);
+	} else {
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+	}
+}
+
+static void ril_clip_query(struct ofono_call_settings *cs,
+			ofono_call_settings_status_cb_t cb, void *data)
+{
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	struct cb_data *cbd = cb_data_new(cb, data, cs);
+	int ret;
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_QUERY_CLIP, NULL,
+				ril_clip_query_cb, cbd, g_free);
+
+	/* In case of error free cbd and return the cb with failure */
+	if (ret <= 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+	}
+}
+
+static void ril_clir_query_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_call_settings *cs = cbd->user;
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	ofono_call_settings_clir_cb_t cb = cbd->cb;
+	struct reply_clir *rclir;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: Reply failure: %s", __func__,
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	rclir = g_ril_reply_parse_get_clir(sd->ril, message);
+	if (rclir == NULL) {
+		ofono_error("%s: parse error", __func__);
+		goto error;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, rclir->status, rclir->provisioned, cbd->data);
+
+	g_ril_reply_free_get_clir(rclir);
+
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, -1, cbd->data);
+}
+
+static void ril_clir_query(struct ofono_call_settings *cs,
+			ofono_call_settings_clir_cb_t cb, void *data)
+{
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	struct cb_data *cbd = cb_data_new(cb, data, cs);
+	int ret;
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_GET_CLIR, NULL,
+				ril_clir_query_cb, cbd, g_free);
+
+	if (ret <= 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, -1, -1, data);
+	}
+}
+
+
+static void ril_clir_set(struct ofono_call_settings *cs, int mode,
+			ofono_call_settings_set_cb_t cb, void *data)
+{
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	struct cb_data *cbd = cb_data_new(cb, data, cs);
+	struct parcel rilp;
+	int ret;
+
+	g_ril_request_set_clir(sd->ril, mode, &rilp);
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_SET_CLIR, &rilp,
+				ril_set_cb, cbd, g_free);
+
+	if (ret <= 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_call_settings *cs = user_data;
+
+	ofono_call_settings_register(cs);
+
+	return FALSE;
+}
+
+static int ril_call_settings_probe(struct ofono_call_settings *cs,
+					unsigned int vendor, void *user)
+{
+	GRil *ril = user;
+	struct settings_data *sd = g_new0(struct settings_data, 1);
+
+	sd->ril = g_ril_clone(ril);
+
+	ofono_call_settings_set_data(cs, sd);
+
+	g_idle_add(ril_delayed_register, cs);
+
+	return 0;
+}
+
+static void ril_call_settings_remove(struct ofono_call_settings *cs)
+{
+	struct settings_data *sd = ofono_call_settings_get_data(cs);
+	ofono_call_settings_set_data(cs, NULL);
+
+	g_ril_unref(sd->ril);
+	g_free(sd);
+}
+
+static struct ofono_call_settings_driver driver = {
+	.name			= RILMODEM,
+	.probe			= ril_call_settings_probe,
+	.remove			= ril_call_settings_remove,
+	.clip_query		= ril_clip_query,
+	.cw_query		= ril_cw_query,
+	.cw_set			= ril_cw_set,
+	.clir_query		= ril_clir_query,
+	.clir_set		= ril_clir_set
+
+	/*
+	 * Not supported in RIL API
+	 * .colp_query		= ril_colp_query,
+	 * .colr_query		= ril_colr_query
+	 */
+};
+
+void ril_call_settings_init(void)
+{
+	ofono_call_settings_driver_register(&driver);
+}
+
+void ril_call_settings_exit(void)
+{
+	ofono_call_settings_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/call-volume.c b/drivers/rilmodem/call-volume.c
new file mode 100644
index 0000000..4e88772
--- /dev/null
+++ b/drivers/rilmodem/call-volume.c
@@ -0,0 +1,182 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2013 Canonical Ltd.
+ *
+ *  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 <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-volume.h>
+
+#include "gril.h"
+#include "grilutil.h"
+
+#include "common.h"
+
+#include "rilmodem.h"
+#include "parcel.h"
+#include "grilrequest.h"
+#include "grilreply.h"
+
+struct cv_data {
+	GRil *ril;
+	unsigned int vendor;
+};
+
+static void volume_mute_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_call_volume_cb_t cb = cbd->cb;
+	struct cv_data *cvd = cbd->user;
+	struct ofono_error error;
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+
+		g_ril_print_response_no_args(cvd->ril, message);
+
+	} else {
+		ofono_error("Could not set the ril mute state");
+		decode_ril_error(&error, "FAIL");
+	}
+
+	cb(&error, cbd->data);
+}
+
+static void ril_call_volume_mute(struct ofono_call_volume *cv, int muted,
+					ofono_call_volume_cb_t cb, void *data)
+{
+	struct cv_data *cvd = ofono_call_volume_get_data(cv);
+	struct cb_data *cbd = cb_data_new(cb, data, cvd);
+	struct parcel rilp;
+
+	DBG("Initial ril muted state: %d", muted);
+
+	g_ril_request_set_mute(cvd->ril, muted, &rilp);
+
+	if (g_ril_send(cvd->ril, RIL_REQUEST_SET_MUTE, &rilp,
+			volume_mute_cb, cbd, g_free) == 0) {
+		ofono_error("Send RIL_REQUEST_SET_MUTE failed.");
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void probe_mute_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_call_volume *cv = user_data;
+	struct cv_data *cvd = ofono_call_volume_get_data(cv);
+	int muted;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("Could not retrieve the ril mute state");
+		return;
+	}
+
+	muted = g_ril_reply_parse_get_mute(cvd->ril, message);
+
+	ofono_call_volume_set_muted(cv, muted);
+}
+
+static void call_probe_mute(gpointer user_data)
+{
+	struct ofono_call_volume *cv = user_data;
+	struct cv_data *cvd = ofono_call_volume_get_data(cv);
+
+	g_ril_send(cvd->ril, RIL_REQUEST_GET_MUTE, NULL,
+			probe_mute_cb, cv, NULL);
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_call_volume *cv = user_data;
+	DBG("");
+	ofono_call_volume_register(cv);
+
+	/* Probe the mute state */
+	call_probe_mute(user_data);
+
+	/* This makes the timeout a single-shot */
+	return FALSE;
+}
+
+static int ril_call_volume_probe(struct ofono_call_volume *cv,
+					unsigned int vendor, void *data)
+{
+	GRil *ril = data;
+	struct cv_data *cvd;
+
+	cvd = g_new0(struct cv_data, 1);
+	if (cvd == NULL)
+		return -ENOMEM;
+
+	cvd->ril = g_ril_clone(ril);
+	cvd->vendor = vendor;
+
+	ofono_call_volume_set_data(cv, cvd);
+
+	/*
+	 * ofono_call_volume_register() needs to be called after
+	 * the driver has been set in ofono_call_volume_create(),
+	 * which calls this function.  Most other drivers make
+	 * some kind of capabilities query to the modem, and then
+	 * call register in the callback; we use an idle event instead.
+	 */
+	g_idle_add(ril_delayed_register, cv);
+
+	return 0;
+}
+
+static void ril_call_volume_remove(struct ofono_call_volume *cv)
+{
+	struct cv_data *cvd = ofono_call_volume_get_data(cv);
+
+	ofono_call_volume_set_data(cv, NULL);
+
+	g_ril_unref(cvd->ril);
+	g_free(cvd);
+}
+
+static struct ofono_call_volume_driver driver = {
+	.name = RILMODEM,
+	.probe = ril_call_volume_probe,
+	.remove = ril_call_volume_remove,
+	.mute = ril_call_volume_mute,
+};
+
+void ril_call_volume_init(void)
+{
+	ofono_call_volume_driver_register(&driver);
+}
+
+void ril_call_volume_exit(void)
+{
+	ofono_call_volume_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/devinfo.c b/drivers/rilmodem/devinfo.c
new file mode 100644
index 0000000..2811837
--- /dev/null
+++ b/drivers/rilmodem/devinfo.c
@@ -0,0 +1,218 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL Modem Support
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2013 Canonical Ltd.
+ *
+ *  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 <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+
+#include "gril.h"
+
+#include "rilmodem.h"
+#include "grilreply.h"
+
+/*
+ * TODO: The functions in this file are stubbed out, and
+ * will need to be re-worked to talk to the /gril layer
+ * in order to get real values from RILD.
+ */
+
+static void ril_query_manufacturer(struct ofono_devinfo *info,
+					ofono_devinfo_query_cb_t cb,
+					void *data)
+{
+	const char *attr = "Fake Manufacturer";
+	struct cb_data *cbd = cb_data_new(cb, data, NULL);
+	struct ofono_error error;
+	decode_ril_error(&error, "OK");
+
+	cb(&error, attr, cbd->data);
+
+	/* Note: this will need to change if cbd passed to gril layer */
+	g_free(cbd);
+}
+
+static void ril_query_model(struct ofono_devinfo *info,
+				ofono_devinfo_query_cb_t cb,
+				void *data)
+{
+	const char *attr = "Fake Modem Model";
+	struct cb_data *cbd = cb_data_new(cb, data, NULL);
+	struct ofono_error error;
+	decode_ril_error(&error, "OK");
+
+	cb(&error, attr, cbd->data);
+
+	/* Note: this will need to change if cbd passed to gril layer */
+	g_free(cbd);
+}
+
+static void query_revision_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_devinfo_query_cb_t cb = cbd->cb;
+	GRil *ril = cbd->user;
+	struct ofono_error error;
+	char *revision;
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+	} else {
+		decode_ril_error(&error, "FAIL");
+		cb(&error, NULL, cbd->data);
+		return;
+	}
+
+	revision = g_ril_reply_parse_baseband_version(ril, message);
+
+	cb(&error, revision, cbd->data);
+
+	g_free(revision);
+}
+
+static void ril_query_revision(struct ofono_devinfo *info,
+				ofono_devinfo_query_cb_t cb,
+				void *data)
+{
+	GRil *ril = ofono_devinfo_get_data(info);
+	struct cb_data *cbd = cb_data_new(cb, data, ril);
+
+	if (g_ril_send(ril, RIL_REQUEST_BASEBAND_VERSION, NULL,
+			query_revision_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, NULL, data);
+	}
+}
+
+static void query_serial_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_devinfo_query_cb_t cb = cbd->cb;
+	GRil *ril = cbd->user;
+	struct ofono_error error;
+	gchar *imei;
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+	} else {
+		decode_ril_error(&error, "FAIL");
+		cb(&error, NULL, cbd->data);
+		return;
+	}
+
+	imei = g_ril_reply_parse_baseband_version(ril, message);
+
+	cb(&error, imei, cbd->data);
+
+	g_free(imei);
+}
+
+static void ril_query_serial(struct ofono_devinfo *info,
+				ofono_devinfo_query_cb_t cb,
+				void *data)
+{
+	GRil *ril = ofono_devinfo_get_data(info);
+	struct cb_data *cbd = cb_data_new(cb, data, ril);
+
+	/*
+	 * TODO: make it support both RIL_REQUEST_GET_IMEI (deprecated) and
+	 * RIL_REQUEST_DEVICE_IDENTITY depending on the rild version used
+	 */
+
+	if (g_ril_send(ril, RIL_REQUEST_GET_IMEI, NULL,
+			query_serial_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, NULL, data);
+	}
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_devinfo *info = user_data;
+	DBG("");
+	ofono_devinfo_register(info);
+
+	/* This makes the timeout a single-shot */
+	return FALSE;
+}
+
+static int ril_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
+				void *data)
+{
+	GRil *ril = NULL;
+
+	if (data != NULL)
+		ril = g_ril_clone(data);
+
+	ofono_devinfo_set_data(info, ril);
+
+	/*
+	 * ofono_devinfo_register() needs to be called after
+	 * the driver has been set in ofono_devinfo_create(),
+	 * which calls this function.  Most other drivers make
+	 * some kind of capabilities query to the modem, and then
+	 * call register in the callback; we use an idle event instead.
+	 */
+	g_idle_add(ril_delayed_register, info);
+
+	return 0;
+}
+
+static void ril_devinfo_remove(struct ofono_devinfo *info)
+{
+	GRil *ril = ofono_devinfo_get_data(info);
+
+	ofono_devinfo_set_data(info, NULL);
+
+	g_ril_unref(ril);
+}
+
+static struct ofono_devinfo_driver driver = {
+	.name			= RILMODEM,
+	.probe			= ril_devinfo_probe,
+	.remove			= ril_devinfo_remove,
+	.query_manufacturer	= ril_query_manufacturer,
+	.query_model		= ril_query_model,
+	.query_revision		= ril_query_revision,
+	.query_serial		= ril_query_serial
+};
+
+void ril_devinfo_init(void)
+{
+	ofono_devinfo_driver_register(&driver);
+}
+
+void ril_devinfo_exit(void)
+{
+	ofono_devinfo_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/gprs-context.c b/drivers/rilmodem/gprs-context.c
new file mode 100644
index 0000000..2021533
--- /dev/null
+++ b/drivers/rilmodem/gprs-context.c
@@ -0,0 +1,585 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013 Canonical Ltd.
+ *
+ *  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 <sys/stat.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs-context.h>
+#include <ofono/types.h>
+
+#include "ofono.h"
+
+#include "grilreply.h"
+#include "grilrequest.h"
+#include "grilunsol.h"
+
+#include "gprs.h"
+#include "rilmodem.h"
+
+#define NUM_DEACTIVATION_RETRIES 4
+#define TIME_BETWEEN_DEACT_RETRIES_S 2
+
+enum state {
+	STATE_IDLE,
+	STATE_ENABLING,
+	STATE_DISABLING,
+	STATE_ACTIVE,
+};
+
+struct gprs_context_data {
+	GRil *ril;
+	struct ofono_modem *modem;
+	unsigned vendor;
+	gint active_ctx_cid;
+	gint active_rild_cid;
+	enum state state;
+	guint call_list_id;
+	char *apn;
+	enum ofono_gprs_context_type type;
+	int deact_retries;
+	guint retry_ev_id;
+	struct cb_data *retry_cbd;
+	guint reset_ev_id;
+};
+
+static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
+						unsigned int id,
+						ofono_gprs_context_cb_t cb,
+						void *data);
+static void ril_deactivate_data_call_cb(struct ril_msg *message,
+					gpointer user_data);
+
+static void set_context_disconnected(struct gprs_context_data *gcd)
+{
+	DBG("");
+
+	gcd->active_ctx_cid = -1;
+	gcd->active_rild_cid = -1;
+	gcd->state = STATE_IDLE;
+	g_free(gcd->apn);
+	gcd->apn = NULL;
+}
+
+static void disconnect_context(struct ofono_gprs_context *gc)
+{
+	ril_gprs_context_deactivate_primary(gc, 0, NULL, NULL);
+}
+
+static void ril_gprs_context_call_list_changed(struct ril_msg *message,
+						gpointer user_data)
+{
+	struct ofono_gprs_context *gc = user_data;
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct ril_data_call *call = NULL;
+	struct ril_data_call_list *call_list;
+	gboolean active_cid_found = FALSE;
+	gboolean disconnect = FALSE;
+	GSList *iterator = NULL;
+
+	call_list = g_ril_unsol_parse_data_call_list(gcd->ril, message);
+	if (call_list == NULL)
+		return;
+
+	DBG("*gc: %p num calls: %d", gc, g_slist_length(call_list->calls));
+
+	for (iterator = call_list->calls; iterator; iterator = iterator->next) {
+		call = (struct ril_data_call *) iterator->data;
+
+		if (call->cid == gcd->active_rild_cid) {
+			active_cid_found = TRUE;
+			DBG("found call - cid: %d", call->cid);
+
+			if (call->active == 0) {
+				DBG("call !active; notify disconnect: %d",
+					call->cid);
+				disconnect = TRUE;
+			}
+
+			break;
+		}
+	}
+
+	if ((disconnect == TRUE || active_cid_found == FALSE)
+		&& gcd->state != STATE_IDLE) {
+		ofono_info("Clearing active context; disconnect: %d"
+			" active_cid_found: %d active_ctx_cid: %d",
+			disconnect, active_cid_found, gcd->active_ctx_cid);
+
+		ofono_gprs_context_deactivated(gc, gcd->active_ctx_cid);
+		set_context_disconnected(gcd);
+	}
+
+	g_ril_unsol_free_data_call_list(call_list);
+}
+
+static void ril_setup_data_call_cb(struct ril_msg *message, gpointer 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 ril_data_call *call = NULL;
+	struct ril_data_call_list *call_list = NULL;
+
+	DBG("*gc: %p", gc);
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: setup data call failed for apn: %s - %s",
+				__func__, gcd->apn,
+				ril_error_to_string(message->error));
+
+		set_context_disconnected(gcd);
+		goto error;
+	}
+
+	call_list = g_ril_unsol_parse_data_call_list(gcd->ril, message);
+	if (call_list == NULL) {
+		/* parsing failed, need to actually disconnect */
+		disconnect_context(gc);
+		goto error;
+	}
+
+	if (g_slist_length(call_list->calls) != 1) {
+		ofono_error("%s: setup_data_call reply for apn: %s,"
+				" includes %d calls",
+				__func__, gcd->apn,
+				g_slist_length(call_list->calls));
+
+		disconnect_context(gc);
+		goto error;
+	}
+
+	call = (struct ril_data_call *) call_list->calls->data;
+
+	/* Check for valid DNS settings, except for MMS contexts */
+	if (gcd->type != OFONO_GPRS_CONTEXT_TYPE_MMS
+				&& (call->dns_addrs == NULL
+				|| g_strv_length(call->dns_addrs) == 0)) {
+		ofono_error("%s: no DNS in context of type %d",
+				__func__, gcd->type);
+		disconnect_context(gc);
+		goto error;
+	}
+
+	if (call->status != PDP_FAIL_NONE) {
+		ofono_error("%s: reply->status for apn: %s, is non-zero: %s",
+				__func__, gcd->apn,
+				ril_pdp_fail_to_string(call->status));
+
+		set_context_disconnected(gcd);
+		goto error;
+	}
+
+	gcd->active_rild_cid = call->cid;
+	gcd->state = STATE_ACTIVE;
+
+	ofono_gprs_context_set_interface(gc, call->ifname);
+	ofono_gprs_context_set_ipv4_netmask(gc,
+					ril_util_get_netmask(call->ip_addr));
+
+	ofono_gprs_context_set_ipv4_address(gc, call->ip_addr, TRUE);
+	ofono_gprs_context_set_ipv4_gateway(gc, call->gateways[0]);
+
+	ofono_gprs_context_set_ipv4_dns_servers(gc,
+					(const char **) call->dns_addrs);
+
+	g_ril_unsol_free_data_call_list(call_list);
+
+	/* activate listener for data call changed events.... */
+	gcd->call_list_id =
+		g_ril_register(gcd->ril,
+				RIL_UNSOL_DATA_CALL_LIST_CHANGED,
+				ril_gprs_context_call_list_changed, gc);
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	return;
+
+error:
+	g_ril_unsol_free_data_call_list(call_list);
+
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void ril_gprs_context_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 ofono_modem *modem = ofono_gprs_context_get_modem(gc);
+	struct ofono_atom *gprs_atom =
+		__ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_GPRS);
+	struct ofono_gprs *gprs = NULL;
+	struct ril_gprs_data *gd = NULL;
+	struct cb_data *cbd = cb_data_new(cb, data, gc);
+	struct req_setup_data_call request;
+	struct parcel rilp;
+	struct ofono_error error;
+	int ret = 0;
+
+	g_assert(gprs_atom != NULL);
+	gprs = __ofono_atom_get_data(gprs_atom);
+	g_assert(gprs != NULL);
+	gd = ofono_gprs_get_data(gprs);
+	g_assert(gd != NULL);
+
+	/*
+	 * 0: CDMA 1: GSM/UMTS, 2...
+	 * anything 2+ is a RadioTechnology value +2
+	 */
+	DBG("*gc: %p activating cid: %d; curr_tech: %d", gc, ctx->cid,
+		gd->tech);
+
+	if (gd->tech == RADIO_TECH_UNKNOWN) {
+		ofono_error("%s: radio tech for apn: %s UNKNOWN!", __func__,
+				gcd->apn);
+		request.tech = 1;
+	} else {
+		request.tech = gd->tech + 2;
+	}
+
+	/*
+	 * TODO: add comments about tethering, other non-public
+	 * profiles...
+	 */
+	if (g_ril_vendor(gcd->ril) == OFONO_RIL_VENDOR_MTK &&
+			gcd->type == OFONO_GPRS_CONTEXT_TYPE_MMS)
+		request.data_profile = RIL_DATA_PROFILE_MTK_MMS;
+	else
+		request.data_profile = RIL_DATA_PROFILE_DEFAULT;
+
+	request.apn = g_strdup(ctx->apn);
+	request.username = g_strdup(ctx->username);
+	request.password = g_strdup(ctx->password);
+
+	/*
+	 * We do the same as in $AOSP/frameworks/opt/telephony/src/java/com/
+	 * android/internal/telephony/dataconnection/DataConnection.java,
+	 * onConnect(), and use authentication or not depending on whether
+	 * the user field is empty or not.
+	 */
+	if (request.username != NULL && request.username[0] != '\0')
+		request.auth_type = RIL_AUTH_BOTH;
+	else
+		request.auth_type = RIL_AUTH_NONE;
+
+	request.protocol = ctx->proto;
+	request.req_cid = ctx->cid;
+
+	if (g_ril_request_setup_data_call(gcd->ril,
+						&request,
+						&rilp,
+						&error) == FALSE) {
+		ofono_error("%s: couldn't build SETUP_DATA_CALL"
+				" request for apn: %s.",
+				__func__, request.apn);
+		goto error;
+	}
+
+	gcd->active_ctx_cid = ctx->cid;
+	gcd->state = STATE_ENABLING;
+	gcd->apn = g_strdup(ctx->apn);
+
+	ret = g_ril_send(gcd->ril, RIL_REQUEST_SETUP_DATA_CALL, &rilp,
+				ril_setup_data_call_cb, cbd, g_free);
+
+error:
+	g_free(request.apn);
+	g_free(request.username);
+	g_free(request.password);
+
+	if (ret == 0) {
+		ofono_error("%s: send SETUP_DATA_CALL failed for apn: %s.",
+				__func__, gcd->apn);
+
+		set_context_disconnected(gcd);
+
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static gboolean reset_modem(gpointer data)
+{
+	/* TODO call mtk_reset_modem when driver is upstreamed */
+	return FALSE;
+}
+
+static gboolean retry_deactivate(gpointer 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 req_deactivate_data_call request;
+	struct parcel rilp;
+	struct ofono_error error;
+
+	gcd->retry_ev_id = 0;
+
+	/* We might have received a call list update while waiting */
+	if (gcd->state == STATE_IDLE) {
+		if (cb)
+			CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+		g_free(cbd);
+
+		return FALSE;
+	}
+
+	request.cid = gcd->active_rild_cid;
+	request.reason = RIL_DEACTIVATE_DATA_CALL_NO_REASON;
+
+	g_ril_request_deactivate_data_call(gcd->ril, &request, &rilp, &error);
+
+	if (g_ril_send(gcd->ril, RIL_REQUEST_DEACTIVATE_DATA_CALL, &rilp,
+			ril_deactivate_data_call_cb, cbd, g_free) == 0) {
+
+		ofono_error("%s: send DEACTIVATE_DATA_CALL failed for apn: %s",
+				__func__, gcd->apn);
+		if (cb)
+			CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+		g_free(cbd);
+	}
+
+	return FALSE;
+}
+
+static void ril_deactivate_data_call_cb(struct ril_msg *message,
+					gpointer 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);
+	gint active_ctx_cid;
+
+	DBG("*gc: %p", gc);
+
+	if (message->error == RIL_E_SUCCESS) {
+
+		g_ril_print_response_no_args(gcd->ril, message);
+
+		active_ctx_cid = gcd->active_ctx_cid;
+		set_context_disconnected(gcd);
+
+		/*
+		 * If the deactivate was a result of a data network detach or of
+		 * an error in data call establishment, there won't be call
+		 * back, so _deactivated() needs to be called directly.
+		 */
+		if (cb)
+			CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		else
+			ofono_gprs_context_deactivated(gc, active_ctx_cid);
+
+	} else {
+		ofono_error("%s: reply failure for apn: %s - %s",
+				__func__, gcd->apn,
+				ril_error_to_string(message->error));
+
+		/*
+		 * It has been detected that some modems fail the deactivation
+		 * temporarily. We do retries to handle that case.
+		 */
+		if (--(gcd->deact_retries) > 0) {
+			gcd->retry_cbd = cb_data_new(cb, cbd->data, gc);
+			gcd->retry_ev_id =
+				g_timeout_add_seconds(
+					TIME_BETWEEN_DEACT_RETRIES_S,
+					retry_deactivate, gcd->retry_cbd);
+		} else {
+			ofono_error("%s: retry limit hit", __func__);
+
+			if (cb)
+				CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+			/*
+			 * Reset modem if MTK. TODO Failures deactivating a
+			 * context have not been reported for other modems, but
+			 * it would be good to have a generic method to force an
+			 * internal reset nonetheless.
+			 */
+			if (gcd->vendor == OFONO_RIL_VENDOR_MTK)
+				gcd->reset_ev_id = g_idle_add(reset_modem, gcd);
+		}
+	}
+}
+
+static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc,
+					unsigned int id,
+					ofono_gprs_context_cb_t cb, void *data)
+{
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct cb_data *cbd = NULL;
+	struct parcel rilp;
+	struct req_deactivate_data_call request;
+	struct ofono_error error;
+	int ret = 0;
+
+	DBG("*gc: %p cid: %d active_rild_cid: %d", gc, id,
+		gcd->active_rild_cid);
+
+	if (gcd->state == STATE_IDLE || gcd->state == STATE_DISABLING) {
+		/* nothing to do */
+
+		if (cb) {
+			CALLBACK_WITH_SUCCESS(cb, data);
+			g_free(cbd);
+		}
+
+		return;
+	}
+
+	cbd = cb_data_new(cb, data, gc);
+
+	gcd->state = STATE_DISABLING;
+	if (g_ril_unregister(gcd->ril, gcd->call_list_id) == FALSE) {
+		ofono_warn("%s: couldn't remove call_list listener"
+				" for apn: %s.",
+				__func__, gcd->apn);
+	}
+
+	request.cid = gcd->active_rild_cid;
+	request.reason = RIL_DEACTIVATE_DATA_CALL_NO_REASON;
+
+	if (g_ril_request_deactivate_data_call(gcd->ril, &request,
+						&rilp, &error) == FALSE) {
+
+		ofono_error("%s: couldn't build DEACTIVATE_DATA_CALL"
+				" request for apn: %s.",
+				__func__, gcd->apn);
+		goto error;
+	}
+
+	gcd->deact_retries = NUM_DEACTIVATION_RETRIES;
+	ret = g_ril_send(gcd->ril, RIL_REQUEST_DEACTIVATE_DATA_CALL, &rilp,
+				ril_deactivate_data_call_cb, cbd, g_free);
+
+error:
+	if (ret == 0) {
+		/* TODO: should we force state to disconnected here? */
+
+		ofono_error("%s: send DEACTIVATE_DATA_CALL failed for apn: %s",
+				__func__, gcd->apn);
+		g_free(cbd);
+		if (cb)
+			CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void ril_gprs_context_detach_shutdown(struct ofono_gprs_context *gc,
+						unsigned int id)
+{
+	DBG("*gc: %p cid: %d", gc, id);
+
+	ril_gprs_context_deactivate_primary(gc, 0, NULL, NULL);
+}
+
+static int ril_gprs_context_probe(struct ofono_gprs_context *gc,
+					unsigned int vendor, void *data)
+{
+	struct ril_gprs_context_data *ril_data = data;
+	struct gprs_context_data *gcd;
+
+	DBG("*gc: %p", gc);
+
+	gcd = g_try_new0(struct gprs_context_data, 1);
+	if (gcd == NULL)
+		return -ENOMEM;
+
+	gcd->ril = g_ril_clone(ril_data->gril);
+	gcd->modem = ril_data->modem;
+	gcd->vendor = vendor;
+	set_context_disconnected(gcd);
+	gcd->call_list_id = -1;
+	gcd->type = ril_data->type;
+
+	ofono_gprs_context_set_data(gc, gcd);
+
+	return 0;
+}
+
+static void ril_gprs_context_remove(struct ofono_gprs_context *gc)
+{
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+
+	DBG("*gc: %p", gc);
+
+	if (gcd->state != STATE_IDLE && gcd->state != STATE_DISABLING) {
+		struct req_deactivate_data_call request;
+		struct parcel rilp;
+		struct ofono_error error;
+
+		request.cid = gcd->active_rild_cid;
+		request.reason = RIL_DEACTIVATE_DATA_CALL_NO_REASON;
+		g_ril_request_deactivate_data_call(gcd->ril, &request,
+								&rilp, &error);
+
+		g_ril_send(gcd->ril, RIL_REQUEST_DEACTIVATE_DATA_CALL,
+						&rilp, NULL, NULL, NULL);
+	}
+
+	if (gcd->retry_ev_id > 0) {
+		g_source_remove(gcd->retry_ev_id);
+		g_free(gcd->retry_cbd);
+	}
+
+	if (gcd->reset_ev_id > 0)
+		g_source_remove(gcd->reset_ev_id);
+
+	ofono_gprs_context_set_data(gc, NULL);
+
+	g_ril_unref(gcd->ril);
+	g_free(gcd);
+}
+
+static struct ofono_gprs_context_driver driver = {
+	.name			= RILMODEM,
+	.probe			= ril_gprs_context_probe,
+	.remove			= ril_gprs_context_remove,
+	.activate_primary       = ril_gprs_context_activate_primary,
+	.deactivate_primary     = ril_gprs_context_deactivate_primary,
+	.detach_shutdown        = ril_gprs_context_detach_shutdown,
+};
+
+void ril_gprs_context_init(void)
+{
+	ofono_gprs_context_driver_register(&driver);
+}
+
+void ril_gprs_context_exit(void)
+{
+	ofono_gprs_context_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/gprs.c b/drivers/rilmodem/gprs.c
new file mode 100644
index 0000000..75dcfcc
--- /dev/null
+++ b/drivers/rilmodem/gprs.c
@@ -0,0 +1,487 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2010  ST-Ericsson AB.
+ *  Copyright (C) 2013 Canonical Ltd.
+ *  Copyright (C) 2013 Jolla Ltd.
+ *
+ *  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/gprs.h>
+#include <ofono/types.h>
+
+#include "gril.h"
+#include "grilutil.h"
+#include "common.h"
+#include "rilmodem.h"
+
+#include "grilreply.h"
+#include "grilrequest.h"
+#include "grilunsol.h"
+#include "gprs.h"
+
+/* Time between get data status retries */
+#define GET_STATUS_TIMER_MS 5000
+
+/*
+ * This module is the ofono_gprs_driver implementation for rilmodem.
+ *
+ * Notes:
+ *
+ * 1. ofono_gprs_suspend/resume() are not used by this module, as
+ *    the concept of suspended GPRS is not exposed by RILD.
+ */
+
+static int ril_tech_to_bearer_tech(int ril_tech)
+{
+	/*
+	 * This code handles the mapping between the RIL_RadioTechnology
+	 * and packet bearer values ( see <curr_bearer> values - 27.007
+	 * Section 7.29 ).
+	 */
+
+	switch (ril_tech) {
+	case RADIO_TECH_GSM:
+	case RADIO_TECH_UNKNOWN:
+		return PACKET_BEARER_NONE;
+	case RADIO_TECH_GPRS:
+		return PACKET_BEARER_GPRS;
+	case RADIO_TECH_EDGE:
+		return PACKET_BEARER_EGPRS;
+	case RADIO_TECH_UMTS:
+		return PACKET_BEARER_UMTS;
+	case RADIO_TECH_HSDPA:
+		return PACKET_BEARER_HSDPA;
+	case RADIO_TECH_HSUPA:
+		return PACKET_BEARER_HSUPA;
+	case RADIO_TECH_HSPAP:
+	case RADIO_TECH_HSPA:
+		/*
+		 * HSPAP is HSPA+; which ofono doesn't define;
+		 * so, if differentiating HSPA and HSPA+ is
+		 * important, then ofono needs to be patched,
+		 * and we probably also need to introduce a
+		 * new indicator icon.
+		 */
+		return PACKET_BEARER_HSUPA_HSDPA;
+	case RADIO_TECH_LTE:
+		return PACKET_BEARER_EPS;
+	default:
+		return PACKET_BEARER_NONE;
+	}
+}
+
+static void ril_gprs_state_change(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_gprs *gprs = user_data;
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+
+	g_ril_print_unsol_no_args(gd->ril, message);
+
+	/*
+	 * We just want to track network data status if ofono
+	 * itself is attached, so we avoid unnecessary data state requests.
+	 */
+	if (gd->ofono_attached == TRUE)
+		ril_gprs_registration_status(gprs, NULL, NULL);
+}
+
+gboolean ril_gprs_set_attached_cb(gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_gprs_cb_t cb = cbd->cb;
+
+	DBG("");
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	g_free(cbd);
+
+	/* Run once per g_idle_add() call */
+	return FALSE;
+}
+
+static void ril_gprs_set_attached(struct ofono_gprs *gprs, int attached,
+					ofono_gprs_cb_t cb, void *data)
+{
+	struct cb_data *cbd = cb_data_new(cb, data, NULL);
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+
+	DBG("attached: %d", attached);
+
+	/*
+	 * As RIL offers no actual control over the GPRS 'attached'
+	 * state, we save the desired state, and use it to override
+	 * the actual modem's state in the 'attached_status' function.
+	 * This is similar to the way the core ofono gprs code handles
+	 * data roaming ( see src/gprs.c gprs_netreg_update().
+	 *
+	 * The core gprs code calls driver->set_attached() when a netreg
+	 * notificaiton is received and any configured roaming conditions
+	 * are met.
+	 */
+	gd->ofono_attached = attached;
+
+	/*
+	 * Call from idle loop, so core can set driver_attached before
+	 * the callback is invoked.
+	 */
+	g_idle_add(ril_gprs_set_attached_cb, cbd);
+}
+
+static gboolean ril_get_status_retry(gpointer user_data)
+{
+	struct ofono_gprs *gprs = user_data;
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+
+	gd->status_retry_cb_id = 0;
+
+	ril_gprs_registration_status(gprs, NULL, NULL);
+
+	return FALSE;
+}
+
+static void ril_data_reg_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_gprs_status_cb_t cb = cbd->cb;
+	struct ofono_gprs *gprs = cbd->user;
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct reply_data_reg_state *reply;
+	gboolean attached = FALSE;
+	gboolean notify_status = FALSE;
+	int old_status;
+
+	old_status = gd->rild_status;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: DATA_REGISTRATION_STATE reply failure: %s",
+				__func__,
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	reply = g_ril_reply_parse_data_reg_state(gd->ril, message);
+	if (reply == NULL)
+		goto error;
+
+	/*
+	 * There are three cases that can result in this callback
+	 * running:
+	 *
+	 * 1) The driver's probe() method was called, and thus an
+	 *    internal call to ril_gprs_registration_status() is
+	 *    generated.  No ofono cb exists.
+	 *
+	 * 2) ril_gprs_state_change() is called due to an unsolicited
+	 *    event from RILD.  No ofono cb exists.
+	 *
+	 * 3) The ofono code code calls the driver's attached_status()
+	 *    function.  A valid ofono cb exists.
+	 */
+
+	if (gd->rild_status != reply->reg_state.status) {
+		gd->rild_status = reply->reg_state.status;
+
+		if (cb == NULL)
+			notify_status = TRUE;
+	}
+
+	/*
+	 * Override the actual status based upon the desired
+	 * attached status set by the core GPRS code ( controlled
+	 * by the ConnnectionManager's 'Powered' property ).
+	 */
+	attached = (reply->reg_state.status ==
+				NETWORK_REGISTRATION_STATUS_REGISTERED ||
+			reply->reg_state.status ==
+				NETWORK_REGISTRATION_STATUS_ROAMING);
+
+	if (attached && gd->ofono_attached == FALSE) {
+		DBG("attached=true; ofono_attached=false; return !REGISTERED");
+		reply->reg_state.status =
+			NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
+
+		/*
+		 * Further optimization so that if ril_status ==
+		 * NOT_REGISTERED, ofono_attached == false, and status ==
+		 * ROAMING | REGISTERED, then notify gets cleared...
+		 *
+		 * As is, this results in unecessary status notify calls
+		 * when nothing has changed.
+		 */
+		if (notify_status && reply->reg_state.status == old_status)
+			notify_status = FALSE;
+	}
+
+	if (old_status == -1) {
+		ofono_gprs_register(gprs);
+
+		/* Different rild implementations use different events here */
+		g_ril_register(gd->ril,
+				gd->state_changed_unsol,
+				ril_gprs_state_change, gprs);
+
+		if (reply->max_cids == 0)
+			gd->max_cids = RIL_MAX_NUM_ACTIVE_DATA_CALLS;
+		else if (reply->max_cids < RIL_MAX_NUM_ACTIVE_DATA_CALLS)
+			gd->max_cids = reply->max_cids;
+		else
+			gd->max_cids = RIL_MAX_NUM_ACTIVE_DATA_CALLS;
+
+		DBG("Setting max cids to %d", gd->max_cids);
+		ofono_gprs_set_cid_range(gprs, 1, gd->max_cids);
+
+		/*
+		 * This callback is a result of the inital call
+		 * to probe(), so should return after registration.
+		 */
+		g_free(reply);
+
+		return;
+	}
+
+	/* Just need to notify ofono if it's already attached */
+	if (notify_status) {
+
+		/*
+		 * If network disconnect has occurred, call detached_notify()
+		 * instead of status_notify().
+		 */
+		if (!attached &&
+			(old_status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
+				old_status ==
+					NETWORK_REGISTRATION_STATUS_ROAMING)) {
+			DBG("calling ofono_gprs_detached_notify()");
+			ofono_gprs_detached_notify(gprs);
+			reply->reg_state.tech = RADIO_TECH_UNKNOWN;
+		} else {
+			DBG("calling ofono_gprs_status_notify()");
+			ofono_gprs_status_notify(gprs, reply->reg_state.status);
+		}
+	}
+
+	if (gd->tech != reply->reg_state.tech) {
+		gd->tech = reply->reg_state.tech;
+
+		ofono_gprs_bearer_notify(gprs,
+				ril_tech_to_bearer_tech(reply->reg_state.tech));
+	}
+
+	if (cb)
+		CALLBACK_WITH_SUCCESS(cb, reply->reg_state.status, cbd->data);
+
+	g_free(reply);
+
+	return;
+error:
+
+	/*
+	 * For some modems DATA_REGISTRATION_STATE will return an error until we
+	 * are registered in the voice network.
+	 */
+	if (old_status == -1 && message->error == RIL_E_GENERIC_FAILURE)
+		gd->status_retry_cb_id =
+			g_timeout_add(GET_STATUS_TIMER_MS,
+					ril_get_status_retry, gprs);
+
+	if (cb)
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
+
+void ril_gprs_registration_status(struct ofono_gprs *gprs,
+					ofono_gprs_status_cb_t cb, void *data)
+{
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct cb_data *cbd = cb_data_new(cb, data, gprs);
+
+	DBG("");
+
+	if (g_ril_send(gd->ril, RIL_REQUEST_DATA_REGISTRATION_STATE, NULL,
+			ril_data_reg_cb, cbd, g_free) == 0) {
+		ofono_error("%s: send "
+				"RIL_REQUEST_DATA_REGISTRATION_STATE failed",
+				__func__);
+		g_free(cbd);
+
+		if (cb != NULL)
+			CALLBACK_WITH_FAILURE(cb, -1, data);
+	}
+}
+
+static void drop_data_call_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_gprs *gprs = user_data;
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+
+	if (message->error == RIL_E_SUCCESS)
+		g_ril_print_response_no_args(gd->ril, message);
+	else
+		ofono_error("%s: RIL error %s", __func__,
+				ril_error_to_string(message->error));
+
+	if (--(gd->pending_deact_req) == 0)
+		ril_gprs_registration_status(gprs, NULL, NULL);
+}
+
+static int drop_data_call(struct ofono_gprs *gprs, int cid)
+{
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct req_deactivate_data_call request;
+	struct parcel rilp;
+	struct ofono_error error;
+
+	request.cid = cid;
+	request.reason = RIL_DEACTIVATE_DATA_CALL_NO_REASON;
+
+	g_ril_request_deactivate_data_call(gd->ril, &request, &rilp, &error);
+
+	if (g_ril_send(gd->ril, RIL_REQUEST_DEACTIVATE_DATA_CALL,
+			&rilp, drop_data_call_cb, gprs, NULL) == 0) {
+		ofono_error("%s: send failed", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void get_active_data_calls_cb(struct ril_msg *message,
+					gpointer user_data)
+{
+	struct ofono_gprs *gprs = user_data;
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct ril_data_call_list *call_list = NULL;
+	GSList *iterator;
+	struct ril_data_call *call;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: RIL error %s", __func__,
+				ril_error_to_string(message->error));
+		goto end;
+	}
+
+	/* reply can be NULL when there are no existing data calls */
+	call_list = g_ril_unsol_parse_data_call_list(gd->ril, message);
+	if (call_list == NULL)
+		goto end;
+
+	/*
+	 * We disconnect from previous calls here, which might be needed
+	 * because of a previous ofono abort, as some rild implementations do
+	 * not disconnect the calls even after the ril socket is closed.
+	 */
+	for (iterator = call_list->calls; iterator; iterator = iterator->next) {
+		call = iterator->data;
+		DBG("Standing data call with cid %d", call->cid);
+		if (drop_data_call(gprs, call->cid) == 0)
+			++(gd->pending_deact_req);
+	}
+
+	g_ril_unsol_free_data_call_list(call_list);
+
+end:
+	if (gd->pending_deact_req == 0)
+		ril_gprs_registration_status(gprs, NULL, NULL);
+}
+
+static void get_active_data_calls(struct ofono_gprs *gprs)
+{
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+
+	if (g_ril_send(gd->ril, RIL_REQUEST_DATA_CALL_LIST, NULL,
+			get_active_data_calls_cb, gprs, NULL) == 0)
+		ofono_error("%s: send failed", __func__);
+}
+
+void ril_gprs_start(struct ril_gprs_driver_data *driver_data,
+			struct ofono_gprs *gprs, struct ril_gprs_data *gd)
+{
+	gd->ril = g_ril_clone(driver_data->gril);
+	gd->modem = driver_data->modem;
+	gd->ofono_attached = FALSE;
+	gd->max_cids = 0;
+	gd->rild_status = -1;
+	gd->tech = RADIO_TECH_UNKNOWN;
+	/* AOSP RILD tracks data network state together with voice */
+	gd->state_changed_unsol =
+		RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED;
+
+	ofono_gprs_set_data(gprs, gd);
+
+	get_active_data_calls(gprs);
+}
+
+int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor, void *data)
+{
+	struct ril_gprs_driver_data *driver_data = data;
+	struct ril_gprs_data *gd;
+
+	gd = g_try_new0(struct ril_gprs_data, 1);
+	if (gd == NULL)
+		return -ENOMEM;
+
+	ril_gprs_start(driver_data, gprs, gd);
+
+	return 0;
+}
+
+void ril_gprs_remove(struct ofono_gprs *gprs)
+{
+	struct ril_gprs_data *gd = ofono_gprs_get_data(gprs);
+
+	DBG("");
+
+	if (gd->status_retry_cb_id != 0)
+		g_source_remove(gd->status_retry_cb_id);
+
+	ofono_gprs_set_data(gprs, NULL);
+
+	g_ril_unref(gd->ril);
+	g_free(gd);
+}
+
+static struct ofono_gprs_driver driver = {
+	.name			= RILMODEM,
+	.probe			= ril_gprs_probe,
+	.remove			= ril_gprs_remove,
+	.set_attached		= ril_gprs_set_attached,
+	.attached_status	= ril_gprs_registration_status,
+};
+
+void ril_gprs_init(void)
+{
+	ofono_gprs_driver_register(&driver);
+}
+
+void ril_gprs_exit(void)
+{
+	ofono_gprs_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/gprs.h b/drivers/rilmodem/gprs.h
new file mode 100644
index 0000000..78bb14c
--- /dev/null
+++ b/drivers/rilmodem/gprs.h
@@ -0,0 +1,46 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2014  Canonical Ltd.
+ *
+ *  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 "drivers/rilmodem/rilutil.h"
+
+struct ril_gprs_data {
+	GRil *ril;
+	struct ofono_modem *modem;
+	gboolean ofono_attached;
+	unsigned int max_cids;
+	int rild_status;
+	int tech;
+	int state_changed_unsol;
+	int pending_deact_req;
+	guint status_retry_cb_id;
+};
+
+int ril_gprs_probe(struct ofono_gprs *gprs, unsigned int vendor, void *data);
+void ril_gprs_remove(struct ofono_gprs *gprs);
+void ril_gprs_start(struct ril_gprs_driver_data *driver_data,
+			struct ofono_gprs *gprs, struct ril_gprs_data *gd);
+gboolean ril_gprs_set_attached_cb(gpointer user_data);
+void ril_gprs_registration_status(struct ofono_gprs *gprs,
+					ofono_gprs_status_cb_t cb, void *data);
+void ril_gprs_set_ia_apn(struct ofono_gprs *gprs, const char *apn,
+				enum ofono_gprs_proto proto, const char *user,
+				const char *passwd, const char *mccmnc,
+				ofono_gprs_cb_t cb, void *data);
diff --git a/drivers/rilmodem/network-registration.c b/drivers/rilmodem/network-registration.c
new file mode 100644
index 0000000..6808a29
--- /dev/null
+++ b/drivers/rilmodem/network-registration.c
@@ -0,0 +1,566 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL Modem Support
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2010  ST-Ericsson AB.
+ *  Copyright (C) 2012-2013  Canonical Ltd.
+ *  Copyright (C) 2013  Jolla Ltd.
+ *
+ *  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 <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/netreg.h>
+
+#include "common.h"
+#include "gril.h"
+#include "rilmodem.h"
+
+#include "grilreply.h"
+#include "grilrequest.h"
+#include "grilunsol.h"
+
+struct netreg_data {
+	GRil *ril;
+	char mcc[OFONO_MAX_MCC_LENGTH + 1];
+	char mnc[OFONO_MAX_MNC_LENGTH + 1];
+	int signal_index; /* If strength is reported via CIND */
+	int signal_min; /* min strength reported via CIND */
+	int signal_max; /* max strength reported via CIND */
+	int signal_invalid; /* invalid strength reported via CIND */
+	int tech;
+	struct ofono_network_time time;
+	guint nitz_timeout;
+	unsigned int vendor;
+};
+
+static void ril_registration_status(struct ofono_netreg *netreg,
+					ofono_netreg_status_cb_t cb,
+					void *data);
+
+static int ril_tech_to_access_tech(int ril_tech)
+{
+	/*
+	 * This code handles the mapping between the RIL_RadioTechnology
+	 * and ofono's access technology values ( see <Act> values - 27.007
+	 * Section 7.3 ).
+	 */
+
+	switch (ril_tech) {
+	case RADIO_TECH_UNKNOWN:
+		return -1;
+	case RADIO_TECH_GSM:
+	case RADIO_TECH_GPRS:
+		return ACCESS_TECHNOLOGY_GSM;
+	case RADIO_TECH_EDGE:
+		return ACCESS_TECHNOLOGY_GSM_EGPRS;
+	case RADIO_TECH_UMTS:
+		return ACCESS_TECHNOLOGY_UTRAN;
+	case RADIO_TECH_HSDPA:
+		return ACCESS_TECHNOLOGY_UTRAN_HSDPA;
+	case RADIO_TECH_HSUPA:
+		return ACCESS_TECHNOLOGY_UTRAN_HSUPA;
+	case RADIO_TECH_HSPAP:
+	case RADIO_TECH_HSPA:
+		/* HSPAP is HSPA+; which ofono doesn't define;
+		 * so, if differentiating HSPA and HSPA+ is
+		 * important, then ofono needs to be patched,
+		 * and we probably also need to introduce a
+		 * new indicator icon.
+		 */
+
+		return ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
+	case RADIO_TECH_LTE:
+		return ACCESS_TECHNOLOGY_EUTRAN;
+	default:
+		return -1;
+	}
+}
+
+static void extract_mcc_mnc(const char *str, char *mcc, char *mnc)
+{
+	/* Three digit country code */
+	strncpy(mcc, str, OFONO_MAX_MCC_LENGTH);
+	mcc[OFONO_MAX_MCC_LENGTH] = '\0';
+
+	/* Usually a 2 but sometimes 3 digit network code */
+	strncpy(mnc, str + OFONO_MAX_MCC_LENGTH, OFONO_MAX_MNC_LENGTH);
+	mnc[OFONO_MAX_MNC_LENGTH] = '\0';
+}
+
+static void ril_creg_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_status_cb_t cb = cbd->cb;
+	struct netreg_data *nd = cbd->user;
+	struct reply_reg_state *reply;
+
+	DBG("");
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: failed to pull registration state",
+				__func__);
+		goto error;
+	}
+
+	reply = g_ril_reply_parse_voice_reg_state(nd->ril, message);
+	if (reply == NULL)
+		goto error;
+
+	nd->tech = reply->tech;
+
+	CALLBACK_WITH_SUCCESS(cb,
+				reply->status,
+				reply->lac,
+				reply->ci,
+				ril_tech_to_access_tech(reply->tech),
+				cbd->data);
+
+	g_free(reply);
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, cbd->data);
+}
+
+static void ril_creg_notify(struct ofono_error *error, int status, int lac,
+					int ci, int tech, gpointer user_data)
+{
+	struct ofono_netreg *netreg = user_data;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		DBG("Error during status notification");
+		return;
+	}
+
+	ofono_netreg_status_notify(netreg, status, lac, ci, tech);
+}
+
+static void ril_network_state_change(struct ril_msg *message,
+							gpointer user_data)
+{
+	struct ofono_netreg *netreg = user_data;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+
+	g_ril_print_unsol_no_args(nd->ril, message);
+
+	ril_registration_status(netreg, NULL, NULL);
+}
+
+static void ril_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;
+
+	/*
+	 * If no cb specified, setup internal callback to
+	 * handle unsolicited VOICE_NET_STATE_CHANGE events.
+	 */
+	if (cb == NULL)
+		cbd = cb_data_new(ril_creg_notify, netreg, nd);
+	else
+		cbd = cb_data_new(cb, data, nd);
+
+	if (g_ril_send(nd->ril, RIL_REQUEST_VOICE_REGISTRATION_STATE, NULL,
+			ril_creg_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data);
+	}
+}
+
+static void set_oper_name(const struct reply_operator *reply,
+				struct ofono_network_operator *op)
+{
+	/* Try to use long by default */
+	if (reply->lalpha)
+		strncpy(op->name, reply->lalpha,
+			OFONO_MAX_OPERATOR_NAME_LENGTH);
+	else if (reply->salpha)
+		strncpy(op->name, reply->salpha,
+			OFONO_MAX_OPERATOR_NAME_LENGTH);
+}
+
+static void ril_cops_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_operator_cb_t cb = cbd->cb;
+	struct netreg_data *nd = cbd->user;
+	struct reply_operator *reply;
+	struct ofono_network_operator op;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: failed to retrive the current operator",
+				__func__);
+		goto error;
+	}
+
+	reply = g_ril_reply_parse_operator(nd->ril, message);
+	if (reply == NULL)
+		goto error;
+
+	set_oper_name(reply, &op);
+
+	extract_mcc_mnc(reply->numeric, op.mcc, op.mnc);
+
+	/* Set to current */
+	op.status = OPERATOR_STATUS_CURRENT;
+	op.tech = ril_tech_to_access_tech(nd->tech);
+
+	CALLBACK_WITH_SUCCESS(cb, &op, cbd->data);
+
+	g_ril_reply_free_operator(reply);
+
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
+static void ril_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, nd);
+
+	if (g_ril_send(nd->ril, RIL_REQUEST_OPERATOR, NULL,
+			ril_cops_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, NULL, data);
+	}
+}
+
+static void ril_cops_list_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_operator_list_cb_t cb = cbd->cb;
+	struct netreg_data *nd = cbd->user;
+	struct reply_avail_ops *reply = NULL;
+	struct ofono_network_operator *ops;
+	struct reply_operator *operator;
+	GSList *l;
+	unsigned int i = 0;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: failed to retrive the list of operators",
+				__func__);
+		goto error;
+	}
+
+	reply = g_ril_reply_parse_avail_ops(nd->ril, message);
+	if (reply == NULL)
+		goto error;
+
+	ops = g_try_new0(struct ofono_network_operator, reply->num_ops);
+	if (ops == NULL) {
+		ofono_error("%s: can't allocate ofono_network_operator",
+				__func__);
+
+		goto error;
+	}
+
+	for (l = reply->list; l; l = l->next) {
+		operator = l->data;
+
+		set_oper_name(operator, &ops[i]);
+
+		extract_mcc_mnc(operator->numeric, ops[i].mcc, ops[i].mnc);
+
+		ops[i].tech = ril_tech_to_access_tech(operator->tech);
+
+		/* Set the proper status  */
+		if (!strcmp(operator->status, "unknown"))
+			ops[i].status = OPERATOR_STATUS_UNKNOWN;
+		else if (!strcmp(operator->status, "available"))
+			ops[i].status = OPERATOR_STATUS_AVAILABLE;
+		else if (!strcmp(operator->status, "current"))
+			ops[i].status = OPERATOR_STATUS_CURRENT;
+		else if (!strcmp(operator->status, "forbidden"))
+			ops[i].status = OPERATOR_STATUS_FORBIDDEN;
+
+		i++;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, reply->num_ops, ops, cbd->data);
+	g_ril_reply_free_avail_ops(reply);
+
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+	g_ril_reply_free_avail_ops(reply);
+}
+
+static void ril_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, nd);
+
+	if (g_ril_send(nd->ril, RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, NULL,
+			ril_cops_list_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, 0, NULL, data);
+	}
+}
+
+static void ril_register_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_register_cb_t cb = cbd->cb;
+	struct netreg_data *nd = cbd->user;
+	struct ofono_error error;
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+
+		g_ril_print_response_no_args(nd->ril, message);
+
+	} else {
+		decode_ril_error(&error, "FAIL");
+	}
+
+	cb(&error, cbd->data);
+}
+
+static void ril_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 = cb_data_new(cb, data, nd);
+
+	if (g_ril_send(nd->ril, RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
+			NULL, ril_register_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void ril_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 = cb_data_new(cb, data, nd);
+	char buf[OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1];
+	struct parcel rilp;
+
+	/* RIL expects a char * specifying MCCMNC of network to select */
+	snprintf(buf, sizeof(buf), "%s%s", mcc, mnc);
+
+	g_ril_request_set_net_select_manual(nd->ril, buf, &rilp);
+
+	/* In case of error free cbd and return the cb with failure */
+	if (g_ril_send(nd->ril, RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, &rilp,
+			ril_register_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void ril_strength_notify(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_netreg *netreg = user_data;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	int strength = g_ril_unsol_parse_signal_strength(nd->ril, message,
+								nd->tech);
+
+	ofono_netreg_strength_notify(netreg, strength);
+}
+
+static void ril_strength_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_netreg_strength_cb_t cb = cbd->cb;
+	struct netreg_data *nd = cbd->user;
+	struct ofono_error error;
+	int strength;
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+	} else {
+		ofono_error("Failed to retrive the signal strength");
+		goto error;
+	}
+
+	/* The g_ril_unsol* function handles both reply & unsolicited */
+	strength = g_ril_unsol_parse_signal_strength(nd->ril, message,
+							nd->tech);
+	cb(&error, strength, cbd->data);
+
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+}
+
+static void ril_signal_strength(struct ofono_netreg *netreg,
+				ofono_netreg_strength_cb_t cb, void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct cb_data *cbd = cb_data_new(cb, data, nd);
+
+	if (g_ril_send(nd->ril, RIL_REQUEST_SIGNAL_STRENGTH, NULL,
+			ril_strength_cb, cbd, g_free) == 0) {
+		ofono_error("Send RIL_REQUEST_SIGNAL_STRENGTH failed.");
+
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+	}
+}
+
+static void ril_nitz_notify(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_netreg *netreg = user_data;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	int year, mon, mday, hour, min, sec, dst, tzi, n_match;
+	char tzs, tz[4];
+	gchar *nitz;
+
+	nitz = g_ril_unsol_parse_nitz(nd->ril, message);
+	if (nitz == NULL)
+		goto error;
+
+	n_match = sscanf(nitz, "%u/%u/%u,%u:%u:%u%c%u,%u", &year, &mon,
+				&mday, &hour, &min, &sec, &tzs, &tzi, &dst);
+	if (n_match != 9)
+		goto error;
+
+	sprintf(tz, "%c%d", tzs, tzi);
+
+	nd->time.utcoff = atoi(tz) * 15 * 60;
+	nd->time.dst = dst;
+	nd->time.sec = sec;
+	nd->time.min = min;
+	nd->time.hour = hour;
+	nd->time.mday = mday;
+	nd->time.mon = mon;
+	nd->time.year = 2000 + year;
+
+	ofono_netreg_time_notify(netreg, &nd->time);
+
+	g_free(nitz);
+
+	return;
+
+error:
+	ofono_error("%s: unable to notify ofono about NITZ (%s)",
+						__func__, nitz ? nitz : "null");
+	g_free(nitz);
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_netreg *netreg = user_data;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	ofono_netreg_register(netreg);
+
+	/* Register for network state changes */
+	g_ril_register(nd->ril, RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
+			ril_network_state_change, netreg);
+
+	/* Register for network time update reports */
+	g_ril_register(nd->ril, RIL_UNSOL_NITZ_TIME_RECEIVED,
+			ril_nitz_notify, netreg);
+
+	/* Register for signal strength changes */
+	g_ril_register(nd->ril, RIL_UNSOL_SIGNAL_STRENGTH,
+			ril_strength_notify, netreg);
+
+	/* This makes the timeout a single-shot */
+	return FALSE;
+}
+
+static int ril_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
+				void *data)
+{
+	GRil *ril = data;
+	struct netreg_data *nd;
+
+	nd = g_new0(struct netreg_data, 1);
+
+	nd->ril = g_ril_clone(ril);
+	nd->vendor = vendor;
+	nd->tech = RADIO_TECH_UNKNOWN;
+	nd->time.sec = -1;
+	nd->time.min = -1;
+	nd->time.hour = -1;
+	nd->time.mday = -1;
+	nd->time.mon = -1;
+	nd->time.year = -1;
+	nd->time.dst = 0;
+	nd->time.utcoff = 0;
+	ofono_netreg_set_data(netreg, nd);
+
+	/*
+	 * ofono_netreg_register() needs to be called after
+	 * the driver has been set in ofono_netreg_create(),
+	 * which calls this function.  Most other drivers make
+	 * some kind of capabilities query to the modem, and then
+	 * call register in the callback; we use the idle loop here.
+	 */
+	g_idle_add(ril_delayed_register, netreg);
+
+	return 0;
+}
+
+static void ril_netreg_remove(struct ofono_netreg *netreg)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+
+	if (nd->nitz_timeout)
+		g_source_remove(nd->nitz_timeout);
+
+	ofono_netreg_set_data(netreg, NULL);
+
+	g_ril_unref(nd->ril);
+	g_free(nd);
+}
+
+static struct ofono_netreg_driver driver = {
+	.name				= RILMODEM,
+	.probe				= ril_netreg_probe,
+	.remove				= ril_netreg_remove,
+	.registration_status		= ril_registration_status,
+	.current_operator		= ril_current_operator,
+	.list_operators			= ril_list_operators,
+	.register_auto			= ril_register_auto,
+	.register_manual		= ril_register_manual,
+	.strength			= ril_signal_strength,
+};
+
+void ril_netreg_init(void)
+{
+	ofono_netreg_driver_register(&driver);
+}
+
+void ril_netreg_exit(void)
+{
+	ofono_netreg_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/phonebook.c b/drivers/rilmodem/phonebook.c
new file mode 100644
index 0000000..c3f1c0b
--- /dev/null
+++ b/drivers/rilmodem/phonebook.c
@@ -0,0 +1,1055 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL Modem Support
+ *
+ *  Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *  Copyright (C) ST-Ericsson SA 2010.
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013 Jolla Ltd
+ *  Contact: Jussi Kangas <jussi.kangas@tieto.com>
+ *  Copyright (C) 2014  Canonical Ltd
+ *
+ *  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 <stdint.h>
+
+#include <glib.h>
+
+#include <ofono.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/phonebook.h>
+#include <sim.h>
+#include <simfs.h>
+#include <util.h>
+
+#include "gril.h"
+#include "simutil.h"
+#include "common.h"
+
+#include "rilmodem.h"
+
+#define UNUSED	0xFF
+
+#define EXT1_CP_SUBADDRESS	1
+#define EXT1_ADDITIONAL_DATA	2
+
+/* TON (Type Of Number) See TS 24.008 */
+#define TON_MASK		0x70
+#define TON_INTERNATIONAL	0x10
+
+enum constructed_tag {
+	TYPE_1_TAG = 0xA8,
+	TYPE_2_TAG = 0xA9,
+	TYPE_3_TAG = 0xAA
+};
+
+enum file_type_tag {
+	TYPE_ADN = 0xC0,
+	TYPE_IAP = 0xC1,
+	TYPE_EXT1 = 0xC2,
+	TYPE_SNE = 0xC3,
+	TYPE_ANR = 0xC4,
+	TYPE_PBC = 0xC5,
+	TYPE_GPR = 0xC6,
+	TYPE_AAS = 0xC7,
+	TYPE_GAS = 0xC8,
+	TYPE_UID = 0xC9,
+	TYPE_EMAIL = 0xCA,
+	TYPE_CCP1 = 0xCB
+};
+
+struct pb_file_info {
+	enum constructed_tag pbr_type;
+	int file_id;
+	enum file_type_tag file_type;
+	int file_length;
+	int record_length;
+};
+
+struct record_to_read {
+	int file_id;
+	enum file_type_tag type_tag;
+	int record_length;
+	int record;
+	int adn_idx;
+	gboolean anr_ext;	/* Is it an EXT1 record for ANR? */
+	gboolean set_by_iap;	/* Type 2 file? */
+};
+
+struct phonebook_entry {
+	int entry;
+	char *name;
+	char *number;
+	char *email;
+	char *anr;
+	char *sne;
+};
+
+unsigned char sim_path[] = { 0x3F, 0x00, 0x7F, 0x10 };
+unsigned char usim_path[] = { 0x3F, 0x00, 0x7F, 0x10, 0x5F, 0x3A };
+
+/*
+ * Table for BCD to utf8 conversion. See table 4.4 in TS 31.102.
+ * BCD 0x0C indicates pause before sending following digits as DTMF tones.
+ * BCD 0x0D is a wildcard that means "any digit". These values are mapped to
+ * ',' and '?', following the Android/iPhone convention for the first and Nokia
+ * convention for the second (only OEM that I have seen that supports this
+ * feature). BCD 0x0E is reserved, we convert it to 'r'.
+ */
+static const char digit_to_utf8[] = "0123456789*#,?r\0";
+
+/* One of these for each record in EF_PBR */
+struct pb_ref_rec {
+	GSList *pb_files;	/* File ids to read (pb_file_info nodes) */
+	GSList *pb_next;	/* Next file info to read */
+	GSList *pending_records;	/* List of record_to_read */
+	GSList *next_record;	/* Next record_to_read to process */
+	GTree *phonebook;	/* Container of phonebook_entry structures */
+};
+
+struct pb_data {
+	GSList *pb_refs;
+	GSList *pb_ref_next;
+	struct ofono_sim *sim;
+	struct ofono_sim_context *sim_context;
+	const unsigned char *df_path;
+	size_t df_size;
+};
+
+static void read_info_cb(int ok, unsigned char file_status,
+				int total_length, int record_length,
+				void *userdata);
+
+static gint comp_int(gconstpointer a, gconstpointer b)
+{
+	int a_val = GPOINTER_TO_INT(a);
+	int b_val = GPOINTER_TO_INT(b);
+
+	return a_val - b_val;
+}
+
+static const struct pb_file_info *
+ext1_info(const GSList *pb_files)
+{
+	const GSList *l;
+	for (l = pb_files; l; l = l->next) {
+		const struct pb_file_info *f_info = l->data;
+		if (f_info->file_type == TYPE_EXT1)
+			return f_info;
+	}
+
+	return NULL;
+}
+
+static struct phonebook_entry *handle_adn(size_t len, const unsigned char *msg,
+					struct pb_ref_rec *ref, int adn_idx)
+{
+	unsigned name_length = len - 14;
+	unsigned number_start = name_length;
+	unsigned number_length;
+	unsigned extension_record = UNUSED;
+	unsigned i, prefix;
+	char *number = NULL;
+	char *name = sim_string_to_utf8(msg, name_length);
+	struct phonebook_entry *new_entry;
+
+	/* Length contains also TON & NPI */
+	number_length = msg[number_start];
+
+	if (number_length != UNUSED && number_length != 0) {
+		number_length--;
+		/* '+' + number + terminator */
+		number = g_try_malloc0(2 * number_length + 2);
+
+		if (number) {
+			prefix = 0;
+
+			if ((msg[number_start + 1] & TON_MASK)
+					== TON_INTERNATIONAL) {
+				number[0] = '+';
+				prefix = 1;
+			}
+
+			for (i = 0; i < number_length; i++) {
+
+				number[2 * i + prefix] =
+					digit_to_utf8[msg[number_start + 2 + i]
+							& 0x0f];
+				number[2 * i + 1 + prefix] =
+					digit_to_utf8[msg[number_start + 2 + i]
+							>> 4];
+			}
+
+			extension_record = msg[len - 1];
+		}
+	}
+
+	DBG("ADN name %s, number %s ", name, number);
+	DBG("number length %d extension_record %d",
+		2 * number_length, extension_record);
+
+	if ((name == NULL || *name == '\0') && number == NULL)
+		goto end;
+
+	new_entry = g_try_malloc0(sizeof(*new_entry));
+	if (new_entry == NULL) {
+		ofono_error("%s: out of memory", __func__);
+		goto end;
+	}
+
+	new_entry->name = name;
+	new_entry->number = number;
+
+	DBG("Creating PB entry %d with", adn_idx);
+	DBG("name %s and number %s", new_entry->name, new_entry->number);
+
+	g_tree_insert(ref->phonebook, GINT_TO_POINTER(adn_idx), new_entry);
+
+	if (extension_record != UNUSED) {
+		struct record_to_read *ext_rec =
+			g_try_malloc0(sizeof(*ext_rec));
+		const struct pb_file_info *f_info = ext1_info(ref->pb_files);
+
+		if (ext_rec && f_info) {
+			ext_rec->file_id = f_info->file_id;
+			ext_rec->type_tag = TYPE_EXT1;
+			ext_rec->record_length = f_info->record_length;
+			ext_rec->record = extension_record;
+			ext_rec->adn_idx = adn_idx;
+
+			ref->pending_records =
+				g_slist_prepend(ref->pending_records, ext_rec);
+		}
+	}
+
+	return new_entry;
+
+end:
+	g_free(name);
+	g_free(number);
+
+	return NULL;
+}
+
+static void handle_iap(size_t len, const unsigned char *msg,
+			struct pb_ref_rec *ref,
+			const struct record_to_read *rec_data)
+{
+	GSList *l;
+	size_t i = 0;
+
+	for (l = ref->pb_files; l; l = l->next) {
+		struct pb_file_info *f_info = l->data;
+		if (f_info->pbr_type == TYPE_2_TAG) {
+			if (i >= len) {
+				ofono_error("%s: EF_IAP record too small",
+						__func__);
+				return;
+			}
+			if (msg[i] != UNUSED) {
+				struct record_to_read *new_rec =
+					g_try_malloc0(sizeof(*new_rec));
+				if (new_rec == NULL) {
+					ofono_error("%s: OOM", __func__);
+					return;
+				}
+				DBG("type 0x%X record %d",
+					f_info->file_type, msg[i]);
+
+				new_rec->file_id = f_info->file_id;
+				new_rec->type_tag = f_info->file_type;
+				new_rec->record_length = f_info->record_length;
+				new_rec->record = msg[i];
+				new_rec->adn_idx = rec_data->adn_idx;
+				new_rec->anr_ext = FALSE;
+				new_rec->set_by_iap = TRUE;
+
+				ref->pending_records =
+					g_slist_prepend(ref->pending_records,
+							new_rec);
+			}
+			++i;
+		}
+	}
+}
+
+static void handle_sne(size_t len, const unsigned char *msg,
+			struct pb_ref_rec *ref,
+			const struct record_to_read *rec_data)
+{
+	char *sne;
+
+	/* There are additional fields for type 2 files */
+	if (rec_data->set_by_iap)
+		len -= 2;
+
+	sne = sim_string_to_utf8(msg, len);
+
+	if (sne && *sne != '\0') {
+		struct phonebook_entry *entry;
+
+		entry = g_tree_lookup(ref->phonebook,
+				GINT_TO_POINTER(rec_data->adn_idx));
+		if (entry) {
+			/* If one already exists, delete it */
+			if (entry->sne)
+				g_free(entry->sne);
+
+			DBG("Adding SNE %s to %d", sne, rec_data->adn_idx);
+			DBG("name %s", entry->name);
+
+			entry->sne = sne;
+		} else {
+			g_free(sne);
+		}
+	} else {
+		g_free(sne);
+	}
+}
+
+static void handle_anr(size_t len,
+			const unsigned char *msg,
+			struct pb_ref_rec *ref,
+			const struct record_to_read *rec_data)
+{
+	unsigned number_length;
+	unsigned extension_record;
+	unsigned aas_record;
+	unsigned i, prefix;
+	char *anr;
+	struct phonebook_entry *entry;
+
+	if (len < 15) {
+		ofono_error("%s: bad EF_ANR record size", __func__);
+		return;
+	}
+
+	aas_record = msg[0];
+	if (aas_record == UNUSED)
+		return;
+
+	DBG("ANR %d", aas_record);
+
+	/* Length contains also TON & NPI */
+	number_length = msg[1];
+	if (number_length < 2)
+		return;
+
+	number_length--;
+	/* '+' + number + terminator */
+	anr = g_try_malloc0(2 * number_length + 2);
+	if (anr == NULL)
+		return;
+
+	prefix = 0;
+	if ((msg[2] & TON_MASK) == TON_INTERNATIONAL) {
+		anr[0] = '+';
+		prefix = 1;
+	}
+
+	for (i = 0; i < number_length; i++) {
+		anr[2 * i + prefix] = digit_to_utf8[msg[3 + i] & 0x0f];
+		anr[2 * i + 1 + prefix] = digit_to_utf8[msg[3 + i] >> 4];
+	}
+
+	entry = g_tree_lookup(ref->phonebook,
+				GINT_TO_POINTER(rec_data->adn_idx));
+	if (entry == NULL) {
+		g_free(anr);
+		return;
+	}
+
+	/* If one already exists, delete it */
+	if (entry->anr)
+		g_free(entry->anr);
+
+	DBG("Adding ANR %s to %d", anr, rec_data->adn_idx);
+	DBG("name %s", entry->name);
+
+	entry->anr = anr;
+
+	extension_record = msg[14];
+
+	DBG("ANR to entry %d number %s number length %d",
+		rec_data->adn_idx, anr, number_length);
+	DBG("extension_record %d aas %d", extension_record, aas_record);
+
+	if (extension_record != UNUSED) {
+		struct record_to_read *ext_rec =
+			g_try_malloc0(sizeof(*ext_rec));
+		const struct pb_file_info *f_info = ext1_info(ref->pb_files);
+
+		if (ext_rec && f_info) {
+			ext_rec->file_id = f_info->file_id;
+			ext_rec->type_tag = TYPE_EXT1;
+			ext_rec->record_length = f_info->record_length;
+			ext_rec->record = extension_record;
+			ext_rec->adn_idx = rec_data->adn_idx;
+			ext_rec->anr_ext = TRUE;
+
+			ref->pending_records =
+				g_slist_prepend(ref->pending_records, ext_rec);
+		}
+	}
+}
+
+static void handle_email(size_t len, const unsigned char *msg,
+			struct pb_ref_rec *ref,
+			const struct record_to_read *rec_data)
+{
+	char *email;
+	struct phonebook_entry *entry;
+
+	/* There are additional fields for type 2 files */
+	if (rec_data->set_by_iap)
+		len -= 2;
+
+	email = sim_string_to_utf8(msg, len);
+	if (email == NULL || *email == '\0') {
+		g_free(email);
+		return;
+	}
+
+	entry = g_tree_lookup(ref->phonebook,
+				GINT_TO_POINTER(rec_data->adn_idx));
+	if (entry == NULL) {
+		g_free(email);
+		return;
+	}
+
+	/* if one already exists, delete it */
+	if (entry->email)
+		g_free(entry->email);
+
+	DBG("Adding email to entry %d", rec_data->adn_idx);
+	DBG("name %s", entry->name);
+
+	entry->email = email;
+}
+
+static void handle_ext1(size_t len, const unsigned char *msg,
+			struct pb_ref_rec *ref,
+			const struct record_to_read *rec_data)
+{
+	unsigned number_length, i, next_extension_record;
+	struct phonebook_entry *entry;
+	char *ext_number;
+
+	if (len < 13) {
+		ofono_error("%s: bad EF_EXT1 record size", __func__);
+		return;
+	}
+
+	/* Check if there is more extension data */
+	next_extension_record = msg[12];
+	if (next_extension_record != UNUSED) {
+		struct record_to_read *ext_rec =
+			g_try_malloc0(sizeof(*ext_rec));
+		const struct pb_file_info *f_info = ext1_info(ref->pb_files);
+
+		if (ext_rec && f_info) {
+			DBG("next_extension_record %d", next_extension_record);
+
+			ext_rec->file_id = f_info->file_id;
+			ext_rec->record_length = f_info->record_length;
+			ext_rec->type_tag = TYPE_EXT1;
+			ext_rec->record = next_extension_record;
+			ext_rec->adn_idx = rec_data->adn_idx;
+			ext_rec->anr_ext = rec_data->anr_ext;
+
+			ref->pending_records =
+				g_slist_prepend(ref->pending_records, ext_rec);
+		}
+	}
+
+	if (msg[0] != EXT1_ADDITIONAL_DATA) {
+		DBG("EXT1 record with subaddress ignored");
+		return;
+	}
+
+	number_length = msg[1];
+	ext_number = g_try_malloc0(2 * number_length + 1);
+	if (ext_number == NULL)
+		return;
+
+	for (i = 0; i < number_length; i++) {
+		ext_number[2 * i] = digit_to_utf8[msg[2 + i] & 0x0f];
+		ext_number[2 * i + 1] = digit_to_utf8[msg[2 + i] >> 4];
+	}
+
+	DBG("Number extension %s", ext_number);
+	DBG("number length %d", number_length);
+
+	DBG("Looking for ADN entry %d", rec_data->adn_idx);
+	entry = g_tree_lookup(ref->phonebook,
+				GINT_TO_POINTER(rec_data->adn_idx));
+	if (entry == NULL) {
+		g_free(ext_number);
+		return;
+	}
+
+	if (rec_data->anr_ext) {
+		char *anr = entry->anr;
+		entry->anr = g_strconcat(anr, ext_number, NULL);
+		g_free(anr);
+	} else {
+		char *number = entry->number;
+		entry->number = g_strconcat(number, ext_number, NULL);
+		g_free(number);
+	}
+
+	g_free(ext_number);
+}
+
+static const char *file_tag_to_string(enum file_type_tag tag)
+{
+	switch (tag) {
+	case TYPE_ADN: return "ADN";
+	case TYPE_IAP: return "IAP";
+	case TYPE_EXT1: return "EXT1";
+	case TYPE_SNE: return "SNE";
+	case TYPE_ANR: return "ANR";
+	case TYPE_PBC: return "PBC";
+	case TYPE_GPR: return "GPR";
+	case TYPE_AAS: return "AAS";
+	case TYPE_GAS: return "GAS";
+	case TYPE_UID: return "UID";
+	case TYPE_EMAIL: return "EMAIL";
+	case TYPE_CCP1: return "CCP1";
+	default: return "<UNKNOWN>";
+	}
+}
+
+static void decode_read_response(const struct record_to_read *rec_data,
+					const unsigned char *msg, size_t len,
+					struct pb_ref_rec *ref)
+{
+	DBG("Decoding %s type record", file_tag_to_string(rec_data->type_tag));
+	switch (rec_data->type_tag) {
+	case TYPE_IAP:
+		handle_iap(len, msg, ref, rec_data);
+		break;
+	case TYPE_SNE:
+		handle_sne(len, msg, ref, rec_data);
+		break;
+	case TYPE_ANR:
+		handle_anr(len, msg, ref, rec_data);
+		break;
+	case TYPE_EMAIL:
+		handle_email(len, msg, ref, rec_data);
+		break;
+	case TYPE_EXT1:
+		handle_ext1(len, msg, ref, rec_data);
+		break;
+	default:
+		DBG("Skipping type");
+		break;
+	}
+}
+
+static gboolean export_entry(gpointer key, gpointer value, gpointer data)
+{
+	struct ofono_phonebook *pb = data;
+	struct phonebook_entry *entry = value;
+
+	ofono_phonebook_entry(pb, -1,
+				entry->number, -1,
+				entry->name, -1,
+				NULL,
+				entry->anr, -1,
+				entry->sne,
+				entry->email,
+				NULL, NULL);
+
+	g_free(entry->name);
+	g_free(entry->number);
+	g_free(entry->email);
+	g_free(entry->anr);
+	g_free(entry->sne);
+	g_free(entry);
+
+	return FALSE;
+}
+
+static void export_and_return(gboolean ok, struct cb_data *cbd)
+{
+	struct ofono_phonebook *pb = cbd->user;
+	ofono_phonebook_cb_t cb = cbd->cb;
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+	GSList *l;
+
+	DBG("phonebook fully read");
+
+	for (l = pbd->pb_refs; l != NULL; l = l->next) {
+		struct pb_ref_rec *ref = l->data;
+
+		g_tree_foreach(ref->phonebook, export_entry, pb);
+		g_tree_destroy(ref->phonebook);
+		g_slist_free_full(ref->pending_records, g_free);
+		g_slist_free_full(ref->pb_files, g_free);
+	}
+
+	g_slist_free_full(pbd->pb_refs, g_free);
+	pbd->pb_refs = NULL;
+
+	if (ok)
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	else
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+	g_free(cbd);
+}
+
+static void read_record_cb(int ok, int total_length, int record,
+			const unsigned char *data,
+			int record_length, void *userdata)
+{
+	struct cb_data *cbd = userdata;
+	struct ofono_phonebook *pb = cbd->user;
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+	struct pb_ref_rec *ref = pbd->pb_ref_next->data;
+	struct record_to_read *rec;
+
+	if (!ok) {
+		ofono_error("%s: error %d", __func__, ok);
+		export_and_return(FALSE, cbd);
+		return;
+	}
+
+	DBG("ok %d; total_length %d; record %d; record_length %d",
+		ok, total_length, record, record_length);
+
+	rec = ref->next_record->data;
+
+	/* This call might add elements to pending_records */
+	decode_read_response(rec, data, record_length, ref);
+
+	ref->pending_records = g_slist_remove(ref->pending_records, rec);
+	g_free(rec);
+
+	if (ref->pending_records) {
+		struct record_to_read *rec;
+
+		ref->next_record = ref->pending_records;
+		rec = ref->next_record->data;
+
+		ofono_sim_read_record(pbd->sim_context, rec->file_id,
+					OFONO_SIM_FILE_STRUCTURE_FIXED,
+					rec->record,
+					rec->record_length,
+					pbd->df_path, pbd->df_size,
+					read_record_cb, cbd);
+	} else {
+		/* Read files from next EF_PBR record, if any */
+
+		pbd->pb_ref_next = pbd->pb_ref_next->next;
+		if (pbd->pb_ref_next == NULL) {
+			export_and_return(TRUE, cbd);
+		} else {
+			struct pb_ref_rec *ref;
+
+			DBG("Next EFpbr record");
+
+			ref = pbd->pb_ref_next->data;
+
+			if (!ref->pb_files) {
+				export_and_return(TRUE, cbd);
+			} else {
+				struct pb_file_info *file_info;
+
+				ref->pb_next = ref->pb_files;
+				file_info = ref->pb_files->data;
+
+				ofono_sim_read_info(pbd->sim_context,
+						file_info->file_id,
+						OFONO_SIM_FILE_STRUCTURE_FIXED,
+						pbd->df_path, pbd->df_size,
+						read_info_cb, cbd);
+			}
+		}
+	}
+}
+
+static void pb_adn_cb(int ok, int total_length, int record,
+			const unsigned char *data,
+			int record_length, void *userdata)
+{
+	struct cb_data *cbd = userdata;
+	struct ofono_phonebook *pb = cbd->user;
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+	struct pb_ref_rec *ref = pbd->pb_ref_next->data;
+	GSList *l;
+
+	if (!ok) {
+		ofono_error("%s: error %d", __func__, ok);
+		export_and_return(FALSE, cbd);
+		return;
+	}
+
+	DBG("ok %d; total_length %d; record %d; record_length %d",
+		ok, total_length, record, record_length);
+
+	if (handle_adn(record_length, data, ref, record) != NULL) {
+		/* Add type 1 records */
+		for (l = ref->pb_files; l; l = l->next) {
+			const struct pb_file_info *f_info = l->data;
+			struct record_to_read *ext_rec;
+
+			if (f_info->pbr_type == TYPE_1_TAG &&
+					f_info->file_type != TYPE_ADN) {
+				ext_rec = g_try_malloc0(sizeof(*ext_rec));
+				if (ext_rec == NULL)
+					break;
+
+				ext_rec->file_id = f_info->file_id;
+				ext_rec->type_tag = f_info->file_type;
+				ext_rec->record_length = f_info->record_length;
+				ext_rec->record = record;
+				ext_rec->adn_idx = record;
+
+				ref->pending_records =
+					g_slist_prepend(ref->pending_records,
+							ext_rec);
+			}
+		}
+	}
+
+	if (record*record_length >= total_length) {
+		DBG("All ADN records read: reading additional files");
+
+		if (ref->pending_records) {
+			struct record_to_read *rec;
+
+			ref->next_record = ref->pending_records;
+			rec = ref->next_record->data;
+
+			ofono_sim_read_record(pbd->sim_context, rec->file_id,
+						OFONO_SIM_FILE_STRUCTURE_FIXED,
+						rec->record,
+						rec->record_length,
+						pbd->df_path, pbd->df_size,
+						read_record_cb, cbd);
+		} else {
+			export_and_return(TRUE, cbd);
+		}
+	}
+}
+
+static void read_info_cb(int ok, unsigned char file_status,
+				int total_length, int record_length,
+				void *userdata)
+{
+	struct cb_data *cbd = userdata;
+	struct ofono_phonebook *pb = cbd->user;
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+	struct pb_file_info *file_info;
+	struct pb_ref_rec *ref = pbd->pb_ref_next->data;
+
+	file_info = ref->pb_next->data;
+	ref->pb_next = ref->pb_next->next;
+
+	if (ok) {
+		file_info->record_length = record_length;
+		file_info->file_length = total_length;
+
+		DBG("file id %x record length %d total_length %d",
+			file_info->file_id, record_length, total_length);
+	} else {
+		ofono_warn("%s: %x not found", __func__, file_info->file_id);
+		ref->pb_files = g_slist_remove(ref->pb_files, file_info);
+		g_free(file_info);
+	}
+
+	if (ref->pb_next == NULL) {
+		if (ref->pb_files == NULL) {
+			ofono_warn("%s: no phonebook on SIM", __func__);
+			export_and_return(FALSE, cbd);
+			return;
+		}
+
+		/* Read full contents of the master file */
+		file_info = ref->pb_files->data;
+
+		ofono_sim_read_path(pbd->sim_context, file_info->file_id,
+					OFONO_SIM_FILE_STRUCTURE_FIXED,
+					pbd->df_path, pbd->df_size,
+					pb_adn_cb, cbd);
+	} else {
+		file_info = ref->pb_next->data;
+
+		ofono_sim_read_info(pbd->sim_context, file_info->file_id,
+					OFONO_SIM_FILE_STRUCTURE_FIXED,
+					pbd->df_path, pbd->df_size,
+					read_info_cb, cbd);
+	}
+}
+
+static void start_sim_app_read(struct cb_data *cbd)
+{
+	struct ofono_phonebook *pb = cbd->user;
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+	struct pb_ref_rec *ref_rec;
+	struct pb_file_info *f_info;
+	struct pb_file_info *f_ext1;
+
+	pbd->df_path = sim_path;
+	pbd->df_size = sizeof(sim_path);
+
+	ref_rec = g_try_malloc0(sizeof(*ref_rec));
+	if (ref_rec == NULL) {
+		ofono_error("%s: OOM", __func__);
+		export_and_return(FALSE, cbd);
+		return;
+	}
+
+	ref_rec->phonebook = g_tree_new(comp_int);
+
+	/* Only EF_ADN and EF_EXT1 read for SIM */
+
+	f_info = g_try_malloc0(sizeof(*f_info));
+	if (f_info == NULL) {
+		ofono_error("%s: OOM", __func__);
+		export_and_return(FALSE, cbd);
+		return;
+	}
+
+	f_info->file_id = SIM_EFADN_FILEID;
+	f_info->pbr_type = TYPE_1_TAG;
+	f_info->file_type = TYPE_ADN;
+	ref_rec->pb_files = g_slist_append(ref_rec->pb_files, f_info);
+
+	f_ext1 = g_try_malloc0(sizeof(*f_ext1));
+	if (f_ext1 == NULL) {
+		ofono_error("%s: OOM", __func__);
+		export_and_return(FALSE, cbd);
+		return;
+	}
+
+	f_ext1->file_id = SIM_EFEXT1_FILEID;
+	f_ext1->pbr_type = TYPE_3_TAG;
+	f_ext1->file_type = TYPE_EXT1;
+	ref_rec->pb_files = g_slist_append(ref_rec->pb_files, f_ext1);
+
+	pbd->pb_refs = g_slist_append(pbd->pb_refs, ref_rec);
+	pbd->pb_ref_next = pbd->pb_refs;
+
+	ref_rec->pb_next = ref_rec->pb_files;
+
+	/* Start reading process for MF */
+	ofono_sim_read_info(pbd->sim_context, f_info->file_id,
+				OFONO_SIM_FILE_STRUCTURE_FIXED,
+				pbd->df_path, pbd->df_size,
+				read_info_cb, cbd);
+}
+
+static void pb_reference_data_cb(int ok, int total_length, int record,
+					const unsigned char *sdata,
+					int record_length, void *userdata)
+{
+	struct cb_data *cbd = userdata;
+	struct ofono_phonebook *pb = cbd->user;
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+	const unsigned char *ptr = sdata;
+	gboolean finished = FALSE;
+	struct pb_ref_rec *ref_rec;
+
+	DBG("total_length %d record %d record_length %d",
+		total_length, record, record_length);
+
+	if (!ok) {
+		/* We migh have a SIM instead of USIM application: try that */
+		DBG("%s: error %d, trying SIM files", __func__, ok);
+		start_sim_app_read(cbd);
+		return;
+	}
+
+	ref_rec = g_try_malloc0(sizeof(*ref_rec));
+	if (ref_rec == NULL) {
+		ofono_error("%s: OOM", __func__);
+		export_and_return(FALSE, cbd);
+		return;
+	}
+
+	ref_rec->phonebook = g_tree_new(comp_int);
+
+	while (ptr < sdata + record_length && finished == FALSE) {
+		int typelen, file_id, i;
+		enum constructed_tag pbr_type = *ptr;
+
+		switch (pbr_type) {
+		case TYPE_1_TAG:
+		case TYPE_2_TAG:
+		case TYPE_3_TAG:
+			typelen = *(ptr + 1);
+			DBG("File type=%02X, len=%d", *ptr, typelen);
+			ptr += 2;
+			i = 0;
+
+			while (i < typelen) {
+				struct pb_file_info *file_info =
+					g_try_new0(struct pb_file_info, 1);
+				if (!file_info) {
+					ofono_error("%s: OOM", __func__);
+					export_and_return(FALSE, cbd);
+					return;
+				}
+
+				file_id = (ptr[i + 2] << 8) + ptr[i + 3];
+
+				DBG("creating file info for File type=%02X",
+					ptr[i]);
+				DBG("File ID=%04X", file_id);
+
+				file_info->pbr_type = pbr_type;
+				file_info->file_type = ptr[i];
+				file_info->file_id = file_id;
+				/* Keep order, important for type 2 files */
+				ref_rec->pb_files =
+					g_slist_append(ref_rec->pb_files,
+							file_info);
+				i += ptr[i + 1] + 2;
+			}
+
+			ptr += typelen;
+			break;
+		default:
+			DBG("All handled %02x", *ptr);
+			finished = TRUE;
+			break;
+		}
+	}
+
+	pbd->pb_refs = g_slist_append(pbd->pb_refs, ref_rec);
+
+	if (record*record_length >= total_length) {
+		struct pb_ref_rec *ref;
+		struct pb_file_info *file_info;
+
+		DBG("All EFpbr records read");
+
+		pbd->pb_ref_next = pbd->pb_refs;
+		ref = pbd->pb_ref_next->data;
+
+		if (ref->pb_files == NULL) {
+			ofono_error("%s: no files to read", __func__);
+			export_and_return(FALSE, cbd);
+			return;
+		}
+
+		ref->pb_next = ref->pb_files;
+		file_info = ref->pb_files->data;
+
+		/* Start reading process for first EF_PBR entry */
+
+		ofono_sim_read_info(pbd->sim_context, file_info->file_id,
+					OFONO_SIM_FILE_STRUCTURE_FIXED,
+					pbd->df_path, pbd->df_size,
+					read_info_cb, cbd);
+	}
+}
+
+static void ril_export_entries(struct ofono_phonebook *pb,
+				const char *storage,
+				ofono_phonebook_cb_t cb, void *data)
+{
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+	struct cb_data *cbd;
+
+	DBG("Storage %s", storage);
+
+	/* Only for SIM memory */
+	if (strcmp(storage, "SM") != 0) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	cbd = cb_data_new(cb, data, pb);
+
+	/* Assume USIM, change in case EF_PBR is not present */
+	pbd->df_path = usim_path;
+	pbd->df_size = sizeof(usim_path);
+
+	ofono_sim_read(pbd->sim_context, SIM_EFPBR_FILEID,
+			OFONO_SIM_FILE_STRUCTURE_FIXED,
+			pb_reference_data_cb, cbd);
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_phonebook *pb = user_data;
+
+	ofono_phonebook_register(pb);
+	return FALSE;
+}
+
+static int ril_phonebook_probe(struct ofono_phonebook *pb,
+				unsigned int vendor, void *user)
+{
+	struct ofono_modem *modem = user;
+	struct pb_data *pd = g_try_new0(struct pb_data, 1);
+	if (pd == NULL)
+		return -ENOMEM;
+
+	pd->sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
+	if (pd->sim == NULL)
+		return -ENOENT;
+
+	pd->sim_context = ofono_sim_context_create(pd->sim);
+	if (pd->sim_context == NULL)
+		return -ENOENT;
+
+	ofono_phonebook_set_data(pb, pd);
+
+	g_idle_add(ril_delayed_register, pb);
+
+	return 0;
+}
+
+static void ril_phonebook_remove(struct ofono_phonebook *pb)
+{
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+
+	ofono_phonebook_set_data(pb, NULL);
+	ofono_sim_context_free(pbd->sim_context);
+
+	g_free(pbd);
+}
+
+static struct ofono_phonebook_driver driver = {
+	.name		= RILMODEM,
+	.probe		= ril_phonebook_probe,
+	.remove		= ril_phonebook_remove,
+	.export_entries	= ril_export_entries
+};
+
+void ril_phonebook_init(void)
+{
+	ofono_phonebook_driver_register(&driver);
+}
+
+void ril_phonebook_exit(void)
+{
+	ofono_phonebook_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/radio-settings.c b/drivers/rilmodem/radio-settings.c
new file mode 100644
index 0000000..9153e5b
--- /dev/null
+++ b/drivers/rilmodem/radio-settings.c
@@ -0,0 +1,300 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013 Jolla Ltd
+ *  Contact: Jussi Kangas <jussi.kangas@tieto.com>
+ *  Copyright (C) 2014 Canonical Ltd
+ *
+ *  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 <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/radio-settings.h>
+
+#include "gril.h"
+
+#include "rilmodem.h"
+
+#include "grilrequest.h"
+#include "grilreply.h"
+#include "radio-settings.h"
+
+static void ril_set_rat_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_radio_settings *rs = cbd->user;
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+	ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
+
+	if (message->error == RIL_E_SUCCESS) {
+		g_ril_print_response_no_args(rd->ril, message);
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	} else {
+		ofono_error("%s: rat mode setting failed", __func__);
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+}
+
+void ril_set_rat_mode(struct ofono_radio_settings *rs,
+			enum ofono_radio_access_mode mode,
+			ofono_radio_settings_rat_mode_set_cb_t cb,
+			void *data)
+{
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+	struct cb_data *cbd = cb_data_new(cb, data, rs);
+	struct parcel rilp;
+	int pref = PREF_NET_TYPE_GSM_WCDMA;
+
+	switch (mode) {
+	case OFONO_RADIO_ACCESS_MODE_ANY:
+		pref = PREF_NET_TYPE_LTE_GSM_WCDMA;
+		break;
+	case OFONO_RADIO_ACCESS_MODE_GSM:
+		pref = PREF_NET_TYPE_GSM_ONLY;
+		break;
+	case OFONO_RADIO_ACCESS_MODE_UMTS:
+		pref = PREF_NET_TYPE_GSM_WCDMA;
+		break;
+	case OFONO_RADIO_ACCESS_MODE_LTE:
+		pref = PREF_NET_TYPE_LTE_GSM_WCDMA;
+		break;
+	}
+
+	g_ril_request_set_preferred_network_type(rd->ril, pref, &rilp);
+
+	if (g_ril_send(rd->ril, RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE,
+				&rilp, ril_set_rat_cb, cbd, g_free) == 0) {
+		ofono_error("%s: unable to set rat mode", __func__);
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void ril_rat_mode_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
+	struct ofono_radio_settings *rs = cbd->user;
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+	int mode, pref;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: error %s", __func__,
+				ril_error_to_string(message->error));
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+		return;
+	}
+
+	pref = g_ril_reply_parse_get_preferred_network_type(rd->ril, message);
+	if (pref < 0) {
+		ofono_error("%s: parse error", __func__);
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+		return;
+	}
+
+	/*
+	 * GSM_WCDMA_AUTO -> ril.h: GSM/WCDMA (auto mode, according to PRL)
+	 * PRL: preferred roaming list.
+	 * This value is returned when selecting the slot as having 3G
+	 * capabilities, so it is sort of the default for MTK modems.
+	 */
+
+	switch (pref) {
+	case PREF_NET_TYPE_GSM_WCDMA:
+	case PREF_NET_TYPE_GSM_WCDMA_AUTO:
+		mode = OFONO_RADIO_ACCESS_MODE_UMTS;
+		break;
+	case PREF_NET_TYPE_GSM_ONLY:
+		mode = OFONO_RADIO_ACCESS_MODE_GSM;
+		break;
+	case PREF_NET_TYPE_LTE_GSM_WCDMA:
+		mode = OFONO_RADIO_ACCESS_MODE_LTE;
+		break;
+	default:
+		ofono_error("%s: Unexpected preferred network type (%d)",
+				__func__, pref);
+		mode = OFONO_RADIO_ACCESS_MODE_ANY;
+		break;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
+}
+
+void ril_query_rat_mode(struct ofono_radio_settings *rs,
+			ofono_radio_settings_rat_mode_query_cb_t cb,
+			void *data)
+{
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+	struct cb_data *cbd = cb_data_new(cb, data, rs);
+
+	if (g_ril_send(rd->ril, RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE,
+				NULL, ril_rat_mode_cb, cbd, g_free) == 0) {
+		ofono_error("%s: unable to send rat mode query", __func__);
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+	}
+}
+
+void ril_query_fast_dormancy(struct ofono_radio_settings *rs,
+			ofono_radio_settings_fast_dormancy_query_cb_t cb,
+			void *data)
+{
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+
+	CALLBACK_WITH_SUCCESS(cb, rd->fast_dormancy, data);
+}
+
+static void ril_display_state_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_radio_settings *rs = cbd->user;
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+	ofono_radio_settings_fast_dormancy_set_cb_t cb = cbd->cb;
+
+	if (message->error == RIL_E_SUCCESS) {
+		g_ril_print_response_no_args(rd->ril, message);
+
+		rd->fast_dormancy = rd->pending_fd;
+
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	} else {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+}
+
+void ril_set_fast_dormancy(struct ofono_radio_settings *rs,
+				ofono_bool_t enable,
+				ofono_radio_settings_fast_dormancy_set_cb_t cb,
+				void *data)
+{
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+	struct cb_data *cbd = cb_data_new(cb, data, rs);
+	struct parcel rilp;
+
+	g_ril_request_screen_state(rd->ril, enable ? 0 : 1, &rilp);
+
+	rd->pending_fd = enable;
+
+	if (g_ril_send(rd->ril, RIL_REQUEST_SCREEN_STATE, &rilp,
+			ril_display_state_cb, cbd, g_free) <= 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static ofono_bool_t query_available_rats_cb(gpointer user_data)
+{
+	unsigned int available_rats;
+	struct cb_data *cbd = user_data;
+	ofono_radio_settings_available_rats_query_cb_t cb = cbd->cb;
+	struct ofono_radio_settings *rs = cbd->user;
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+
+	available_rats = OFONO_RADIO_ACCESS_MODE_GSM
+				| OFONO_RADIO_ACCESS_MODE_UMTS;
+
+	if (ofono_modem_get_boolean(rd->modem, MODEM_PROP_LTE_CAPABLE))
+		available_rats |= OFONO_RADIO_ACCESS_MODE_LTE;
+
+	CALLBACK_WITH_SUCCESS(cb, available_rats, cbd->data);
+
+	g_free(cbd);
+
+	return FALSE;
+}
+
+void ril_query_available_rats(struct ofono_radio_settings *rs,
+			ofono_radio_settings_available_rats_query_cb_t cb,
+			void *data)
+{
+	struct cb_data *cbd = cb_data_new(cb, data, rs);
+
+	g_idle_add(query_available_rats_cb, cbd);
+}
+
+void ril_delayed_register(const struct ofono_error *error, void *user_data)
+{
+	struct ofono_radio_settings *rs = user_data;
+
+	if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
+		ofono_radio_settings_register(rs);
+	else
+		ofono_error("%s: cannot set default fast dormancy", __func__);
+}
+
+static int ril_radio_settings_probe(struct ofono_radio_settings *rs,
+					unsigned int vendor, void *user)
+{
+	struct ril_radio_settings_driver_data *rs_init_data = user;
+	struct radio_data *rsd = g_try_new0(struct radio_data, 1);
+
+	if (rsd == NULL) {
+		ofono_error("%s: cannot allocate memory", __func__);
+		return -ENOMEM;
+	}
+
+	rsd->ril = g_ril_clone(rs_init_data->gril);
+	rsd->modem = rs_init_data->modem;
+
+	ofono_radio_settings_set_data(rs, rsd);
+
+	ril_set_fast_dormancy(rs, FALSE, ril_delayed_register, rs);
+
+	return 0;
+}
+
+void ril_radio_settings_remove(struct ofono_radio_settings *rs)
+{
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+	ofono_radio_settings_set_data(rs, NULL);
+
+	g_ril_unref(rd->ril);
+	g_free(rd);
+}
+
+static struct ofono_radio_settings_driver driver = {
+	.name			= RILMODEM,
+	.probe			= ril_radio_settings_probe,
+	.remove			= ril_radio_settings_remove,
+	.query_rat_mode		= ril_query_rat_mode,
+	.set_rat_mode		= ril_set_rat_mode,
+	.query_fast_dormancy	= ril_query_fast_dormancy,
+	.set_fast_dormancy	= ril_set_fast_dormancy,
+	.query_available_rats	= ril_query_available_rats
+};
+
+void ril_radio_settings_init(void)
+{
+	ofono_radio_settings_driver_register(&driver);
+}
+
+void ril_radio_settings_exit(void)
+{
+	ofono_radio_settings_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/radio-settings.h b/drivers/rilmodem/radio-settings.h
new file mode 100644
index 0000000..727d538
--- /dev/null
+++ b/drivers/rilmodem/radio-settings.h
@@ -0,0 +1,47 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2014  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+struct radio_data {
+	GRil *ril;
+	struct ofono_modem *modem;
+	gboolean fast_dormancy;
+	gboolean pending_fd;
+};
+
+void ril_delayed_register(const struct ofono_error *error, void *user_data);
+void ril_radio_settings_remove(struct ofono_radio_settings *rs);
+void ril_query_rat_mode(struct ofono_radio_settings *rs,
+			ofono_radio_settings_rat_mode_query_cb_t cb,
+			void *data);
+void ril_set_rat_mode(struct ofono_radio_settings *rs,
+			enum ofono_radio_access_mode mode,
+			ofono_radio_settings_rat_mode_set_cb_t cb,
+			void *data);
+void ril_query_fast_dormancy(struct ofono_radio_settings *rs,
+			ofono_radio_settings_fast_dormancy_query_cb_t cb,
+			void *data);
+void ril_set_fast_dormancy(struct ofono_radio_settings *rs,
+				ofono_bool_t enable,
+				ofono_radio_settings_fast_dormancy_set_cb_t cb,
+				void *data);
+void ril_query_available_rats(struct ofono_radio_settings *rs,
+			ofono_radio_settings_available_rats_query_cb_t cb,
+			void *data);
diff --git a/drivers/rilmodem/rilmodem.c b/drivers/rilmodem/rilmodem.c
new file mode 100644
index 0000000..e693563
--- /dev/null
+++ b/drivers/rilmodem/rilmodem.c
@@ -0,0 +1,78 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL Modem Support
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012 Canonical, Ltd. 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 <glib.h>
+#include <gril.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/types.h>
+
+#include "rilmodem.h"
+
+static int rilmodem_init(void)
+{
+	DBG("");
+
+	ril_devinfo_init();
+	ril_sim_init();
+	ril_voicecall_init();
+	ril_sms_init();
+	ril_netreg_init();
+	ril_call_volume_init();
+	ril_gprs_init();
+	ril_gprs_context_init();
+	ril_ussd_init();
+	ril_call_settings_init();
+	ril_call_forwarding_init();
+	ril_radio_settings_init();
+	ril_call_barring_init();
+
+	return 0;
+}
+
+static void rilmodem_exit(void)
+{
+	DBG("");
+
+	ril_devinfo_exit();
+	ril_sim_exit();
+	ril_voicecall_exit();
+	ril_sms_exit();
+	ril_netreg_exit();
+	ril_call_volume_exit();
+	ril_gprs_exit();
+	ril_gprs_context_exit();
+	ril_ussd_exit();
+	ril_call_settings_exit();
+	ril_call_forwarding_exit();
+	ril_radio_settings_exit();
+	ril_call_barring_exit();
+}
+
+OFONO_PLUGIN_DEFINE(rilmodem, "RIL modem driver", VERSION,
+		OFONO_PLUGIN_PRIORITY_DEFAULT, rilmodem_init, rilmodem_exit)
diff --git a/drivers/rilmodem/rilmodem.h b/drivers/rilmodem/rilmodem.h
new file mode 100644
index 0000000..987ce3c
--- /dev/null
+++ b/drivers/rilmodem/rilmodem.h
@@ -0,0 +1,71 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL Modem Support
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012 Canonical Ltd.
+ *
+ *  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 "rilutil.h"
+
+#define RILMODEM "rilmodem"
+
+/* Shared constants */
+#define EF_STATUS_INVALIDATED 0
+#define EF_STATUS_VALID 1
+
+extern void ril_devinfo_init(void);
+extern void ril_devinfo_exit(void);
+
+extern void ril_call_volume_init(void);
+extern void ril_call_volume_exit(void);
+
+extern void ril_voicecall_init(void);
+extern void ril_voicecall_exit(void);
+
+extern void ril_sim_init(void);
+extern void ril_sim_exit(void);
+
+extern void ril_sms_init(void);
+extern void ril_sms_exit(void);
+
+extern void ril_netreg_init(void);
+extern void ril_netreg_exit(void);
+
+extern void ril_gprs_init(void);
+extern void ril_gprs_exit(void);
+
+extern void ril_gprs_context_init(void);
+extern void ril_gprs_context_exit(void);
+
+extern void ril_ussd_init(void);
+extern void ril_ussd_exit(void);
+
+extern void ril_call_settings_init(void);
+extern void ril_call_settings_exit(void);
+
+extern void ril_call_forwarding_init(void);
+extern void ril_call_forwarding_exit(void);
+
+extern void ril_radio_settings_init(void);
+extern void ril_radio_settings_exit(void);
+
+extern void ril_call_barring_init(void);
+extern void ril_call_barring_exit(void);
+
+extern void ril_phonebook_init(void);
+extern void ril_phonebook_exit(void);
diff --git a/drivers/rilmodem/rilutil.c b/drivers/rilmodem/rilutil.c
new file mode 100644
index 0000000..c173940
--- /dev/null
+++ b/drivers/rilmodem/rilutil.c
@@ -0,0 +1,194 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  Canonical Ltd.
+ *
+ *  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 <glib.h>
+#include <gril.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/log.h>
+#include <ofono/types.h>
+
+#include "common.h"
+#include "rilutil.h"
+#include "simutil.h"
+#include "util.h"
+#include "ril_constants.h"
+
+struct ril_util_sim_state_query {
+	GRil *ril;
+	guint cpin_poll_source;
+	guint cpin_poll_count;
+	guint interval;
+	guint num_times;
+	ril_util_sim_inserted_cb_t cb;
+	void *userdata;
+	GDestroyNotify destroy;
+};
+
+static gboolean cpin_check(gpointer userdata);
+
+void decode_ril_error(struct ofono_error *error, const char *final)
+{
+	if (!strcmp(final, "OK")) {
+		error->type = OFONO_ERROR_TYPE_NO_ERROR;
+		error->error = 0;
+	} else {
+		error->type = OFONO_ERROR_TYPE_FAILURE;
+		error->error = 0;
+	}
+}
+
+gint ril_util_call_compare_by_status(gconstpointer a, gconstpointer b)
+{
+	const struct ofono_call *call = a;
+	int status = GPOINTER_TO_INT(b);
+
+	if (status != call->status)
+		return 1;
+
+	return 0;
+}
+
+gint ril_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b)
+{
+	const struct ofono_call *call = a;
+	const struct ofono_phone_number *pb = b;
+
+	return memcmp(&call->phone_number, pb,
+				sizeof(struct ofono_phone_number));
+}
+
+gint ril_util_call_compare_by_id(gconstpointer a, gconstpointer b)
+{
+	const struct ofono_call *call = a;
+	unsigned int id = GPOINTER_TO_UINT(b);
+
+	if (id < call->id)
+		return -1;
+
+	if (id > call->id)
+		return 1;
+
+	return 0;
+}
+
+gint ril_util_call_compare(gconstpointer a, gconstpointer b)
+{
+	const struct ofono_call *ca = a;
+	const struct ofono_call *cb = b;
+
+	if (ca->id < cb->id)
+		return -1;
+
+	if (ca->id > cb->id)
+		return 1;
+
+	return 0;
+}
+
+static gboolean cpin_check(gpointer userdata)
+{
+	struct ril_util_sim_state_query *req = userdata;
+
+	req->cpin_poll_source = 0;
+
+	return FALSE;
+}
+
+gchar *ril_util_get_netmask(const gchar *address)
+{
+	char *result;
+
+	if (g_str_has_suffix(address, "/30")) {
+		result = PREFIX_30_NETMASK;
+	} else if (g_str_has_suffix(address, "/29")) {
+		result = PREFIX_29_NETMASK;
+	} else if (g_str_has_suffix(address, "/28")) {
+		result = PREFIX_28_NETMASK;
+	} else if (g_str_has_suffix(address, "/27")) {
+		result = PREFIX_27_NETMASK;
+	} else if (g_str_has_suffix(address, "/26")) {
+		result = PREFIX_26_NETMASK;
+	} else if (g_str_has_suffix(address, "/25")) {
+		result = PREFIX_25_NETMASK;
+	} else if (g_str_has_suffix(address, "/24")) {
+		result = PREFIX_24_NETMASK;
+	} else {
+		/*
+		 * This handles the case where the
+		 * Samsung RILD returns an address without
+		 * a prefix, however it explicitly sets a
+		 * /24 netmask ( which isn't returned as
+		 * an attribute of the DATA_CALL.
+		 *
+		 * TODO/OEM: this might need to be quirked
+		 * for specific devices.
+		 */
+		result = PREFIX_24_NETMASK;
+	}
+
+	DBG("address: %s netmask: %s", address, result);
+
+	return result;
+}
+
+struct ril_util_sim_state_query *ril_util_sim_state_query_new(GRil *ril,
+						guint interval, guint num_times,
+						ril_util_sim_inserted_cb_t cb,
+						void *userdata,
+						GDestroyNotify destroy)
+{
+	struct ril_util_sim_state_query *req;
+
+	req = g_new0(struct ril_util_sim_state_query, 1);
+
+	req->ril = ril;
+	req->interval = interval;
+	req->num_times = num_times;
+	req->cb = cb;
+	req->userdata = userdata;
+	req->destroy = destroy;
+
+	cpin_check(req);
+
+	return req;
+}
+
+void ril_util_sim_state_query_free(struct ril_util_sim_state_query *req)
+{
+	if (req == NULL)
+		return;
+
+	if (req->cpin_poll_source > 0)
+		g_source_remove(req->cpin_poll_source);
+
+	if (req->destroy)
+		req->destroy(req->userdata);
+
+	g_free(req);
+}
diff --git a/drivers/rilmodem/rilutil.h b/drivers/rilmodem/rilutil.h
new file mode 100644
index 0000000..25aed2e
--- /dev/null
+++ b/drivers/rilmodem/rilutil.h
@@ -0,0 +1,165 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+#ifndef RILUTIL_H
+#define RILUTIL_H
+
+#include <stdio.h>
+#include <modem.h>
+#include <sim.h>
+#include <gprs-context.h>
+
+/* TODO: create a table lookup*/
+#define PREFIX_30_NETMASK "255.255.255.252"
+#define PREFIX_29_NETMASK "255.255.255.248"
+#define PREFIX_28_NETMASK "255.255.255.240"
+#define PREFIX_27_NETMASK "255.255.255.224"
+#define PREFIX_26_NETMASK "255.255.255.192"
+#define PREFIX_25_NETMASK "255.255.255.128"
+#define PREFIX_24_NETMASK "255.255.255.0"
+
+#define MODEM_PROP_LTE_CAPABLE "lte-capable"
+
+enum ril_util_sms_store {
+	RIL_UTIL_SMS_STORE_SM =	0,
+	RIL_UTIL_SMS_STORE_ME =	1,
+	RIL_UTIL_SMS_STORE_MT =	2,
+	RIL_UTIL_SMS_STORE_SR =	3,
+	RIL_UTIL_SMS_STORE_BM =	4,
+};
+
+/* 3GPP TS 27.007 Release 8 Section 5.5 */
+enum at_util_charset {
+	RIL_UTIL_CHARSET_GSM =		0x1,
+	RIL_UTIL_CHARSET_HEX =		0x2,
+	RIL_UTIL_CHARSET_IRA =		0x4,
+	RIL_UTIL_CHARSET_PCCP437 =	0x8,
+	RIL_UTIL_CHARSET_PCDN =		0x10,
+	RIL_UTIL_CHARSET_UCS2 =		0x20,
+	RIL_UTIL_CHARSET_UTF8 =		0x40,
+	RIL_UTIL_CHARSET_8859_1 =	0x80,
+	RIL_UTIL_CHARSET_8859_2 =	0x100,
+	RIL_UTIL_CHARSET_8859_3 =	0x200,
+	RIL_UTIL_CHARSET_8859_4 =	0x400,
+	RIL_UTIL_CHARSET_8859_5 =	0x800,
+	RIL_UTIL_CHARSET_8859_6 =	0x1000,
+	RIL_UTIL_CHARSET_8859_C =	0x2000,
+	RIL_UTIL_CHARSET_8859_A =	0x4000,
+	RIL_UTIL_CHARSET_8859_G =	0x8000,
+	RIL_UTIL_CHARSET_8859_H =	0x10000,
+};
+
+struct ril_sim_data {
+	struct ofono_modem *modem;
+	GRil *gril;
+	ofono_sim_state_event_cb_t ril_state_watch;
+};
+
+struct ril_gprs_context_data {
+	GRil *gril;
+	struct ofono_modem *modem;
+	enum ofono_gprs_context_type type;
+};
+
+struct ril_voicecall_driver_data {
+	GRil *gril;
+	struct ofono_modem *modem;
+};
+
+struct ril_gprs_driver_data {
+	GRil *gril;
+	struct ofono_modem *modem;
+};
+
+struct ril_radio_settings_driver_data {
+	GRil *gril;
+	struct ofono_modem *modem;
+};
+
+typedef void (*ril_util_sim_inserted_cb_t)(gboolean present, void *userdata);
+
+void decode_ril_error(struct ofono_error *error, const char *final);
+gint ril_util_call_compare_by_status(gconstpointer a, gconstpointer b);
+gint ril_util_call_compare_by_phone_number(gconstpointer a, gconstpointer b);
+gint ril_util_call_compare_by_id(gconstpointer a, gconstpointer b);
+gint ril_util_call_compare(gconstpointer a, gconstpointer b);
+gchar *ril_util_get_netmask(const char *address);
+
+struct ril_util_sim_state_query *ril_util_sim_state_query_new(GRil *ril,
+						guint interval, guint num_times,
+						ril_util_sim_inserted_cb_t cb,
+						void *userdata,
+						GDestroyNotify destroy);
+void ril_util_sim_state_query_free(struct ril_util_sim_state_query *req);
+
+struct cb_data {
+	void *cb;
+	void *data;
+	void *user;
+};
+
+static inline struct cb_data *cb_data_new(void *cb, void *data, void *user)
+{
+	struct cb_data *ret;
+
+	ret = g_new0(struct cb_data, 1);
+	ret->cb = cb;
+	ret->data = data;
+	ret->user = user;
+
+	return ret;
+}
+
+static inline int ril_util_convert_signal_strength(int strength)
+{
+	int result;
+
+	if (strength == 99)
+		result = -1;
+	else
+		result = (strength * 100) / 31;
+
+	return result;
+}
+
+#define DECLARE_FAILURE(e)			\
+	struct ofono_error e;			\
+	e.type = OFONO_ERROR_TYPE_FAILURE;	\
+	e.error = 0				\
+
+#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)
+
+#endif /* RILUTIL_H */
diff --git a/drivers/rilmodem/sim.c b/drivers/rilmodem/sim.c
new file mode 100644
index 0000000..178cb97
--- /dev/null
+++ b/drivers/rilmodem/sim.c
@@ -0,0 +1,1200 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL Modem Support
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013 Canonical, Ltd. All rights reserved.
+ *  Copyright (C) 2015 Ratchanan Srirattanamet.
+ *
+ *  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/sim.h>
+
+#include "ofono.h"
+
+#include "simutil.h"
+#include "util.h"
+
+#include "gril.h"
+#include "grilutil.h"
+#include "parcel.h"
+#include "ril_constants.h"
+#include "rilmodem.h"
+
+#include "grilreply.h"
+#include "grilrequest.h"
+#include "grilunsol.h"
+
+#include "drivers/infineonmodem/infineon_constants.h"
+
+/* Number of passwords in EPINC response */
+#define MTK_EPINC_NUM_PASSWD 4
+
+/*
+ * Based on ../drivers/atmodem/sim.c.
+ *
+ * TODO:
+ * 1. Defines constants for hex literals
+ * 2. Document P1-P3 usage (+CSRM)
+ */
+
+/*
+ * TODO: CDMA/IMS
+ *
+ * This code currently only grabs the AID/application ID from
+ * the gsm_umts application on the SIM card.  This code will
+ * need to be modified for CDMA support, and possibly IMS-based
+ * applications.  In this case, app_id should be changed to an
+ * array or HashTable of app_status structures.
+ *
+ * The same applies to the app_type.
+ */
+
+static void ril_pin_change_state(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 {
+	GRil *ril;
+	enum ofono_ril_vendor vendor;
+	gchar *aid_str;
+	guint app_type;
+	gchar *app_str;
+	guint app_index;
+	enum ofono_sim_password_type passwd_type;
+	int retries[OFONO_SIM_PASSWORD_INVALID];
+	enum ofono_sim_password_type passwd_state;
+	struct ofono_modem *modem;
+	ofono_sim_state_event_cb_t ril_state_watch;
+	ofono_bool_t unlock_pending;
+};
+
+struct change_state_cbd {
+	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;
+};
+
+static void send_get_sim_status(struct ofono_sim *sim);
+
+static void ril_file_info_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_file_info_cb_t cb = cbd->cb;
+	struct sim_data *sd = cbd->user;
+	struct ofono_error error;
+	gboolean ok = FALSE;
+	int sw1, sw2;
+	int flen = 0, rlen = 0, str = 0;
+	guchar access[3] = { 0x00, 0x00, 0x00 };
+	guchar file_status = EF_STATUS_VALID;
+	struct reply_sim_io *reply = NULL;
+
+	/* Error, and no data */
+	if (message->error != RIL_E_SUCCESS && message->buf_len == 0) {
+		ofono_error("%s: Reply failure: %s", __func__,
+				ril_error_to_string(message->error));
+		decode_ril_error(&error, "FAIL");
+		goto error;
+	}
+
+	/*
+	 * The reply can have event data even when message->error is not zero
+	 * in mako.
+	 */
+	reply = g_ril_reply_parse_sim_io(sd->ril, message);
+	if (reply == NULL) {
+		decode_ril_error(&error, "FAIL");
+		goto error;
+	}
+
+	sw1 = reply->sw1;
+	sw2 = reply->sw2;
+
+	/*
+	 * SIM app file not found || USIM app file not found
+	 * See 3gpp TS 51.011, 9.4.4, and ETSI TS 102 221, 10.2.1.5.3
+	 * This can happen with result SUCCESS (maguro) or GENERIC_FAILURE
+	 * (mako)
+	 */
+	if ((sw1 == 0x94 && sw2 == 0x04) || (sw1 == 0x6A && sw2 == 0x82)) {
+		DBG("File not found. Error %s",
+			ril_error_to_string(message->error));
+		decode_ril_error(&error, "FAIL");
+		goto error;
+	}
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+	} else {
+		ofono_error("%s: Reply failure: %s, %02x, %02x", __func__,
+				ril_error_to_string(message->error), sw1, sw2);
+		decode_ril_error(&error, "FAIL");
+		goto error;
+	}
+
+	if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
+			(sw1 == 0x90 && sw2 != 0x00)) {
+		ofono_error("Error reply, invalid values: sw1: %02x sw2: %02x",
+				sw1, sw2);
+
+		/* TODO: fix decode_ril_error to take type & error */
+
+		error.type = OFONO_ERROR_TYPE_SIM;
+		error.error = (sw1 << 8) | sw2;
+
+		goto error;
+	}
+
+	if (reply->hex_len) {
+		if (reply->hex_response[0] == 0x62) {
+			ok = sim_parse_3g_get_response(reply->hex_response,
+							reply->hex_len,
+							&flen, &rlen, &str,
+							access, NULL);
+		} else {
+			ok = sim_parse_2g_get_response(reply->hex_response,
+							reply->hex_len,
+							&flen, &rlen, &str,
+							access, &file_status);
+		}
+	}
+
+	if (!ok) {
+		ofono_error("%s: parse response failed", __func__);
+		decode_ril_error(&error, "FAIL");
+		goto error;
+	}
+
+	cb(&error, flen, str, rlen, access, file_status, cbd->data);
+
+	g_ril_reply_free_sim_io(reply);
+
+	return;
+
+error:
+	g_ril_reply_free_sim_io(reply);
+
+	cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
+}
+
+static void ril_sim_read_info(struct ofono_sim *sim, int fileid,
+				const unsigned char *path,
+				unsigned int path_len,
+				ofono_sim_file_info_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd = cb_data_new(cb, data, sd);
+	struct parcel rilp;
+	struct req_sim_read_info req;
+	guint ret = 0;
+
+	DBG("file %04x", fileid);
+
+	req.app_type = sd->app_type;
+	req.aid_str = sd->aid_str;
+	req.fileid = fileid;
+	req.path = path;
+	req.path_len = path_len;
+
+	if (!g_ril_request_sim_read_info(sd->ril,
+					&req,
+					&rilp)) {
+		ofono_error("Couldn't build SIM read info request");
+		goto error;
+	}
+
+	g_ril_append_print_buf(sd->ril,
+				"%s0,0,15,(null),pin2=(null),aid=%s)",
+				print_buf,
+				sd->aid_str);
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_SIM_IO, &rilp,
+				ril_file_info_cb, cbd, g_free);
+
+error:
+	if (ret == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
+				EF_STATUS_INVALIDATED, data);
+	}
+}
+
+static void ril_file_io_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_read_cb_t cb = cbd->cb;
+	struct sim_data *sd = cbd->user;
+	struct ofono_error error;
+	struct reply_sim_io *reply;
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+	} else {
+		ofono_error("RILD reply failure: %s",
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	reply = g_ril_reply_parse_sim_io(sd->ril, message);
+	if (reply == NULL) {
+		ofono_error("Can't parse SIM IO response from RILD");
+		goto error;
+	}
+
+	if (reply->hex_len == 0) {
+		ofono_error("Null SIM IO response from RILD");
+		g_ril_reply_free_sim_io(reply);
+		goto error;
+	}
+
+	cb(&error, reply->hex_response, reply->hex_len, cbd->data);
+
+	g_ril_reply_free_sim_io(reply);
+
+	return;
+
+error:
+	decode_ril_error(&error, "FAIL");
+	cb(&error, NULL, 0, cbd->data);
+}
+
+static void ril_file_write_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_write_cb_t cb = cbd->cb;
+	struct sim_data *sd = cbd->user;
+	struct reply_sim_io *reply;
+	int sw1, sw2;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s: RILD reply failure: %s",
+				__func__, ril_error_to_string(message->error));
+		goto error;
+	}
+
+	reply = g_ril_reply_parse_sim_io(sd->ril, message);
+	if (reply == NULL) {
+		ofono_error("%s: Can't parse SIM IO response", __func__);
+		goto error;
+	}
+
+	sw1 = reply->sw1;
+	sw2 = reply->sw2;
+
+	g_ril_reply_free_sim_io(reply);
+
+	if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
+			(sw1 == 0x90 && sw2 != 0x00)) {
+		struct ofono_error error;
+
+		ofono_error("%s: error sw1 %02x sw2 %02x", __func__, sw1, sw2);
+
+		error.type = OFONO_ERROR_TYPE_SIM;
+		error.error = (sw1 << 8) | sw2;
+
+		cb(&error, cbd->data);
+
+		return;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+
+	return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+}
+
+static void ril_sim_read_binary(struct ofono_sim *sim, int fileid,
+				int start, int length,
+				const unsigned char *path,
+				unsigned int path_len,
+				ofono_sim_read_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd = cb_data_new(cb, data, sd);
+	struct parcel rilp;
+	struct req_sim_read_binary req;
+	gint ret = 0;
+
+	DBG("file %04x", fileid);
+
+	req.app_type = sd->app_type;
+	req.aid_str = sd->aid_str;
+	req.fileid = fileid;
+	req.path = path;
+	req.path_len = path_len;
+	req.start = start;
+	req.length = length;
+
+	if (!g_ril_request_sim_read_binary(sd->ril,
+						&req,
+						&rilp)) {
+		ofono_error("Couldn't build SIM read binary request");
+		goto error;
+	}
+
+	g_ril_append_print_buf(sd->ril,
+				"%s%d,%d,%d,(null),pin2=(null),aid=%s)",
+				print_buf,
+				(start >> 8),
+				(start & 0xff),
+				length,
+				sd->aid_str);
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_SIM_IO, &rilp,
+				ril_file_io_cb, cbd, g_free);
+error:
+	if (ret == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+	}
+}
+
+static void ril_sim_read_record(struct ofono_sim *sim, int fileid,
+				int record, int length,
+				const unsigned char *path,
+				unsigned int path_len,
+				ofono_sim_read_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd = cb_data_new(cb, data, sd);
+	struct parcel rilp;
+	struct req_sim_read_record req;
+	guint ret = 0;
+
+	DBG("file %04x", fileid);
+
+	req.app_type = sd->app_type;
+	req.aid_str = sd->aid_str;
+	req.fileid = fileid;
+	req.path = path;
+	req.path_len = path_len;
+	req.record = record;
+	req.length = length;
+
+	if (!g_ril_request_sim_read_record(sd->ril,
+						&req,
+						&rilp)) {
+		ofono_error("Couldn't build SIM read record request");
+		goto error;
+	}
+
+	g_ril_append_print_buf(sd->ril,
+				"%s%d,%d,%d,(null),pin2=(null),aid=%s)",
+				print_buf,
+				record,
+				4,
+				length,
+				sd->aid_str);
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_SIM_IO, &rilp,
+				ril_file_io_cb, cbd, g_free);
+
+error:
+	if (ret == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+	}
+}
+
+static void ril_sim_update_binary(struct ofono_sim *sim, int fileid,
+					int start, int length,
+					const unsigned char *value,
+					const unsigned char *path,
+					unsigned int path_len,
+					ofono_sim_write_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd = cb_data_new(cb, data, sd);
+	struct parcel rilp;
+	struct req_sim_write_binary req;
+	guint ret = 0;
+
+	DBG("file 0x%04x", fileid);
+
+	req.app_type = sd->app_type;
+	req.aid_str = sd->aid_str;
+	req.fileid = fileid;
+	req.path = path;
+	req.path_len = path_len;
+	req.start = start;
+	req.length = length;
+	req.data = value;
+
+	if (!g_ril_request_sim_write_binary(sd->ril, &req, &rilp)) {
+		ofono_error("%s: Couldn't build SIM write request", __func__);
+		goto error;
+	}
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_SIM_IO, &rilp,
+				ril_file_write_cb, cbd, g_free);
+
+error:
+	if (ret == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void update_record(struct ofono_sim *sim, int fileid,
+				enum req_record_access_mode mode,
+				int record, int length,
+				const unsigned char *value,
+				const unsigned char *path,
+				unsigned int path_len,
+				ofono_sim_write_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd = cb_data_new(cb, data, sd);
+	struct parcel rilp;
+	struct req_sim_write_record req;
+	guint ret = 0;
+
+	DBG("file 0x%04x", fileid);
+
+	req.app_type = sd->app_type;
+	req.aid_str = sd->aid_str;
+	req.fileid = fileid;
+	req.path = path;
+	req.path_len = path_len;
+	req.mode = mode;
+	req.record = record;
+	req.length = length;
+	req.data = value;
+
+	if (!g_ril_request_sim_write_record(sd->ril, &req, &rilp)) {
+		ofono_error("%s: Couldn't build SIM write request", __func__);
+		goto error;
+	}
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_SIM_IO, &rilp,
+				ril_file_write_cb, cbd, g_free);
+
+error:
+	if (ret == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void ril_sim_update_record(struct ofono_sim *sim, int fileid,
+					int record, int length,
+					const unsigned char *value,
+					const unsigned char *path,
+					unsigned int path_len,
+					ofono_sim_write_cb_t cb, void *data)
+{
+	update_record(sim, fileid, GRIL_REC_ACCESS_MODE_ABSOLUTE, record,
+			length, value, path, path_len, cb, data);
+}
+
+static void ril_sim_update_cyclic(struct ofono_sim *sim, int fileid,
+					int length, const unsigned char *value,
+					const unsigned char *path,
+					unsigned int path_len,
+					ofono_sim_write_cb_t cb, void *data)
+{
+	/* Only mode valid for cyclic files is PREVIOUS */
+	update_record(sim, fileid, GRIL_REC_ACCESS_MODE_PREVIOUS, 0,
+			length, value, path, path_len, cb, data);
+}
+
+static void ril_imsi_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_imsi_cb_t cb = cbd->cb;
+	struct sim_data *sd = cbd->user;
+	struct ofono_error error;
+	gchar *imsi;
+
+	if (message->error == RIL_E_SUCCESS) {
+		DBG("GET IMSI reply - OK");
+		decode_ril_error(&error, "OK");
+	} else {
+		ofono_error("Reply failure: %s",
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	imsi = g_ril_reply_parse_imsi(sd->ril, message);
+	if (imsi == NULL) {
+		ofono_error("Error empty IMSI");
+		goto error;
+	}
+
+	cb(&error, imsi, cbd->data);
+	g_free(imsi);
+
+	return;
+
+error:
+	decode_ril_error(&error, "FAIL");
+	cb(&error, NULL, cbd->data);
+}
+
+static void ril_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 = cb_data_new(cb, data, sd);
+	struct parcel rilp;
+
+	g_ril_request_read_imsi(sd->ril, sd->aid_str, &rilp);
+
+	if (g_ril_send(sd->ril, RIL_REQUEST_GET_IMSI, &rilp,
+			ril_imsi_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, NULL, data);
+	}
+}
+
+static void configure_active_app(struct sim_data *sd,
+					struct reply_sim_app *app,
+					guint index)
+{
+	g_free(sd->aid_str);
+	g_free(sd->app_str);
+	sd->app_type = app->app_type;
+	sd->aid_str = g_strdup(app->aid_str);
+	sd->app_str = g_strdup(app->app_str);
+	sd->app_index = index;
+
+	DBG("setting aid_str (AID) to: %s", sd->aid_str);
+	switch (app->app_state) {
+	case RIL_APPSTATE_PIN:
+		sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PIN;
+		break;
+	case RIL_APPSTATE_PUK:
+		sd->passwd_state = OFONO_SIM_PASSWORD_SIM_PUK;
+		break;
+	case RIL_APPSTATE_SUBSCRIPTION_PERSO:
+		switch (app->perso_substate) {
+		case RIL_PERSOSUBSTATE_SIM_NETWORK:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHNET_PIN;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHNETSUB_PIN;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_CORPORATE:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHCORP_PIN;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHSP_PIN;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_SIM:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHSIM_PIN;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_NETWORK_PUK:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHNET_PUK;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHNETSUB_PUK;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHCORP_PUK;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHSP_PUK;
+			break;
+		case RIL_PERSOSUBSTATE_SIM_SIM_PUK:
+			sd->passwd_state = OFONO_SIM_PASSWORD_PHFSIM_PUK;
+			break;
+		default:
+			sd->passwd_state = OFONO_SIM_PASSWORD_NONE;
+			break;
+		};
+		break;
+	case RIL_APPSTATE_READY:
+		sd->passwd_state = OFONO_SIM_PASSWORD_NONE;
+		break;
+	case RIL_APPSTATE_UNKNOWN:
+	case RIL_APPSTATE_DETECTED:
+	default:
+		sd->passwd_state = OFONO_SIM_PASSWORD_INVALID;
+		break;
+	}
+}
+
+static void sim_status_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_sim *sim = user_data;
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct reply_sim_status *status;
+	guint search_index;
+
+	status = g_ril_reply_parse_sim_status(sd->ril, message);
+	if (status == NULL) {
+		ofono_error("%s: Cannot parse SIM status reply", __func__);
+		return;
+	}
+
+	DBG("SIM status is %u", status->card_state);
+
+	if (status->card_state == RIL_CARDSTATE_PRESENT)
+		ofono_sim_inserted_notify(sim, TRUE);
+	else if (status && status->card_state == RIL_CARDSTATE_ABSENT)
+		ofono_sim_inserted_notify(sim, FALSE);
+	else
+		ofono_error("%s: bad SIM state (%u)",
+				__func__, status->card_state);
+
+	if (status->card_state == RIL_CARDSTATE_PRESENT) {
+		/*
+		 * TODO(CDMA): need some kind of logic
+		 * to set the correct app_index
+		 */
+		search_index = status->gsm_umts_index;
+		if (search_index < status->num_apps) {
+			struct reply_sim_app *app = status->apps[search_index];
+
+			if (app->app_type != RIL_APPTYPE_UNKNOWN) {
+				/*
+				 * We cache the current password state. Ideally
+				 * this should be done by issuing a
+				 * GET_SIM_STATUS request from
+				 * ril_query_passwd_state, which is called by
+				 * the core after sending a password, but
+				 * unfortunately the response to GET_SIM_STATUS
+				 * is not reliable in mako when sent just after
+				 * sending the password. Some time is needed
+				 * before the modem refreshes its internal
+				 * state, and when it does it sends a
+				 * SIM_STATUS_CHANGED event. In that moment we
+				 * retrieve the status and this function is
+				 * executed. We call __ofono_sim_recheck_pin as
+				 * it is the only way to indicate the core to
+				 * call query_passwd_state again. An option
+				 * that can be explored in the future is wait
+				 * before invoking core callback for send_passwd
+				 * until we know the real password state.
+				 */
+				configure_active_app(sd, app, search_index);
+				DBG("passwd_state: %d", sd->passwd_state);
+
+				/*
+				 * Note: There doesn't seem to be any other way
+				 * to force the core SIM code to recheck the
+				 * PIN. This call causes the core to call this
+				 * atom's query_passwd() function.
+				 */
+				__ofono_sim_recheck_pin(sim);
+			}
+		}
+	}
+
+	g_ril_reply_free_sim_status(status);
+}
+
+static void send_get_sim_status(struct ofono_sim *sim)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	g_ril_send(sd->ril, RIL_REQUEST_GET_SIM_STATUS, NULL,
+			sim_status_cb, sim, NULL);
+}
+
+static void ril_sim_status_changed(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_sim *sim = (struct ofono_sim *) user_data;
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	DBG("");
+
+	g_ril_print_unsol_no_args(sd->ril, message);
+
+	send_get_sim_status(sim);
+}
+
+static void inf_pin_retries_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_pin_retries_cb_t cb = cbd->cb;
+	struct sim_data *sd = cbd->user;
+	struct reply_oem_hook *reply = NULL;
+	int32_t *ret_data;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("Reply failure: %s",
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	reply = g_ril_reply_oem_hook_raw(sd->ril, message);
+	if (reply == NULL) {
+		ofono_error("%s: parse error", __func__);
+		goto error;
+	}
+
+	if (reply->length < 5 * (int) sizeof(int32_t)) {
+		ofono_error("%s: reply too small", __func__);
+		goto error;
+	}
+
+	/* First integer is INF_RIL_REQUEST_OEM_GET_REMAIN_SIM_PIN_ATTEMPTS */
+	ret_data = reply->data;
+	sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] = *(++ret_data);
+	sd->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = *(++ret_data);
+	sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = *(++ret_data);
+	sd->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = *(++ret_data);
+
+	g_ril_reply_free_oem_hook(reply);
+	CALLBACK_WITH_SUCCESS(cb, sd->retries, cbd->data);
+
+	return;
+
+error:
+	g_ril_reply_free_oem_hook(reply);
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
+static void mtk_pin_retries_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_pin_retries_cb_t cb = cbd->cb;
+	struct sim_data *sd = cbd->user;
+	struct parcel_str_array *str_arr = NULL;
+	int pin[MTK_EPINC_NUM_PASSWD];
+	int num_pin;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("Reply failure: %s",
+				ril_error_to_string(message->error));
+		goto error;
+	}
+
+	str_arr = g_ril_reply_oem_hook_strings(sd->ril, message);
+	if (str_arr == NULL || str_arr->num_str < 1) {
+		ofono_error("%s: parse error", __func__);
+		goto error;
+	}
+
+	num_pin = sscanf(str_arr->str[0], "+EPINC:%d,%d,%d,%d",
+					&pin[0], &pin[1], &pin[2], &pin[3]);
+
+	if (num_pin != MTK_EPINC_NUM_PASSWD) {
+		ofono_error("%s: failed parsing %s", __func__, str_arr->str[0]);
+		goto error;
+	}
+
+	sd->retries[OFONO_SIM_PASSWORD_SIM_PIN] = pin[0];
+	sd->retries[OFONO_SIM_PASSWORD_SIM_PIN2] = pin[1];
+	sd->retries[OFONO_SIM_PASSWORD_SIM_PUK] = pin[2];
+	sd->retries[OFONO_SIM_PASSWORD_SIM_PUK2] = pin[3];
+
+	parcel_free_str_array(str_arr);
+	CALLBACK_WITH_SUCCESS(cb, sd->retries, cbd->data);
+	return;
+
+error:
+	parcel_free_str_array(str_arr);
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+}
+
+static void ril_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);
+
+	DBG("");
+
+	if (sd->vendor == OFONO_RIL_VENDOR_INFINEON) {
+		struct cb_data *cbd = cb_data_new(cb, data, sd);
+		struct parcel rilp;
+		int32_t oem_req =
+			INF_RIL_REQUEST_OEM_GET_REMAIN_SIM_PIN_ATTEMPTS;
+
+		g_ril_request_oem_hook_raw(sd->ril, &oem_req,
+						sizeof(oem_req), &rilp);
+
+		/* Send request to RIL */
+		if (g_ril_send(sd->ril, RIL_REQUEST_OEM_HOOK_RAW, &rilp,
+				inf_pin_retries_cb, cbd, g_free) == 0) {
+			g_free(cbd);
+			CALLBACK_WITH_FAILURE(cb, NULL, data);
+		}
+	} else if (sd->vendor == OFONO_RIL_VENDOR_MTK) {
+		struct cb_data *cbd = cb_data_new(cb, data, sd);
+		struct parcel rilp;
+		const char *at_epinc[] = { "AT+EPINC", "+EPINC:" };
+
+		g_ril_request_oem_hook_strings(sd->ril, at_epinc,
+						G_N_ELEMENTS(at_epinc), &rilp);
+
+		if (g_ril_send(sd->ril, RIL_REQUEST_OEM_HOOK_STRINGS, &rilp,
+				mtk_pin_retries_cb, cbd, g_free) == 0) {
+			g_free(cbd);
+			CALLBACK_WITH_FAILURE(cb, NULL, data);
+		}
+	} else {
+		CALLBACK_WITH_SUCCESS(cb, sd->retries, data);
+	}
+}
+
+static void ril_query_passwd_state(struct ofono_sim *sim,
+					ofono_sim_passwd_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	DBG("passwd_state %u", sd->passwd_state);
+
+	if (sd->passwd_state == OFONO_SIM_PASSWORD_INVALID)
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+	else
+		CALLBACK_WITH_SUCCESS(cb, sd->passwd_state, data);
+}
+
+static void ril_pin_change_state_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ofono_sim *sim = cbd->user;
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	int *retries;
+	/*
+	 * There is no reason to ask SIM status until
+	 * unsolicited sim status change indication
+	 * Looks like state does not change before that.
+	 */
+
+	DBG("Enter password: type %d, result %d",
+		sd->passwd_type, message->error);
+
+	retries = g_ril_reply_parse_retries(sd->ril, message, sd->passwd_type);
+	if (retries != NULL) {
+		memcpy(sd->retries, retries, sizeof(sd->retries));
+		g_free(retries);
+	}
+
+	/* TODO: re-factor to not use macro for FAILURE;
+	   doesn't return error! */
+	if (message->error == RIL_E_SUCCESS) {
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	} else {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		/*
+		 * Refresh passwd_state (not needed if the unlock is
+		 * successful, as an event will refresh the state in that case)
+		 */
+		send_get_sim_status(sim);
+	}
+}
+
+static void ril_pin_send(struct ofono_sim *sim, const char *passwd,
+				ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+	/*
+	 * TODO: This function is supposed to enter the pending password, which
+	 * might be also PIN2. So we must check the pending PIN in the future.
+	 */
+
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd = cb_data_new(cb, data, sim);
+	struct parcel rilp;
+
+	sd->passwd_type = OFONO_SIM_PASSWORD_SIM_PIN;
+
+	g_ril_request_pin_send(sd->ril,
+				passwd,
+				sd->aid_str,
+				&rilp);
+
+	if (g_ril_send(sd->ril, RIL_REQUEST_ENTER_SIM_PIN, &rilp,
+			ril_pin_change_state_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void enter_pin_done(const struct ofono_error *error, void *data)
+{
+	struct change_state_cbd *csd = data;
+	struct sim_data *sd = ofono_sim_get_data(csd->sim);
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		ofono_error("%s: wrong password", __func__);
+		sd->unlock_pending = FALSE;
+		CALLBACK_WITH_FAILURE(csd->cb, csd->data);
+	} else {
+		ril_pin_change_state(csd->sim, csd->passwd_type, csd->enable,
+					csd->passwd, csd->cb, csd->data);
+	}
+
+	g_free(csd);
+}
+
+static void ril_pin_change_state(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 parcel rilp;
+	struct req_pin_change_state req;
+	int ret = 0;
+
+	/*
+	 * If we want to unlock a password that has not been entered yet,
+	 * we enter it before trying to unlock. We need sd->unlock_pending as
+	 * the password still has not yet been refreshed when this function is
+	 * called from enter_pin_done().
+	 */
+	if (ofono_sim_get_password_type(sim) == passwd_type
+			&& enable == FALSE && sd->unlock_pending == FALSE) {
+		struct change_state_cbd *csd = g_malloc0(sizeof(*csd));
+		csd->sim = sim;
+		csd->passwd_type = passwd_type;
+		csd->enable = enable;
+		csd->passwd = passwd;
+		csd->cb = cb;
+		csd->data = data;
+		sd->unlock_pending = TRUE;
+
+		ril_pin_send(sim, passwd, enter_pin_done, csd);
+
+		return;
+	}
+
+	sd->unlock_pending = FALSE;
+
+	cbd = cb_data_new(cb, data, sim);
+
+	sd->passwd_type = passwd_type;
+
+	req.aid_str = sd->aid_str;
+	req.passwd_type = passwd_type;
+	req.enable = enable;
+	req.passwd = passwd;
+
+	if (!g_ril_request_pin_change_state(sd->ril,
+						&req,
+						&rilp)) {
+		ofono_error("Couldn't build pin change state request");
+		goto error;
+	}
+
+	ret = g_ril_send(sd->ril, RIL_REQUEST_SET_FACILITY_LOCK, &rilp,
+				ril_pin_change_state_cb, cbd, g_free);
+
+error:
+	if (ret == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void ril_pin_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 = cb_data_new(cb, data, sim);
+	struct parcel rilp;
+
+	sd->passwd_type = OFONO_SIM_PASSWORD_SIM_PUK;
+
+	g_ril_request_pin_send_puk(sd->ril,
+					puk,
+					passwd,
+					sd->aid_str,
+					&rilp);
+
+	if (g_ril_send(sd->ril, RIL_REQUEST_ENTER_SIM_PUK, &rilp,
+			ril_pin_change_state_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void ril_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 = cb_data_new(cb, data, sim);
+	struct parcel rilp;
+	int request = RIL_REQUEST_CHANGE_SIM_PIN;
+
+	sd->passwd_type = passwd_type;
+
+	g_ril_request_change_passwd(sd->ril,
+					old_passwd,
+					new_passwd,
+					sd->aid_str,
+					&rilp);
+
+	if (passwd_type == OFONO_SIM_PASSWORD_SIM_PIN2)
+		request = RIL_REQUEST_CHANGE_SIM_PIN2;
+
+	if (g_ril_send(sd->ril, request, &rilp, ril_pin_change_state_cb,
+			cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static gboolean listen_and_get_sim_status(gpointer user)
+{
+	struct ofono_sim *sim = user;
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	send_get_sim_status(sim);
+
+	g_ril_register(sd->ril, RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,
+			(GRilNotifyFunc) ril_sim_status_changed, sim);
+
+	/* TODO: should we also register for RIL_UNSOL_SIM_REFRESH? */
+	return FALSE;
+}
+
+static gboolean ril_sim_register(gpointer user)
+{
+	struct ofono_sim *sim = user;
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	DBG("");
+
+	ofono_sim_register(sim);
+
+	if (sd->ril_state_watch != NULL &&
+			!ofono_sim_add_state_watch(sim, sd->ril_state_watch,
+							sd->modem, NULL))
+		ofono_error("Error registering ril sim watch");
+
+	/*
+	 * We use g_idle_add here to make sure that the presence of the SIM
+	 * interface is signalled before signalling anything else from the said
+	 * interface, as ofono_sim_register also uses g_idle_add.
+	 */
+	g_idle_add(listen_and_get_sim_status, sim);
+
+	return FALSE;
+}
+
+static int ril_sim_probe(struct ofono_sim *sim, unsigned int vendor,
+				void *data)
+{
+	struct ril_sim_data *ril_data = data;
+	GRil *ril = ril_data->gril;
+	struct sim_data *sd;
+	int i;
+
+	sd = g_new0(struct sim_data, 1);
+	sd->ril = g_ril_clone(ril);
+	sd->vendor = vendor;
+	sd->aid_str = NULL;
+	sd->app_str = NULL;
+	sd->app_type = RIL_APPTYPE_UNKNOWN;
+	sd->passwd_state = OFONO_SIM_PASSWORD_NONE;
+	sd->passwd_type = OFONO_SIM_PASSWORD_NONE;
+	sd->modem = ril_data->modem;
+	sd->ril_state_watch = ril_data->ril_state_watch;
+
+	for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
+		sd->retries[i] = -1;
+
+	ofono_sim_set_data(sim, sd);
+
+	/*
+	 * TODO: analyze if capability check is needed
+	 * and/or timer should be adjusted.
+	 *
+	 * ofono_sim_register() needs to be called after the
+	 * driver has been set in ofono_sim_create(), which
+	 * calls this function.	 Most other drivers make some
+	 * kind of capabilities query to the modem, and then
+	 * call register in the callback; we use an idle event
+	 * instead.
+	 */
+	g_idle_add(ril_sim_register, sim);
+
+	return 0;
+}
+
+static void ril_sim_remove(struct ofono_sim *sim)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	ofono_sim_set_data(sim, NULL);
+
+	g_ril_unref(sd->ril);
+	g_free(sd->aid_str);
+	g_free(sd->app_str);
+	g_free(sd);
+}
+
+static struct ofono_sim_driver driver = {
+	.name			= RILMODEM,
+	.probe			= ril_sim_probe,
+	.remove			= ril_sim_remove,
+	.read_file_info		= ril_sim_read_info,
+	.read_file_transparent	= ril_sim_read_binary,
+	.read_file_linear	= ril_sim_read_record,
+	.read_file_cyclic	= ril_sim_read_record,
+	.write_file_transparent	= ril_sim_update_binary,
+	.write_file_linear	= ril_sim_update_record,
+	.write_file_cyclic	= ril_sim_update_cyclic,
+	.read_imsi		= ril_read_imsi,
+	.query_passwd_state	= ril_query_passwd_state,
+	.send_passwd		= ril_pin_send,
+	.query_pin_retries	= ril_query_pin_retries,
+	.reset_passwd		= ril_pin_send_puk,
+	.change_passwd		= ril_change_passwd,
+	.lock			= ril_pin_change_state,
+/*
+ * TODO: Implmenting PIN/PUK support requires defining
+ * the following driver methods.
+ *
+ * In the meanwhile, as long as the SIM card is present,
+ * and unlocked, the core SIM code will check for the
+ * presence of query_passwd_state, and if null, then the
+ * function sim_initialize_after_pin() is called.
+ *
+ *	.query_locked		= ril_pin_query_enabled,
+ */
+};
+
+void ril_sim_init(void)
+{
+	DBG("");
+	ofono_sim_driver_register(&driver);
+}
+
+void ril_sim_exit(void)
+{
+	ofono_sim_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/sms.c b/drivers/rilmodem/sms.c
new file mode 100644
index 0000000..14816e5
--- /dev/null
+++ b/drivers/rilmodem/sms.c
@@ -0,0 +1,315 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL Modem Support
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2013 Canonical Ltd.
+ *  Copyright (C) 2013 Jolla Ltd.
+ *
+ *  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 <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <gril.h>
+#include <parcel.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/sms.h>
+#include "smsutil.h"
+#include "util.h"
+
+#include "rilmodem.h"
+#include "grilrequest.h"
+#include "grilreply.h"
+#include "grilunsol.h"
+
+struct sms_data {
+	GRil *ril;
+	unsigned int vendor;
+};
+
+static void ril_csca_set_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sms_sca_set_cb_t cb = cbd->cb;
+	struct sms_data *sd = cbd->user;
+
+	if (message->error == RIL_E_SUCCESS) {
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	} else {
+		ofono_error("%s RILD reply failure: %s",
+			g_ril_request_id_to_string(sd->ril, message->req),
+			ril_error_to_string(message->error));
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+}
+
+static void ril_csca_set(struct ofono_sms *sms,
+			const struct ofono_phone_number *sca,
+			ofono_sms_sca_set_cb_t cb, void *user_data)
+{
+	struct sms_data *sd = ofono_sms_get_data(sms);
+	struct cb_data *cbd = cb_data_new(cb, user_data, sd);
+	struct parcel rilp;
+
+	g_ril_request_set_smsc_address(sd->ril, sca, &rilp);
+
+	/* Send request to RIL */
+	if (g_ril_send(sd->ril, RIL_REQUEST_SET_SMSC_ADDRESS, &rilp,
+			ril_csca_set_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, user_data);
+	}
+}
+
+static void ril_csca_query_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_sms_sca_query_cb_t cb = cbd->cb;
+	struct sms_data *sd = cbd->user;
+	struct ofono_phone_number *sca;
+
+	if (message->error != RIL_E_SUCCESS) {
+		ofono_error("%s RILD reply failure: %s",
+			g_ril_request_id_to_string(sd->ril, message->req),
+			ril_error_to_string(message->error));
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+		return;
+	}
+
+	sca = g_ril_reply_parse_get_smsc_address(sd->ril, message);
+	if (sca == NULL) {
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+	} else {
+		CALLBACK_WITH_SUCCESS(cb, sca, cbd->data);
+		g_free(sca);
+	}
+}
+
+static void ril_csca_query(struct ofono_sms *sms, ofono_sms_sca_query_cb_t cb,
+					void *user_data)
+{
+	struct sms_data *sd = ofono_sms_get_data(sms);
+	struct cb_data *cbd = cb_data_new(cb, user_data, sd);
+
+	DBG("Sending csca_query");
+
+	if (g_ril_send(sd->ril, RIL_REQUEST_GET_SMSC_ADDRESS, NULL,
+			ril_csca_query_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, NULL, user_data);
+	}
+}
+
+static void ril_submit_sms_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_error error;
+	ofono_sms_submit_cb_t cb = cbd->cb;
+	struct sms_data *sd = cbd->user;
+	int mr = 0;
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+		mr = g_ril_reply_parse_sms_response(sd->ril, message);
+	} else {
+		decode_ril_error(&error, "FAIL");
+	}
+
+	cb(&error, mr, cbd->data);
+}
+
+static void ril_cmgs(struct ofono_sms *sms, const unsigned char *pdu,
+			int pdu_len, int tpdu_len, int mms,
+			ofono_sms_submit_cb_t cb, void *user_data)
+{
+	struct sms_data *sd = ofono_sms_get_data(sms);
+	struct cb_data *cbd = cb_data_new(cb, user_data, sd);
+	struct parcel rilp;
+	struct req_sms_cmgs req;
+
+	DBG("pdu_len: %d, tpdu_len: %d mms: %d", pdu_len, tpdu_len, mms);
+
+	/* TODO: if (mms) { ... } */
+
+	req.pdu = pdu;
+	req.pdu_len = pdu_len;
+	req.tpdu_len = tpdu_len;
+
+	g_ril_request_sms_cmgs(sd->ril, &req, &rilp);
+
+	if (g_ril_send(sd->ril, RIL_REQUEST_SEND_SMS, &rilp,
+			ril_submit_sms_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, -1, user_data);
+	}
+}
+
+static void ril_ack_delivery_cb(struct ril_msg *message, gpointer user_data)
+{
+	if (message->error != RIL_E_SUCCESS)
+		ofono_error("SMS acknowledgement failed: "
+				"Further SMS reception is not guaranteed");
+}
+
+static void ril_ack_delivery(struct ofono_sms *sms)
+{
+	struct sms_data *sd = ofono_sms_get_data(sms);
+	struct parcel rilp;
+
+	g_ril_request_sms_acknowledge(sd->ril, &rilp);
+
+	/* TODO: should ACK be sent for either of the error cases? */
+
+	/* ACK the incoming NEW_SMS */
+	g_ril_send(sd->ril, RIL_REQUEST_SMS_ACKNOWLEDGE, &rilp,
+			ril_ack_delivery_cb, NULL, NULL);
+
+}
+
+static void ril_sms_notify(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_sms *sms = user_data;
+	struct sms_data *sd = ofono_sms_get_data(sms);
+	unsigned int smsc_len;
+	long ril_buf_len;
+	struct unsol_sms_data *pdu_data;
+
+	DBG("req: %d; data_len: %d", message->req, (int) message->buf_len);
+
+	pdu_data = g_ril_unsol_parse_new_sms(sd->ril, message);
+	if (pdu_data == NULL)
+		goto error;
+
+	/*
+	 * The first octect in the pdu contains the SMSC address length
+	 * which is the X following octects it reads. We add 1 octet to
+	 * the read length to take into account this read octet in order
+	 * to calculate the proper tpdu length.
+	 */
+	smsc_len = pdu_data->data[0] + 1;
+	ril_buf_len = pdu_data->length;
+	DBG("smsc_len is %d", smsc_len);
+
+	if (message->req == RIL_UNSOL_RESPONSE_NEW_SMS)
+		/* Last parameter is 'tpdu_len' ( substract SMSC length ) */
+		ofono_sms_deliver_notify(sms, pdu_data->data,
+						ril_buf_len,
+						ril_buf_len - smsc_len);
+	else if (message->req == RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT)
+		ofono_sms_status_notify(sms, pdu_data->data, ril_buf_len,
+						ril_buf_len - smsc_len);
+
+	/* ACK the incoming NEW_SMS */
+	ril_ack_delivery(sms);
+
+	g_ril_unsol_free_sms_data(pdu_data);
+
+error:
+	;
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_sms *sms = user_data;
+	struct sms_data *data = ofono_sms_get_data(sms);
+
+	DBG("");
+	ofono_sms_register(sms);
+
+	/* register to receive INCOMING_SMS and SMS status reports */
+	g_ril_register(data->ril, RIL_UNSOL_RESPONSE_NEW_SMS,
+			ril_sms_notify,	sms);
+	g_ril_register(data->ril, RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
+			ril_sms_notify, sms);
+
+	/* This makes the delayed call a single-shot */
+	return FALSE;
+}
+
+static int ril_sms_probe(struct ofono_sms *sms, unsigned int vendor,
+				void *user)
+{
+	GRil *ril = user;
+	struct sms_data *data;
+
+	data = g_new0(struct sms_data, 1);
+	data->ril = g_ril_clone(ril);
+	data->vendor = vendor;
+
+	ofono_sms_set_data(sms, data);
+
+	/*
+	 * ofono_sms_register() needs to be called after
+	 * the driver has been set in ofono_sms_create(), which
+	 * calls this function.  Most other drivers make some
+	 * kind of capabilities query to the modem, and then
+	 * call register in the callback; we use an idle add instead.
+	 */
+	g_idle_add(ril_delayed_register, sms);
+
+	return 0;
+}
+
+static void ril_sms_remove(struct ofono_sms *sms)
+{
+	struct sms_data *data = ofono_sms_get_data(sms);
+
+	DBG("");
+
+	g_ril_unref(data->ril);
+	g_free(data);
+
+	ofono_sms_set_data(sms, NULL);
+}
+
+static struct ofono_sms_driver driver = {
+	.name		= RILMODEM,
+	.probe		= ril_sms_probe,
+	.sca_query	= ril_csca_query,
+	.sca_set	= ril_csca_set,
+	.remove		= ril_sms_remove,
+	.submit		= ril_cmgs,
+
+	/*
+	 * TODO: investigate/implement:
+	 * .bearer_query  = NULL,
+	 * .bearer_set	  = NULL,
+	 */
+};
+
+void ril_sms_init(void)
+{
+	DBG("");
+	if (ofono_sms_driver_register(&driver))
+		DBG("ofono_sms_driver_register failed!");
+}
+
+void ril_sms_exit(void)
+{
+	DBG("");
+	ofono_sms_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/ussd.c b/drivers/rilmodem/ussd.c
new file mode 100644
index 0000000..04985ec
--- /dev/null
+++ b/drivers/rilmodem/ussd.c
@@ -0,0 +1,264 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013 Jolla Ltd
+ *  Copyright (C) 2013 Canonical Ltd
+ *
+ *  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 <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/ussd.h>
+#include <smsutil.h>
+#include <util.h>
+
+#include "gril.h"
+#include "grilutil.h"
+#include "grilrequest.h"
+#include "grilunsol.h"
+
+#include "rilmodem.h"
+
+#include "ril_constants.h"
+
+struct ussd_data {
+	GRil *ril;
+};
+
+static gboolean request_success(gpointer data)
+{
+	struct cb_data *cbd = data;
+	ofono_ussd_cb_t cb = cbd->cb;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	g_free(cbd);
+
+	return FALSE;
+}
+
+static void ril_ussd_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_ussd *ussd = user_data;
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+
+	/*
+	 * We fake an ON_USSD event if there was an error sending the request,
+	 * as core will be waiting for one to respond to the Initiate() call.
+	 * Note that we already made the callback (see ril_ussd_request()).
+	 */
+	if (message->error == RIL_E_SUCCESS)
+		g_ril_print_response_no_args(ud->ril, message);
+	else
+		ofono_ussd_notify(ussd, OFONO_USSD_STATUS_NOT_SUPPORTED,
+					0, NULL, 0);
+}
+
+static void ril_ussd_request(struct ofono_ussd *ussd, int dcs,
+			const unsigned char *pdu, int len,
+			ofono_ussd_cb_t cb, void *data)
+{
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+	struct cb_data *cbd = cb_data_new(cb, data, ussd);
+	enum sms_charset charset;
+	char *text = NULL;
+	int ret = 0;
+
+	if (cbs_dcs_decode(dcs, NULL, NULL, &charset, NULL, NULL, NULL)) {
+
+		if (charset == SMS_CHARSET_7BIT) {
+			long written;
+
+			text = (char *) unpack_7bit(pdu, len, 0, TRUE,
+							0, &written, 1);
+			if (text != NULL)
+				*(text + written) = '\0';
+
+		} else if (charset == SMS_CHARSET_UCS2) {
+			text = g_convert((char *) pdu, len,
+					"UTF-8//TRANSLIT", "UCS-2BE",
+					NULL, NULL, NULL);
+		} else {
+			ofono_error("%s: No support for charset %d",
+					__func__, charset);
+		}
+	}
+
+	if (text) {
+		struct parcel rilp;
+
+		g_ril_request_send_ussd(ud->ril, text, &rilp);
+
+		ret = g_ril_send(ud->ril, RIL_REQUEST_SEND_USSD,
+					&rilp, ril_ussd_cb, ussd, NULL);
+		g_free(text);
+	}
+
+	/*
+	 * We do not wait for the SEND_USSD reply to do the callback, as some
+	 * networks send it after sending one or more ON_USSD events. From the
+	 * ofono core perspective, Initiate() does not return until one ON_USSD
+	 * event is received: making here a successful callback just makes the
+	 * core wait for that event.
+	 */
+	if (ret <= 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	} else {
+		g_idle_add(request_success, cbd);
+	}
+}
+
+static void ril_ussd_cancel_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_ussd *ussd = cbd->user;
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+	ofono_ussd_cb_t cb = cbd->cb;
+
+	if (message->error == RIL_E_SUCCESS) {
+		g_ril_print_response_no_args(ud->ril, message);
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	} else {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+}
+
+static void ril_ussd_cancel(struct ofono_ussd *ussd,
+				ofono_ussd_cb_t cb, void *user_data)
+{
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+	struct cb_data *cbd = cb_data_new(cb, user_data, ussd);
+	int ret;
+
+	ret = g_ril_send(ud->ril, RIL_REQUEST_CANCEL_USSD, NULL,
+				ril_ussd_cancel_cb, cbd, g_free);
+
+	if (ret <= 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, user_data);
+	}
+}
+
+static void ril_ussd_notify(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_ussd *ussd = user_data;
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+	struct unsol_ussd *unsol;
+
+	unsol = g_ril_unsol_parse_ussd(ud->ril, message);
+	if (unsol == NULL) {
+		ofono_error("%s: Parsing error", __func__);
+		return;
+	}
+
+	/* To fix bug in MTK: USSD-Notify arrive with type 2 instead of 0 */
+	if (g_ril_vendor(ud->ril) == OFONO_RIL_VENDOR_MTK &&
+			unsol->message != NULL && unsol->type == 2)
+		unsol->type = 0;
+
+	/*
+	 * With data coding scheme 0x48, we are saying that the ussd string is a
+	 * UCS-2 string, uncompressed, and with unspecified message class. For
+	 * the DCS coding, see 3gpp 23.038, sect. 5.
+	 */
+	if (unsol->message != NULL) {
+		gsize written;
+		char *ucs2;
+
+		ucs2 = g_convert(unsol->message, -1, "UCS-2BE//TRANSLIT",
+					"UTF-8", NULL, &written, NULL);
+		if (ucs2 != NULL) {
+			ofono_ussd_notify(ussd, unsol->type, 0x48,
+					(unsigned char *) ucs2, written);
+			g_free(ucs2);
+		} else {
+			ofono_error("%s: Error transcoding", __func__);
+		}
+	} else {
+		ofono_ussd_notify(ussd, unsol->type, 0, NULL, 0);
+	}
+
+	g_ril_unsol_free_ussd(unsol);
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_ussd *ussd = user_data;
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+
+	DBG("");
+
+	ofono_ussd_register(ussd);
+
+	/* Register for USSD responses */
+	g_ril_register(ud->ril, RIL_UNSOL_ON_USSD, ril_ussd_notify, ussd);
+
+	return FALSE;
+}
+
+static int ril_ussd_probe(struct ofono_ussd *ussd,
+					unsigned int vendor,
+					void *user)
+{
+	GRil *ril = user;
+	struct ussd_data *ud = g_new0(struct ussd_data, 1);
+
+	ud->ril = g_ril_clone(ril);
+	ofono_ussd_set_data(ussd, ud);
+	g_idle_add(ril_delayed_register, ussd);
+
+	return 0;
+}
+
+static void ril_ussd_remove(struct ofono_ussd *ussd)
+{
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+	ofono_ussd_set_data(ussd, NULL);
+
+	g_ril_unref(ud->ril);
+	g_free(ud);
+}
+
+static struct ofono_ussd_driver driver = {
+	.name		= RILMODEM,
+	.probe		= ril_ussd_probe,
+	.remove		= ril_ussd_remove,
+	.request	= ril_ussd_request,
+	.cancel		= ril_ussd_cancel
+};
+
+void ril_ussd_init(void)
+{
+	ofono_ussd_driver_register(&driver);
+}
+
+void ril_ussd_exit(void)
+{
+	ofono_ussd_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/vendor.h b/drivers/rilmodem/vendor.h
new file mode 100644
index 0000000..83cc939
--- /dev/null
+++ b/drivers/rilmodem/vendor.h
@@ -0,0 +1,32 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2014  Canonical Ltd. 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
+ *
+ */
+
+#ifndef RILMODEM_VENDOR_H
+#define RILMODEM_VENDOR_H
+
+enum ofono_ril_vendor {
+	OFONO_RIL_VENDOR_AOSP = 0,
+	OFONO_RIL_VENDOR_MTK,
+	OFONO_RIL_VENDOR_INFINEON,
+	OFONO_RIL_VENDOR_QCOM_MSIM
+};
+
+#endif /* RILMODEM_VENDOR_H */
diff --git a/drivers/rilmodem/voicecall.c b/drivers/rilmodem/voicecall.c
new file mode 100644
index 0000000..3fa4b37
--- /dev/null
+++ b/drivers/rilmodem/voicecall.c
@@ -0,0 +1,824 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2013 Canonical Ltd.
+ *  Copyright (C) 2013 Jolla Ltd.
+ *
+ *  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.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/voicecall.h>
+
+#include "gril.h"
+#include "grilrequest.h"
+#include "grilreply.h"
+#include "grilunsol.h"
+
+#include "common.h"
+#include "rilmodem.h"
+#include "voicecall.h"
+
+/* Amount of ms we wait between CLCC calls */
+#define POLL_CLCC_INTERVAL 300
+
+#define FLAG_NEED_CLIP 1
+
+#define MAX_DTMF_BUFFER 32
+
+/* To use with change_state_req::affected_types */
+#define AFFECTED_STATES_ALL 0x3F
+
+/* Auto-answer delay in seconds */
+#define AUTO_ANSWER_DELAY_S 3
+
+struct release_id_req {
+	struct ofono_voicecall *vc;
+	ofono_voicecall_cb_t cb;
+	void *data;
+	int id;
+};
+
+struct change_state_req {
+	struct ofono_voicecall *vc;
+	ofono_voicecall_cb_t cb;
+	void *data;
+	/* Call states affected by a local release (1 << enum call_status) */
+	int affected_types;
+};
+
+struct lastcause_req {
+	struct ofono_voicecall *vc;
+	int id;
+};
+
+/* Data for dial after swap */
+struct hold_before_dial_req {
+	struct ofono_voicecall *vc;
+	struct ofono_phone_number dial_ph;
+	enum ofono_clir_option dial_clir;
+};
+
+static void send_one_dtmf(struct ril_voicecall_data *vd);
+static void clear_dtmf_queue(struct ril_voicecall_data *vd);
+
+static void lastcause_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct lastcause_req *reqdata = user_data;
+	struct ofono_voicecall *vc = reqdata->vc;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	enum ofono_disconnect_reason reason;
+
+	reason = g_ril_reply_parse_call_fail_cause(vd->ril, message);
+
+	DBG("Call %d ended with reason %d", reqdata->id, reason);
+
+	ofono_voicecall_disconnected(vc, reqdata->id, reason, NULL);
+}
+
+static gboolean auto_answer_call(gpointer user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+
+	DBG("");
+
+	ril_answer(vc, NULL, NULL);
+
+	return FALSE;
+}
+
+static gboolean is_auto_answer(struct ril_voicecall_data *vd,
+				struct ofono_call *call)
+{
+	static const char test_mcc_mnc_1[] = "00101";
+	static const char test_mcc_mnc_2[] = "001001";
+
+	const char *imsi;
+	struct ofono_sim *sim;
+
+	if (call->status != CALL_STATUS_INCOMING)
+		return FALSE;
+
+	sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, vd->modem);
+	if (sim == NULL)
+		return FALSE;
+
+	imsi = ofono_sim_get_imsi(sim);
+	if (imsi == NULL)
+		return FALSE;
+
+	if (strncmp(imsi, test_mcc_mnc_1, sizeof(test_mcc_mnc_1) - 1) == 0 ||
+		strncmp(imsi, test_mcc_mnc_2, sizeof(test_mcc_mnc_2) - 1)
+			== 0) {
+		ofono_info("Auto answering incoming call, imsi is %s", imsi);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void clcc_poll_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	int reqid = RIL_REQUEST_LAST_CALL_FAIL_CAUSE;
+	GSList *calls;
+	GSList *n, *o;
+	struct ofono_call *nc, *oc;
+
+	/*
+	 * We consider all calls have been dropped if there is no radio, which
+	 * happens, for instance, when flight mode is set whilst in a call.
+	 */
+	if (message->error != RIL_E_SUCCESS &&
+			message->error != RIL_E_RADIO_NOT_AVAILABLE) {
+		ofono_error("We are polling CLCC and received an error");
+		ofono_error("All bets are off for call management");
+		return;
+	}
+
+	calls = g_ril_reply_parse_get_calls(vd->ril, message);
+
+	n = calls;
+	o = vd->calls;
+
+	while (n || o) {
+		nc = n ? n->data : NULL;
+		oc = o ? o->data : NULL;
+
+		/* TODO: Add comments explaining call id handling */
+		if (oc && (nc == NULL || (nc->id > oc->id))) {
+			if (vd->local_release & (1 << oc->id)) {
+				ofono_voicecall_disconnected(vc, oc->id,
+					OFONO_DISCONNECT_REASON_LOCAL_HANGUP,
+					NULL);
+			} else if (message->error ==
+						RIL_E_RADIO_NOT_AVAILABLE) {
+				ofono_voicecall_disconnected(vc, oc->id,
+					OFONO_DISCONNECT_REASON_ERROR,
+					NULL);
+			} else {
+				/* Get disconnect cause before calling core */
+				struct lastcause_req *reqdata =
+					g_try_new0(struct lastcause_req, 1);
+				if (reqdata != NULL) {
+					reqdata->vc = user_data;
+					reqdata->id = oc->id;
+
+					g_ril_send(vd->ril, reqid, NULL,
+							lastcause_cb, reqdata,
+							g_free);
+				}
+			}
+
+			clear_dtmf_queue(vd);
+
+			o = o->next;
+		} else if (nc && (oc == NULL || (nc->id < oc->id))) {
+			/* new call, signal it */
+			if (nc->type) {
+				ofono_voicecall_notify(vc, nc);
+
+				if (vd->cb) {
+					struct ofono_error error;
+					ofono_voicecall_cb_t cb = vd->cb;
+					decode_ril_error(&error, "OK");
+					cb(&error, vd->data);
+					vd->cb = NULL;
+					vd->data = NULL;
+				}
+
+				if (is_auto_answer(vd, nc))
+					g_timeout_add_seconds(
+							AUTO_ANSWER_DELAY_S,
+							auto_answer_call, vc);
+			}
+
+			n = n->next;
+		} else {
+			/*
+			 * Always use the clip_validity from old call
+			 * the only place this is truly told to us is
+			 * in the CLIP notify, the rest are fudged
+			 * anyway.  Useful when RING, CLIP is used,
+			 * and we're forced to use CLCC and clip_validity
+			 * is 1
+			 */
+			if (oc->clip_validity == 1)
+				nc->clip_validity = oc->clip_validity;
+
+			nc->cnap_validity = oc->cnap_validity;
+
+			/*
+			 * CDIP doesn't arrive as part of CLCC, always
+			 * re-use from the old call
+			 */
+			memcpy(&nc->called_number, &oc->called_number,
+					sizeof(oc->called_number));
+
+			/*
+			 * If the CLIP is not provided and the CLIP never
+			 * arrives, or RING is used, then signal the call
+			 * here
+			 */
+			if (nc->status == CALL_STATUS_INCOMING &&
+					(vd->flags & FLAG_NEED_CLIP)) {
+				if (nc->type)
+					ofono_voicecall_notify(vc, nc);
+
+				vd->flags &= ~FLAG_NEED_CLIP;
+			} else if (memcmp(nc, oc, sizeof(*nc)) && nc->type)
+				ofono_voicecall_notify(vc, nc);
+
+			n = n->next;
+			o = o->next;
+		}
+	}
+
+	g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
+	g_slist_free(vd->calls);
+
+	vd->calls = calls;
+	vd->local_release = 0;
+}
+
+gboolean ril_poll_clcc(gpointer user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+	g_ril_send(vd->ril, RIL_REQUEST_GET_CURRENT_CALLS, NULL,
+			clcc_poll_cb, vc, NULL);
+
+	vd->clcc_source = 0;
+
+	return FALSE;
+}
+
+static void generic_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct change_state_req *req = user_data;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(req->vc);
+	struct ofono_error error;
+
+	if (message->error == RIL_E_SUCCESS) {
+		decode_ril_error(&error, "OK");
+	} else {
+		decode_ril_error(&error, "FAIL");
+		goto out;
+	}
+
+	g_ril_print_response_no_args(vd->ril, message);
+
+	if (req->affected_types) {
+		GSList *l;
+		struct ofono_call *call;
+
+		for (l = vd->calls; l; l = l->next) {
+			call = l->data;
+
+			if (req->affected_types & (1 << call->status))
+				vd->local_release |= (1 << call->id);
+		}
+	}
+
+out:
+	g_ril_send(vd->ril, RIL_REQUEST_GET_CURRENT_CALLS, NULL,
+			clcc_poll_cb, req->vc, NULL);
+
+	/* We have to callback after we schedule a poll if required */
+	if (req->cb)
+		req->cb(&error, req->data);
+}
+
+static int ril_template(const guint rreq, struct ofono_voicecall *vc,
+			GRilResponseFunc func, unsigned int affected_types,
+			gpointer pdata, ofono_voicecall_cb_t cb, void *data)
+{
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct change_state_req *req = g_try_new0(struct change_state_req, 1);
+	int ret;
+
+	if (req == NULL)
+		goto error;
+
+	req->vc = vc;
+	req->cb = cb;
+	req->data = data;
+	req->affected_types = affected_types;
+
+	ret = g_ril_send(vd->ril, rreq, pdata, func, req, g_free);
+	if (ret > 0)
+		return ret;
+error:
+	g_free(req);
+
+	if (cb)
+		CALLBACK_WITH_FAILURE(cb, data);
+
+	return 0;
+}
+
+static void rild_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ofono_voicecall *vc = cbd->user;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	ofono_voicecall_cb_t cb = cbd->cb;
+	struct ofono_error error;
+
+	/*
+	 * DIAL_MODIFIED_TO_DIAL means redirection. The call we will see when
+	 * polling will have a different called number.
+	 */
+	if (message->error == RIL_E_SUCCESS ||
+			(g_ril_vendor(vd->ril) == OFONO_RIL_VENDOR_AOSP &&
+			message->error == RIL_E_DIAL_MODIFIED_TO_DIAL)) {
+		decode_ril_error(&error, "OK");
+	} else {
+		decode_ril_error(&error, "FAIL");
+		goto out;
+	}
+
+	g_ril_print_response_no_args(vd->ril, message);
+
+	/* CLCC will update the oFono call list with proper ids  */
+	if (!vd->clcc_source)
+		vd->clcc_source = g_timeout_add(POLL_CLCC_INTERVAL,
+						ril_poll_clcc, vc);
+
+	/* we cannot answer just yet since we don't know the call id */
+	vd->cb = cb;
+	vd->data = cbd->data;
+
+	return;
+
+out:
+	cb(&error, cbd->data);
+}
+
+static void dial(struct ofono_voicecall *vc,
+			const struct ofono_phone_number *ph,
+			enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
+			void *data)
+{
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct cb_data *cbd = cb_data_new(cb, data, vc);
+	struct parcel rilp;
+
+	g_ril_request_dial(vd->ril, ph, clir, &rilp);
+
+	/* Send request to RIL */
+	if (g_ril_send(vd->ril, RIL_REQUEST_DIAL, &rilp,
+			rild_cb, cbd, g_free) == 0) {
+		g_free(cbd);
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void hold_before_dial_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct hold_before_dial_req *req = cbd->user;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(req->vc);
+	ofono_voicecall_cb_t cb = cbd->cb;
+
+	if (message->error != RIL_E_SUCCESS) {
+		g_free(req);
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		return;
+	}
+
+	g_ril_print_response_no_args(vd->ril, message);
+
+	/* Current calls held: we can dial now */
+	dial(req->vc, &req->dial_ph, req->dial_clir, cb, cbd->data);
+
+	g_free(req);
+}
+
+void ril_dial(struct ofono_voicecall *vc, const struct ofono_phone_number *ph,
+		enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
+		void *data)
+{
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	int current_active = 0;
+	struct ofono_call *call;
+	GSList *l;
+
+	/* Check for current active calls */
+	for (l = vd->calls; l; l = l->next) {
+		call = l->data;
+
+		if (call->status == CALL_STATUS_ACTIVE) {
+			current_active = 1;
+			break;
+		}
+	}
+
+	/*
+	 * The network will put current active calls on hold. In some cases
+	 * (mako), the modem also updates properly the state. In others
+	 * (maguro), we need to explicitly set the state to held. In both cases
+	 * we send a request for holding the active call, as it is not harmful
+	 * when it is not really needed, and is what Android does.
+	 */
+	if (current_active) {
+		struct hold_before_dial_req *req;
+		struct cb_data *cbd;
+
+		req = g_malloc0(sizeof(*req));
+		req->vc = vc;
+		req->dial_ph = *ph;
+		req->dial_clir = clir;
+
+		cbd = cb_data_new(cb, data, req);
+
+		if (g_ril_send(vd->ril, RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE,
+				NULL, hold_before_dial_cb, cbd, g_free) == 0) {
+			g_free(cbd);
+			CALLBACK_WITH_FAILURE(cb, data);
+		}
+
+	} else {
+		dial(vc, ph, clir, cb, data);
+	}
+}
+
+void ril_hangup_all(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
+			void *data)
+{
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct parcel rilp;
+	struct ofono_error error;
+	struct ofono_call *call;
+	GSList *l;
+
+	for (l = vd->calls; l; l = l->next) {
+		call = l->data;
+
+		if (call->status == CALL_STATUS_INCOMING) {
+			/*
+			 * Need to use this request so that declined
+			 * calls in this state, are properly forwarded
+			 * to voicemail.  REQUEST_HANGUP doesn't do the
+			 * right thing for some operators, causing the
+			 * caller to hear a fast busy signal.
+			 */
+			ril_template(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
+					vc, generic_cb, AFFECTED_STATES_ALL,
+					NULL, NULL, NULL);
+		} else {
+
+			/* TODO: Hangup just the active ones once we have call
+			 * state tracking (otherwise it can't handle ringing) */
+			g_ril_request_hangup(vd->ril, call->id, &rilp);
+
+			/* Send request to RIL */
+			ril_template(RIL_REQUEST_HANGUP, vc, generic_cb,
+					AFFECTED_STATES_ALL, &rilp, NULL, NULL);
+		}
+	}
+
+	/* TODO: Deal in case of an error at hungup */
+	decode_ril_error(&error, "OK");
+	cb(&error, data);
+}
+
+void ril_hangup_specific(struct ofono_voicecall *vc,
+				int id, ofono_voicecall_cb_t cb, void *data)
+{
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct parcel rilp;
+
+	DBG("Hanging up call with id %d", id);
+
+	g_ril_request_hangup(vd->ril, id, &rilp);
+
+	/* Send request to RIL */
+	ril_template(RIL_REQUEST_HANGUP, vc, generic_cb,
+			AFFECTED_STATES_ALL, &rilp, cb, data);
+}
+
+void ril_call_state_notify(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+	g_ril_print_unsol_no_args(vd->ril, message);
+
+	/* Just need to request the call list again */
+	ril_poll_clcc(vc);
+
+	return;
+}
+
+static void ril_ss_notify(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct unsol_supp_svc_notif *unsol;
+
+	unsol = g_ril_unsol_parse_supp_svc_notif(vd->ril,  message);
+	if (unsol == NULL) {
+		ofono_error("%s: Parsing error", __func__);
+		return;
+	}
+
+	DBG("RIL data: MT/MO: %i, code: %i, index: %i",
+		unsol->notif_type, unsol->code, unsol->index);
+
+	/* 0 stands for MO intermediate, 1 for MT unsolicited */
+	/* TODO How do we know the affected call? Refresh call list? */
+	if (unsol->notif_type == 1)
+		ofono_voicecall_ssn_mt_notify(
+			vc, 0, unsol->code, unsol->index, &unsol->number);
+	else
+		ofono_voicecall_ssn_mo_notify(vc, 0, unsol->code, unsol->index);
+
+	g_ril_unsol_free_supp_svc_notif(unsol);
+}
+
+void ril_answer(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb, void *data)
+{
+	DBG("Answering current call");
+
+	/* Send request to RIL */
+	ril_template(RIL_REQUEST_ANSWER, vc, generic_cb, 0, NULL, cb, data);
+}
+
+static void ril_send_dtmf_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct ril_voicecall_data *vd = user_data;
+
+	if (message->error == RIL_E_SUCCESS) {
+		/* Remove sent DTMF character from queue */
+		gchar *tmp_tone_queue = g_strdup(vd->tone_queue + 1);
+		int remaining = strlen(tmp_tone_queue);
+
+		memcpy(vd->tone_queue, tmp_tone_queue, remaining);
+		vd->tone_queue[remaining] = '\0';
+		g_free(tmp_tone_queue);
+
+		vd->tone_pending = FALSE;
+
+		if (remaining > 0)
+			send_one_dtmf(vd);
+	} else {
+		DBG("error=%d", message->error);
+		clear_dtmf_queue(vd);
+	}
+}
+
+static void send_one_dtmf(struct ril_voicecall_data *vd)
+{
+	struct parcel rilp;
+
+	if (vd->tone_pending == TRUE)
+		return; /* RIL request pending */
+
+	if (strlen(vd->tone_queue) == 0)
+		return; /* nothing to send */
+
+	g_ril_request_dtmf(vd->ril, vd->tone_queue[0], &rilp);
+
+	g_ril_send(vd->ril, RIL_REQUEST_DTMF, &rilp,
+			ril_send_dtmf_cb, vd, NULL);
+
+	vd->tone_pending = TRUE;
+}
+
+void ril_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
+			ofono_voicecall_cb_t cb, void *data)
+{
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct ofono_error error;
+
+	DBG("Queue '%s'", dtmf);
+
+	/*
+	 * Queue any incoming DTMF (up to MAX_DTMF_BUFFER characters),
+	 * send them to RIL one-by-one, immediately call back
+	 * core with no error
+	 */
+	g_strlcat(vd->tone_queue, dtmf, MAX_DTMF_BUFFER);
+	send_one_dtmf(vd);
+
+	/* We don't really care about errors here */
+	decode_ril_error(&error, "OK");
+	cb(&error, data);
+}
+
+static void clear_dtmf_queue(struct ril_voicecall_data *vd)
+{
+	g_free(vd->tone_queue);
+	vd->tone_queue = g_strnfill(MAX_DTMF_BUFFER + 1, '\0');
+	vd->tone_pending = FALSE;
+}
+
+void ril_create_multiparty(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	ril_template(RIL_REQUEST_CONFERENCE, vc, generic_cb, 0, NULL, cb, data);
+}
+
+void ril_private_chat(struct ofono_voicecall *vc, int id,
+			ofono_voicecall_cb_t cb, void *data)
+{
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct parcel rilp;
+
+	g_ril_request_separate_conn(vd->ril, id, &rilp);
+
+	/* Send request to RIL */
+	ril_template(RIL_REQUEST_SEPARATE_CONNECTION, vc,
+			generic_cb, 0, &rilp, cb, data);
+}
+
+void ril_swap_without_accept(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	ril_template(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE, vc,
+			generic_cb, 0, NULL, cb, data);
+}
+
+void ril_hold_all_active(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	ril_template(RIL_REQUEST_SWITCH_HOLDING_AND_ACTIVE, vc,
+			generic_cb, 0, NULL, cb, data);
+}
+
+void ril_release_all_held(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	ril_template(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, vc,
+			generic_cb, 0, NULL, cb, data);
+}
+
+void ril_release_all_active(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	ril_template(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, vc,
+			generic_cb, 0, NULL, cb, data);
+}
+
+void ril_set_udub(struct ofono_voicecall *vc,
+			ofono_voicecall_cb_t cb, void *data)
+{
+	ril_template(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, vc,
+			generic_cb, 0, NULL, cb, data);
+}
+
+static gboolean enable_supp_svc(gpointer user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	struct parcel rilp;
+
+	g_ril_request_set_supp_svc_notif(vd->ril, &rilp);
+
+	g_ril_send(vd->ril, RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, &rilp,
+			NULL, vc, NULL);
+
+	/* Makes this a single shot */
+	return FALSE;
+}
+
+static gboolean ril_delayed_register(gpointer user_data)
+{
+	struct ofono_voicecall *vc = user_data;
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+	ofono_voicecall_register(vc);
+
+	/* Initialize call list */
+	ril_poll_clcc(vc);
+
+	/* Unsol when call state changes */
+	g_ril_register(vd->ril, RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
+			ril_call_state_notify, vc);
+
+	/* Unsol when call set on hold */
+	g_ril_register(vd->ril, RIL_UNSOL_SUPP_SVC_NOTIFICATION,
+			ril_ss_notify, vc);
+
+	/* request supplementary service notifications*/
+	enable_supp_svc(vc);
+
+	/* This makes the timeout a single-shot */
+	return FALSE;
+}
+
+void ril_voicecall_start(struct ril_voicecall_driver_data *driver_data,
+				struct ofono_voicecall *vc,
+				unsigned int vendor,
+				struct ril_voicecall_data *vd)
+{
+	vd->ril = g_ril_clone(driver_data->gril);
+	vd->modem = driver_data->modem;
+	vd->vendor = vendor;
+	vd->cb = NULL;
+	vd->data = NULL;
+
+	clear_dtmf_queue(vd);
+
+	ofono_voicecall_set_data(vc, vd);
+
+	/*
+	 * ofono_voicecall_register() needs to be called after
+	 * the driver has been set in ofono_voicecall_create(),
+	 * which calls this function.  Most other drivers make
+	 * some kind of capabilities query to the modem, and then
+	 * call register in the callback; we use an idle event instead.
+	 */
+	g_idle_add(ril_delayed_register, vc);
+}
+
+int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
+			void *data)
+{
+	struct ril_voicecall_driver_data *driver_data = data;
+	struct ril_voicecall_data *vd;
+
+	vd = g_try_new0(struct ril_voicecall_data, 1);
+	if (vd == NULL)
+		return -ENOMEM;
+
+	ril_voicecall_start(driver_data, vc, vendor, vd);
+
+	return 0;
+}
+
+void ril_voicecall_remove(struct ofono_voicecall *vc)
+{
+	struct ril_voicecall_data *vd = ofono_voicecall_get_data(vc);
+
+	if (vd->clcc_source)
+		g_source_remove(vd->clcc_source);
+
+	g_slist_foreach(vd->calls, (GFunc) g_free, NULL);
+	g_slist_free(vd->calls);
+
+	ofono_voicecall_set_data(vc, NULL);
+
+	g_ril_unref(vd->ril);
+	g_free(vd->tone_queue);
+	g_free(vd);
+}
+
+static struct ofono_voicecall_driver driver = {
+	.name			= RILMODEM,
+	.probe			= ril_voicecall_probe,
+	.remove			= ril_voicecall_remove,
+	.dial			= ril_dial,
+	.answer			= ril_answer,
+	.hangup_all		= ril_hangup_all,
+	.release_specific	= ril_hangup_specific,
+	.send_tones		= ril_send_dtmf,
+	.create_multiparty	= ril_create_multiparty,
+	.private_chat		= ril_private_chat,
+	.swap_without_accept	= ril_swap_without_accept,
+	.hold_all_active	= ril_hold_all_active,
+	.release_all_held	= ril_release_all_held,
+	.set_udub		= ril_set_udub,
+	.release_all_active	= ril_release_all_active,
+};
+
+void ril_voicecall_init(void)
+{
+	ofono_voicecall_driver_register(&driver);
+}
+
+void ril_voicecall_exit(void)
+{
+	ofono_voicecall_driver_unregister(&driver);
+}
diff --git a/drivers/rilmodem/voicecall.h b/drivers/rilmodem/voicecall.h
new file mode 100644
index 0000000..0407abe
--- /dev/null
+++ b/drivers/rilmodem/voicecall.h
@@ -0,0 +1,71 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2014  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+struct ril_voicecall_data {
+	GSList *calls;
+	/* Call local hangup indicator, one bit per call (1 << call_id) */
+	unsigned int local_release;
+	unsigned int clcc_source;
+	GRil *ril;
+	struct ofono_modem *modem;
+	unsigned int vendor;
+	unsigned char flags;
+	ofono_voicecall_cb_t cb;
+	void *data;
+	gchar *tone_queue;
+	gboolean tone_pending;
+};
+
+int ril_voicecall_probe(struct ofono_voicecall *vc, unsigned int vendor,
+			void *data);
+void ril_voicecall_remove(struct ofono_voicecall *vc);
+void ril_dial(struct ofono_voicecall *vc, const struct ofono_phone_number *ph,
+		enum ofono_clir_option clir, ofono_voicecall_cb_t cb,
+		void *data);
+void ril_answer(struct ofono_voicecall *vc,
+		ofono_voicecall_cb_t cb, void *data);
+void ril_hangup_all(struct ofono_voicecall *vc, ofono_voicecall_cb_t cb,
+			void *data);
+void ril_hangup_specific(struct ofono_voicecall *vc,
+				int id, ofono_voicecall_cb_t cb, void *data);
+void ril_send_dtmf(struct ofono_voicecall *vc, const char *dtmf,
+			ofono_voicecall_cb_t cb, void *data);
+void ril_create_multiparty(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data);
+void ril_private_chat(struct ofono_voicecall *vc, int id,
+			ofono_voicecall_cb_t cb, void *data);
+void ril_swap_without_accept(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data);
+void ril_hold_all_active(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data);
+void ril_release_all_held(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data);
+void ril_set_udub(struct ofono_voicecall *vc,
+			ofono_voicecall_cb_t cb, void *data);
+void ril_release_all_active(struct ofono_voicecall *vc,
+				ofono_voicecall_cb_t cb, void *data);
+
+void ril_voicecall_start(struct ril_voicecall_driver_data *driver_data,
+				struct ofono_voicecall *vc,
+				unsigned int vendor,
+				struct ril_voicecall_data *vd);
+void ril_call_state_notify(struct ril_msg *message, gpointer user_data);
+gboolean ril_poll_clcc(gpointer user_data);
-- 
2.1.4


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

* [PATCH 5/9] ril: Plugin for Android modems
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
                   ` (3 preceding siblings ...)
  2015-10-13 16:07 ` [PATCH 4/9] rilmodem: driver for Android modems Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 6/9] infineon: Definitions for infineon modem Alfonso Sanchez-Beato
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

From: Tony Espy <espy@canonical.com>

Plugin for Android modem, which uses the rilmodem driver.

Co-authored-by: Tony Espy <espy@canonical.com>
Co-authored-by: Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
Co-authored-by: Alfonso Sanchez-Beato <alfonso.sanchez-beato@canonical.com>
Co-authored-by: Islam Amer <islam.amer@jollamobile.com>
Co-authored-by: Jussi Kangas <jussi.kangas@tieto.com>
Co-authored-by: Juho Hämäläinen <juho.hamalainen@tieto.com>
Co-authored-by: Martti Piirainen <martti.piirainen@canonical.com>
Co-authored-by: Jarko Poutiainen <Jarko.Poutiainen@oss.tieto.com>
Co-authored-by: Tommi Kenakkala <tommi.kenakkala@oss.tieto.com>
Co-authored-by: Petri Takalokastari <petri.takalokastari@oss.tieto.com>
Co-authored-by: Miia Leinonen <miia.leinonen@oss.tieto.com>
Co-authored-by: Mikko Hurskainen <mikko.hurskainen@nomovok.com>
Co-authored-by: You-Sheng Yang <vicamo.yang@canonical.com>
---
 plugins/ril.c | 461 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 plugins/ril.h |  30 ++++
 2 files changed, 491 insertions(+)
 create mode 100644 plugins/ril.c
 create mode 100644 plugins/ril.h

diff --git a/plugins/ril.c b/plugins/ril.c
new file mode 100644
index 0000000..e27c98c
--- /dev/null
+++ b/plugins/ril.c
@@ -0,0 +1,461 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL-based devices
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012-2014 Canonical Ltd.
+ *  Copyright (C) 2013 Jolla Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.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/phonebook.h>
+#include <ofono/netreg.h>
+#include <ofono/voicecall.h>
+#include <ofono/sms.h>
+#include <ofono/cbs.h>
+#include <ofono/sim.h>
+#include <ofono/ussd.h>
+#include <ofono/call-forwarding.h>
+#include <ofono/call-settings.h>
+#include <ofono/call-barring.h>
+#include <ofono/call-meter.h>
+#include <ofono/call-volume.h>
+#include <ofono/radio-settings.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/audio-settings.h>
+#include <ofono/types.h>
+
+#include "ofono.h"
+
+#include <grilreply.h>
+#include <grilrequest.h>
+#include <grilunsol.h>
+
+#include "ril.h"
+#include "drivers/rilmodem/rilmodem.h"
+#include "drivers/rilmodem/vendor.h"
+
+#define MAX_SIM_STATUS_RETRIES 15
+
+/* this gives 30s for rild to initialize */
+#define RILD_MAX_CONNECT_RETRIES 5
+#define RILD_CONNECT_RETRY_TIME_S 5
+
+char *RILD_CMD_SOCKET[] = {"/dev/socket/rild", "/dev/socket/rild1"};
+char *GRIL_HEX_PREFIX[] = {"Device 0: ", "Device 1: "};
+
+struct ril_data {
+	GRil *ril;
+	enum ofono_ril_vendor vendor;
+	int sim_status_retries;
+	ofono_bool_t connected;
+	ofono_bool_t ofono_online;
+	int radio_state;
+	struct ofono_sim *sim;
+	struct ofono_radio_settings *radio_settings;
+	int rild_connect_retries;
+};
+
+static void ril_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	ofono_info("%s%s", prefix, str);
+}
+
+static void ril_radio_state_changed(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_modem *modem = user_data;
+	struct ril_data *rd = ofono_modem_get_data(modem);
+	int radio_state = g_ril_unsol_parse_radio_state_changed(rd->ril,
+								message);
+
+	if (radio_state != rd->radio_state) {
+
+		ofono_info("%s: state: %s rd->ofono_online: %d",
+				__func__,
+				ril_radio_state_to_string(radio_state),
+				rd->ofono_online);
+
+		rd->radio_state = radio_state;
+
+		switch (radio_state) {
+		case RADIO_STATE_ON:
+
+			if (rd->radio_settings == NULL) {
+				struct ril_radio_settings_driver_data
+						rs_data = { rd->ril, modem };
+
+				rd->radio_settings =
+					ofono_radio_settings_create(modem,
+							rd->vendor, RILMODEM,
+							&rs_data);
+			}
+
+			break;
+
+		case RADIO_STATE_UNAVAILABLE:
+		case RADIO_STATE_OFF:
+
+			/*
+			 * Unexpected radio state change, as we are supposed to
+			 * be online. UNAVAILABLE has been seen occassionally
+			 * when powering off the phone. We wait 5 secs to avoid
+			 * too fast re-spawns, then exit with error to make
+			 * upstart re-start ofono.
+			 */
+			if (rd->ofono_online) {
+				ofono_error("%s: radio self-powered off!",
+						__func__);
+				sleep(5);
+				exit(1);
+			}
+			break;
+		default:
+			/* Malformed parcel; no radio state == broken rild */
+			g_assert(FALSE);
+		}
+	}
+}
+
+int ril_create(struct ofono_modem *modem, enum ofono_ril_vendor vendor)
+{
+	ofono_bool_t lte_cap;
+	struct ril_data *rd = g_try_new0(struct ril_data, 1);
+	if (rd == NULL) {
+		errno = ENOMEM;
+		goto error;
+	}
+
+	DBG("");
+
+	rd->vendor = vendor;
+	rd->ofono_online = FALSE;
+	rd->radio_state = RADIO_STATE_OFF;
+
+	lte_cap = getenv("OFONO_RIL_RAT_LTE") ? TRUE : FALSE;
+	ofono_modem_set_boolean(modem, MODEM_PROP_LTE_CAPABLE, lte_cap);
+
+	ofono_modem_set_data(modem, rd);
+
+	return 0;
+
+error:
+	g_free(rd);
+
+	return -errno;
+}
+
+static int ril_probe(struct ofono_modem *modem)
+{
+	return ril_create(modem, OFONO_RIL_VENDOR_AOSP);
+}
+
+void ril_remove(struct ofono_modem *modem)
+{
+	struct ril_data *rd = ofono_modem_get_data(modem);
+
+	ofono_modem_set_data(modem, NULL);
+
+	if (!rd)
+		return;
+
+	g_ril_unref(rd->ril);
+
+	g_free(rd);
+}
+
+void ril_pre_sim(struct ofono_modem *modem)
+{
+	struct ril_data *rd = ofono_modem_get_data(modem);
+	struct ril_voicecall_driver_data vc_data = { rd->ril, modem };
+	struct ril_sim_data sim_data;
+
+	DBG("");
+
+	ofono_devinfo_create(modem, rd->vendor, RILMODEM, rd->ril);
+	ofono_voicecall_create(modem, rd->vendor, RILMODEM, &vc_data);
+	ofono_call_volume_create(modem, rd->vendor, RILMODEM, rd->ril);
+
+	sim_data.gril = rd->ril;
+	sim_data.modem = modem;
+	sim_data.ril_state_watch = NULL;
+
+	rd->sim = ofono_sim_create(modem, rd->vendor, RILMODEM, &sim_data);
+	g_assert(rd->sim != NULL);
+}
+
+void ril_post_sim(struct ofono_modem *modem)
+{
+	struct ril_data *rd = ofono_modem_get_data(modem);
+	struct ofono_gprs *gprs;
+	struct ofono_gprs_context *gc;
+	struct ofono_message_waiting *mw;
+	struct ril_gprs_driver_data gprs_data = { rd->ril, modem };
+	struct ril_gprs_context_data
+		inet_ctx = { rd->ril, modem, OFONO_GPRS_CONTEXT_TYPE_INTERNET };
+	struct ril_gprs_context_data
+		mms_ctx = { rd->ril, modem, OFONO_GPRS_CONTEXT_TYPE_MMS };
+
+	/* TODO: this function should setup:
+	 *  - phonebook
+	 *  - stk ( SIM toolkit )
+	 *  - radio_settings
+	 */
+	ofono_sms_create(modem, rd->vendor, RILMODEM, rd->ril);
+
+	gprs = ofono_gprs_create(modem, rd->vendor, RILMODEM, &gprs_data);
+	gc = ofono_gprs_context_create(modem, rd->vendor, RILMODEM, &inet_ctx);
+
+	if (gc) {
+		ofono_gprs_context_set_type(gc,
+					OFONO_GPRS_CONTEXT_TYPE_INTERNET);
+		ofono_gprs_add_context(gprs, gc);
+	}
+
+	gc = ofono_gprs_context_create(modem, rd->vendor, RILMODEM, &mms_ctx);
+
+	if (gc) {
+		ofono_gprs_context_set_type(gc,
+					OFONO_GPRS_CONTEXT_TYPE_MMS);
+		ofono_gprs_add_context(gprs, gc);
+	}
+
+	mw = ofono_message_waiting_create(modem);
+	if (mw)
+		ofono_message_waiting_register(mw);
+
+	ofono_call_forwarding_create(modem, rd->vendor, RILMODEM, rd->ril);
+
+	ofono_phonebook_create(modem, rd->vendor, RILMODEM, modem);
+}
+
+void ril_post_online(struct ofono_modem *modem)
+{
+	struct ril_data *rd = ofono_modem_get_data(modem);
+
+	ofono_netreg_create(modem, rd->vendor, RILMODEM, rd->ril);
+	ofono_ussd_create(modem, rd->vendor, RILMODEM, rd->ril);
+	ofono_call_settings_create(modem, rd->vendor, RILMODEM, rd->ril);
+	ofono_call_barring_create(modem, rd->vendor, RILMODEM, rd->ril);
+}
+
+static void ril_set_online_cb(struct ril_msg *message, gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	struct ril_data *rd = cbd->user;
+	ofono_modem_online_cb_t cb = cbd->cb;
+
+	if (message->error == RIL_E_SUCCESS) {
+		DBG("%s: set_online OK: rd->ofono_online: %d", __func__,
+			rd->ofono_online);
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	} else {
+		ofono_error("%s: set_online: %d failed", __func__,
+				rd->ofono_online);
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+}
+
+static void ril_send_power(struct ril_data *rd, ofono_bool_t online,
+				GRilResponseFunc func,
+				gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	ofono_modem_online_cb_t cb;
+	GDestroyNotify notify = NULL;
+	struct parcel rilp;
+
+	if (cbd != NULL) {
+		notify = g_free;
+		cb = cbd->cb;
+	}
+
+	DBG("(online = 1, offline = 0)): %i", online);
+
+	g_ril_request_power(rd->ril, (const gboolean) online, &rilp);
+
+	if (g_ril_send(rd->ril, RIL_REQUEST_RADIO_POWER, &rilp,
+			func, cbd, notify) == 0 && cbd != NULL) {
+
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+	}
+}
+
+void ril_set_online(struct ofono_modem *modem, ofono_bool_t online,
+			ofono_modem_online_cb_t callback, void *data)
+{
+	struct ril_data *rd = ofono_modem_get_data(modem);
+	struct cb_data *cbd = cb_data_new(callback, data, rd);
+
+	rd->ofono_online = online;
+
+	DBG("setting rd->ofono_online to: %d", online);
+
+	ril_send_power(rd, online, ril_set_online_cb, cbd);
+}
+
+static void ril_connected(struct ril_msg *message, gpointer user_data)
+{
+	struct ofono_modem *modem = (struct ofono_modem *) user_data;
+	struct ril_data *rd = ofono_modem_get_data(modem);
+
+	ofono_info("[%d,UNSOL]< %s", g_ril_get_slot(rd->ril),
+		g_ril_unsol_request_to_string(rd->ril, message->req));
+
+	/* TODO: need a disconnect function to restart things! */
+	rd->connected = TRUE;
+
+	DBG("calling set_powered(TRUE)");
+
+	ofono_modem_set_powered(modem, TRUE);
+}
+
+static int create_gril(struct ofono_modem *modem)
+{
+	struct ril_data *rd = ofono_modem_get_data(modem);
+	int slot_id = ofono_modem_get_integer(modem, "Slot");
+
+	ofono_info("Using %s as socket for slot %d.",
+					RILD_CMD_SOCKET[slot_id], slot_id);
+	rd->ril = g_ril_new(RILD_CMD_SOCKET[slot_id], OFONO_RIL_VENDOR_AOSP);
+
+	/* NOTE: Since AT modems open a tty, and then call
+	 * g_at_chat_new(), they're able to return -EIO if
+	 * the first fails, and -ENOMEM if the second fails.
+	 * in our case, we already return -EIO if the ril_new
+	 * fails.  If this is important, we can create a ril_socket
+	 * abstraction... ( probaby not a bad idea ).
+	 */
+
+	if (rd->ril == NULL) {
+		ofono_error("g_ril_new() failed to create modem!");
+		return -EIO;
+	}
+	g_ril_set_slot(rd->ril, slot_id);
+
+	if (getenv("OFONO_RIL_TRACE"))
+		g_ril_set_trace(rd->ril, TRUE);
+
+	if (getenv("OFONO_RIL_HEX_TRACE"))
+		g_ril_set_debugf(rd->ril, ril_debug, GRIL_HEX_PREFIX[slot_id]);
+
+	g_ril_register(rd->ril, RIL_UNSOL_RIL_CONNECTED,
+			ril_connected, modem);
+
+	g_ril_register(rd->ril, RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
+			ril_radio_state_changed, modem);
+
+	return 0;
+}
+
+static gboolean connect_rild(gpointer user_data)
+{
+	struct ofono_modem *modem = (struct ofono_modem *) user_data;
+	struct ril_data *rd = ofono_modem_get_data(modem);
+
+	ofono_info("Trying to reconnect to rild...");
+
+	if (rd->rild_connect_retries++ < RILD_MAX_CONNECT_RETRIES) {
+		if (create_gril(modem) < 0)
+			return TRUE;
+	} else {
+		ofono_error("Exiting, can't connect to rild.");
+		exit(0);
+	}
+
+	return FALSE;
+}
+
+int ril_enable(struct ofono_modem *modem)
+{
+	int ret;
+
+	DBG("");
+
+	ret = create_gril(modem);
+	if (ret < 0)
+		g_timeout_add_seconds(RILD_CONNECT_RETRY_TIME_S,
+					connect_rild, modem);
+
+	return -EINPROGRESS;
+}
+
+int ril_disable(struct ofono_modem *modem)
+{
+	struct ril_data *rd = ofono_modem_get_data(modem);
+
+	DBG("%p", modem);
+
+	ril_send_power(rd, FALSE, NULL, NULL);
+
+	return 0;
+}
+
+static struct ofono_modem_driver ril_driver = {
+	.name = "ril",
+	.probe = ril_probe,
+	.remove = ril_remove,
+	.enable = ril_enable,
+	.disable = ril_disable,
+	.pre_sim = ril_pre_sim,
+	.post_sim = ril_post_sim,
+	.post_online = ril_post_online,
+	.set_online = ril_set_online,
+};
+
+/*
+ * This plugin is a generic ( aka default ) device plugin for RIL-based devices.
+ * The plugin 'rildev' is used to determine which RIL plugin should be loaded
+ * based upon an environment variable.
+ */
+static int ril_init(void)
+{
+	int retval = ofono_modem_driver_register(&ril_driver);
+
+	if (retval != 0)
+		DBG("ofono_modem_driver_register returned: %d", retval);
+
+	return retval;
+}
+
+static void ril_exit(void)
+{
+	DBG("");
+	ofono_modem_driver_unregister(&ril_driver);
+}
+
+OFONO_PLUGIN_DEFINE(ril, "RIL modem driver", VERSION,
+			OFONO_PLUGIN_PRIORITY_DEFAULT, ril_init, ril_exit)
diff --git a/plugins/ril.h b/plugins/ril.h
new file mode 100644
index 0000000..3897222
--- /dev/null
+++ b/plugins/ril.h
@@ -0,0 +1,30 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL-based devices
+ *
+ *  Copyright (C) 2014  Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+int ril_create(struct ofono_modem *modem, enum ofono_ril_vendor vendor);
+void ril_remove(struct ofono_modem *modem);
+int ril_enable(struct ofono_modem *modem);
+int ril_disable(struct ofono_modem *modem);
+void ril_pre_sim(struct ofono_modem *modem);
+void ril_post_sim(struct ofono_modem *modem);
+void ril_post_online(struct ofono_modem *modem);
+void ril_set_online(struct ofono_modem *modem, ofono_bool_t online,
+			ofono_modem_online_cb_t callback, void *data);
-- 
2.1.4


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

* [PATCH 6/9] infineon: Definitions for infineon modem
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
                   ` (4 preceding siblings ...)
  2015-10-13 16:07 ` [PATCH 5/9] ril: Plugin " Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 7/9] infineon: Plugin for infineon modems Alfonso Sanchez-Beato
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

---
 drivers/infineonmodem/infineon_constants.h | 77 ++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 drivers/infineonmodem/infineon_constants.h

diff --git a/drivers/infineonmodem/infineon_constants.h b/drivers/infineonmodem/infineon_constants.h
new file mode 100644
index 0000000..b0ca7ed
--- /dev/null
+++ b/drivers/infineonmodem/infineon_constants.h
@@ -0,0 +1,77 @@
+/*
+ *
+ *  RIL constants for infineon modem
+ *
+ *  Copyright (C) 2014 Canonical Ltd.
+ *
+ *  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
+ *
+ */
+
+#ifndef INFINEON_CONSTANTS_H
+#define INFINEON_CONSTANTS_H
+
+/* Messages encapsulated in RIL_REQUEST_OEM_HOOK_RAW requests */
+#define INF_RIL_REQUEST_OEM_QUERY_SELECT_BAND 1
+#define INF_RIL_REQUEST_OEM_SET_SELECT_BAND 2
+#define INF_RIL_REQUEST_OEM_SET_CIRCUIT_SWITCHING_PAGING 3
+#define INF_RIL_REQUEST_OEM_GET_LAST_FAILURE_REPORT_FOR_CS_REGISTRATION 4
+#define INF_RIL_REQUEST_OEM_GET_SELECT_BEARER_SERVICE_TYPE 5
+#define INF_RIL_REQUEST_OEM_GET_XPROGRESS_STATUS 6
+#define INF_RIL_REQUEST_OEM_SET_SS_NOTIFY 7
+#define INF_RIL_REQUEST_OEM_GET_SS_NOTIFY 8
+#define INF_RIL_REQUEST_OEM_SET_AUTHENTICATION_TYPE 9
+#define INF_RIL_REQUEST_OEM_SWITCH_OFF_MS 10
+#define INF_RIL_REQUEST_OEM_SET_AUTO_TIMEZONE_UPDATE 11
+#define INF_RIL_REQUEST_OEM_SET_TIMEZONE_RESPORTING 12
+#define INF_RIL_REQUEST_OEM_SET_DISPLAY_SIM_AND_PB_STATUS 13
+#define INF_RIL_REQUEST_OEM_GET_REMAIN_SIM_PIN_ATTEMPTS 14
+#define INF_RIL_REQUEST_OEM_SET_AUTO_REDIAL 15
+#define INF_RIL_REQUEST_OEM_QUERY_CALL_STATUS_REPORTING 16
+#define INF_RIL_REQUEST_OEM_SET_AUTO_ANSWER 17
+#define INF_RIL_REQUEST_OEM_SET_LINE 18
+#define INF_RIL_REQUEST_OEM_PDP_ACTIVATE_OR_DEACTIVATE 19
+#define INF_RIL_REQUEST_OEM_QUERY_GPRS_MS_CLASS 20
+#define INF_RIL_REQUEST_OEM_SET_TRACE_AND_AT_INTERFACES 21
+#define INF_RIL_REQUEST_OEM_QUERY_TRACE_AND_AT_INTERFACES_CONFIGURE 22
+#define INF_RIL_REQUEST_OEM_SWITCH_TRACE_ON_OR_OFF 23
+#define INF_RIL_REQUEST_OEM_READ_EXCEPTION_LOG 24
+#define INF_RIL_REQUEST_OEM_GET_PHONE_ACTIVITY_STATUS 25
+#define INF_RIL_REQUEST_OEM_INITIATE_RESEND_SMS_IF_GPRS_FAILS 26
+#define INF_RIL_REQUEST_OEM_GET_DEVICE_NUMBER 27
+#define INF_RIL_REQUEST_OEM_ENABLE_STK 28
+#define INF_RIL_REQUEST_OEM_GET_SUBSCRIBER_NUMBER 29
+#define INF_RIL_REQUEST_OEM_SELECT_PHONE_BOOK  30
+#define INF_RIL_REQUEST_OEM_READ_PHONE_BOOK    31
+#define INF_RIL_REQUEST_OEM_INSERT_RECORD_TO_PHONE_BOOK 32
+#define INF_RIL_REQUEST_OEM_DELECT_RECORD_IN_PHONE_BOOK  33
+#define INF_RIL_REQUEST_OEM_GET_RECORD_FIELDS_MAX_LEN   34
+#define INF_RIL_REQUEST_OEM_SET_SERIAL_PORT 35
+#define INF_RIL_REQUEST_OEM_SET_DATA_PREFERED 36
+#define INF_RIL_REQUEST_OEM_SET_MODEM_ROUTING 37
+#define INF_RIL_REQUEST_OEM_CLEAR_MISS_NUMBER 38
+#define INF_RIL_REQUEST_OEM_ATH 39
+#define INF_RIL_REQUEST_OEM_NOSIG_MODE_TEST  40
+#define INF_RIL_REQUEST_OEM_SELECT_3G_BAND   41
+#define INF_RIL_REQUEST_OEM_QUERY_3G_BAND    42
+#define INF_RIL_REQUEST_OEM_HW_RESET_MODEM   43
+#define INF_RIL_REQUEST_OEM_QUERY_DIRECT     44
+#define INF_RIL_REQUEST_OEM_USER_PLMN_QUERY  45
+#define INF_RIL_REQUEST_OEM_USER_PLMN_SET    46
+#define INF_RIL_REQUEST_OEM_USER_PLMN_DELTE  47
+#define INF_RIL_REQUEST_OEM_SET_USB_LOG      48
+#define INF_RIL_REQUEST_OEM_UPDATE_CSQ       49
+#define INF_RIL_REQUEST_OEM_DUMP_CELL_ENV    50
+
+#endif /* INFINEON_CONSTANTS_H */
-- 
2.1.4


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

* [PATCH 7/9] infineon: Plugin for infineon modems
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
                   ` (5 preceding siblings ...)
  2015-10-13 16:07 ` [PATCH 6/9] infineon: Definitions for infineon modem Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 8/9] rildev: plugin that creates ril-type modems Alfonso Sanchez-Beato
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

Plugin for infineon modems, which is a variant of the ril modem.
---
 plugins/infineon.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 plugins/infineon.c

diff --git a/plugins/infineon.c b/plugins/infineon.c
new file mode 100644
index 0000000..a90aacc
--- /dev/null
+++ b/plugins/infineon.c
@@ -0,0 +1,77 @@
+/*
+ *
+ *  oFono - Open Source Telephony - RIL-based devices: infineon modems
+ *
+ *  Copyright (C) 2014  Canonical Ltd.
+ *
+ *  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 <ofono/log.h>
+#include <ofono/modem.h>
+
+#include "ofono.h"
+
+#include "drivers/rilmodem/vendor.h"
+#include "ril.h"
+
+static int inf_probe(struct ofono_modem *modem)
+{
+	return ril_create(modem, OFONO_RIL_VENDOR_INFINEON);
+}
+
+static struct ofono_modem_driver infineon_driver = {
+	.name = "infineon",
+	.probe = inf_probe,
+	.remove = ril_remove,
+	.enable = ril_enable,
+	.disable = ril_disable,
+	.pre_sim = ril_pre_sim,
+	.post_sim = ril_post_sim,
+	.post_online = ril_post_online,
+	.set_online = ril_set_online,
+};
+
+/*
+ * This plugin is a device plugin for infineon modems that use RIL interface.
+ * The plugin 'rildev' is used to determine which RIL plugin should be loaded
+ * based upon an environment variable.
+ */
+static int inf_init(void)
+{
+	int retval = 0;
+
+	retval = ofono_modem_driver_register(&infineon_driver);
+	if (retval != 0)
+		DBG("ofono_modem_driver_register returned: %d", retval);
+
+	return retval;
+}
+
+static void inf_exit(void)
+{
+	DBG("");
+	ofono_modem_driver_unregister(&infineon_driver);
+}
+
+OFONO_PLUGIN_DEFINE(infineon, "Infineon modem driver", VERSION,
+			OFONO_PLUGIN_PRIORITY_DEFAULT, inf_init, inf_exit)
-- 
2.1.4


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

* [PATCH 8/9] rildev: plugin that creates ril-type modems
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
                   ` (6 preceding siblings ...)
  2015-10-13 16:07 ` [PATCH 7/9] infineon: Plugin for infineon modems Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-13 16:07 ` [PATCH 9/9] build: Add rilmodem to the build Alfonso Sanchez-Beato
  2015-10-14 15:46 ` [PATCH 0/9] Rilmodem driver Denis Kenzior
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

This plugin creates modems that use the rilmodem driver by looking at
environment variables: when OFONO_RIL_DEVICE exists it creates a ril
modem of the sub-type specified by the variable. OFONO_RIL_NUM_SIM_SLOTS
specifies the number of SIM slots for multi-SIM modems.
---
 plugins/rildev.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)
 create mode 100644 plugins/rildev.c

diff --git a/plugins/rildev.c b/plugins/rildev.c
new file mode 100644
index 0000000..461324d
--- /dev/null
+++ b/plugins/rildev.c
@@ -0,0 +1,133 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2014 Canonical Ltd.
+ *
+ *  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 <ctype.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/modem.h>
+#include <ofono/log.h>
+
+static GSList *modem_list;
+
+static int create_rilmodem(const char *ril_type, int slot)
+{
+	struct ofono_modem *modem;
+	char dev_name[64];
+	int retval;
+
+	snprintf(dev_name, sizeof(dev_name), "ril_%d", slot);
+
+	modem = ofono_modem_create(dev_name, ril_type);
+	if (modem == NULL) {
+		DBG("ofono_modem_create failed for type %s", ril_type);
+		return -ENODEV;
+	}
+
+	modem_list = g_slist_prepend(modem_list, modem);
+
+	ofono_modem_set_integer(modem, "Slot", slot);
+
+	/* This causes driver->probe() to be called... */
+	retval = ofono_modem_register(modem);
+	if (retval != 0) {
+		ofono_error("%s: ofono_modem_register returned: %d",
+				__func__, retval);
+		return retval;
+	}
+
+	/*
+	 * kickstart the modem:
+	 * causes core modem code to call
+	 * - set_powered(TRUE) - which in turn
+	 *   calls driver->enable()
+	 *
+	 * - driver->pre_sim()
+	 *
+	 * Could also be done via:
+	 *
+	 * - a DBus call to SetProperties w/"Powered=TRUE" *1
+	 * - sim_state_watch ( handles SIM removal? LOCKED states? **2
+	 * - ofono_modem_set_powered()
+	 */
+	ofono_modem_reset(modem);
+
+	return 0;
+}
+
+static int detect_init(void)
+{
+	const char *ril_type;
+	const char *multi_sim;
+	int num_slots = 1;
+	int i;
+
+	ril_type = getenv("OFONO_RIL_DEVICE");
+	if (ril_type == NULL)
+		ril_type = "ril";
+
+	/* Check for multi-SIM support */
+	multi_sim = getenv("OFONO_RIL_NUM_SIM_SLOTS");
+	if (multi_sim != NULL && *multi_sim != '\0') {
+		int env_slots;
+		char *endp;
+
+		env_slots = (int) strtoul(multi_sim, &endp, 10);
+		if (*endp == '\0')
+			num_slots = env_slots;
+	}
+
+	ofono_info("RILDEV detected modem type %s, %d SIM slot(s)",
+			ril_type, num_slots);
+
+	for (i = 0; i < num_slots; ++i)
+		create_rilmodem(ril_type, i);
+
+	return 0;
+}
+
+static void detect_exit(void)
+{
+	GSList *list;
+
+	for (list = modem_list; list; list = list->next) {
+		struct ofono_modem *modem = list->data;
+
+		ofono_modem_remove(modem);
+	}
+
+	g_slist_free(modem_list);
+	modem_list = NULL;
+}
+
+OFONO_PLUGIN_DEFINE(rildev, "ril type detection", VERSION,
+		OFONO_PLUGIN_PRIORITY_DEFAULT, detect_init, detect_exit)
-- 
2.1.4


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

* [PATCH 9/9] build: Add rilmodem to the build
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
                   ` (7 preceding siblings ...)
  2015-10-13 16:07 ` [PATCH 8/9] rildev: plugin that creates ril-type modems Alfonso Sanchez-Beato
@ 2015-10-13 16:07 ` Alfonso Sanchez-Beato
  2015-10-14 15:46 ` [PATCH 0/9] Rilmodem driver Denis Kenzior
  9 siblings, 0 replies; 11+ messages in thread
From: Alfonso Sanchez-Beato @ 2015-10-13 16:07 UTC (permalink / raw)
  To: ofono

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

Build gril, the rilmodem and infineon drivers, and the corresponding
plugins.
---
 Makefile.am  | 44 +++++++++++++++++++++++++++++++++++++++++++-
 configure.ac |  5 +++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index 113a2d5..3ad1302 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -95,6 +95,15 @@ gisi_sources = gisi/client.c gisi/client.h gisi/common.h \
 				gisi/server.c gisi/server.h \
 				gisi/socket.c gisi/socket.h
 
+gril_sources = gril/gril.h gril/gril.c gril/grilio.h \
+				gril/grilio.c gril/grilutil.h \
+				gril/grilutil.c gril/ringbuffer.h \
+				gril/gfunc.h gril/ril.h \
+				gril/parcel.c gril/parcel.h \
+				gril/grilreply.c gril/grilreply.h \
+				gril/grilrequest.c gril/grilrequest.h \
+				gril/grilunsol.c gril/grilunsol.h
+
 btio_sources = btio/btio.h btio/btio.c
 
 if UDEV
@@ -107,6 +116,39 @@ builtin_modules += udevng
 builtin_sources += plugins/udevng.c
 endif
 
+if RILMODEM
+builtin_sources += $(gril_sources)
+
+builtin_modules += rildev
+builtin_sources += plugins/rildev.c
+
+builtin_modules += ril
+builtin_sources += plugins/ril.c
+
+builtin_modules += infineon
+builtin_sources += plugins/infineon.c
+
+builtin_modules += rilmodem
+builtin_sources += drivers/rilmodem/rilmodem.h \
+			drivers/rilmodem/vendor.h \
+			drivers/rilmodem/rilmodem.c \
+			drivers/rilmodem/devinfo.c \
+			drivers/rilmodem/network-registration.c \
+			drivers/rilmodem/voicecall.c \
+			drivers/rilmodem/call-volume.c \
+			drivers/rilmodem/gprs.c \
+			drivers/rilmodem/gprs-context.c \
+			drivers/rilmodem/sim.c \
+			drivers/rilmodem/sms.c \
+			drivers/rilmodem/rilutil.c \
+			drivers/rilmodem/rilutil.h \
+			drivers/rilmodem/ussd.c \
+			drivers/rilmodem/call-settings.c \
+			drivers/rilmodem/call-forwarding.c \
+			drivers/rilmodem/radio-settings.c \
+			drivers/rilmodem/call-barring.c
+endif
+
 if ISIMODEM
 builtin_modules += isimodem
 builtin_sources += $(gisi_sources) \
@@ -563,7 +605,7 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ $(builtin_cflags) \
 
 AM_CPPFLAGS = -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/src \
 			-I$(srcdir)/gdbus -I$(srcdir)/gisi -I$(srcdir)/gatchat \
-			-I$(srcdir)/btio
+			-I$(srcdir)/btio -I$(srcdir)/gril
 
 doc_files = doc/overview.txt doc/ofono-paper.txt doc/release-faq.txt \
 		doc/manager-api.txt doc/modem-api.txt doc/network-api.txt \
diff --git a/configure.ac b/configure.ac
index 130e8cf..b8d42c8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -161,6 +161,11 @@ AC_ARG_ENABLE(isimodem, AC_HELP_STRING([--disable-isimodem],
 					[enable_isimodem=${enableval}])
 AM_CONDITIONAL(ISIMODEM, test "${enable_isimodem}" != "no")
 
+AC_ARG_ENABLE(rilmodem, AC_HELP_STRING([--disable-rilmodem],
+				[disable RIL modem support]),
+					[enable_rilmodem=${enableval}])
+AM_CONDITIONAL(RILMODEM, test "${enable_rilmodem}" != "no")
+
 AC_ARG_ENABLE(qmimodem, AC_HELP_STRING([--disable-qmimodem],
 				[disable Qualcomm QMI modem support]),
 					[enable_qmimodem=${enableval}])
-- 
2.1.4


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

* Re: [PATCH 0/9] Rilmodem driver
  2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
                   ` (8 preceding siblings ...)
  2015-10-13 16:07 ` [PATCH 9/9] build: Add rilmodem to the build Alfonso Sanchez-Beato
@ 2015-10-14 15:46 ` Denis Kenzior
  9 siblings, 0 replies; 11+ messages in thread
From: Denis Kenzior @ 2015-10-14 15:46 UTC (permalink / raw)
  To: ofono

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

Hi Alfonso,

On 10/13/2015 11:07 AM, Alfonso Sanchez-Beato wrote:
> This patch series implements the rilmodem driver, which uses Android's
> radio interface layer (RIL, part of the Android HAL) to interact with
> the modem.
>
> The driver is almost feature-complete with some exceptions, being CBS
> and SAT the most prominent.
>
> Besides the driver, the patches include the following plugins:
> * ril.c: Plugin for Android modems
> * infineon.c: Plugin for infineon modems, which are a variant of the ril
>    modem
> * rildev: plugin that creates ril-type modems using environment
>    variables
>
> Finally, the patches contain some minor modifications of the core code
> to export a couple of enumerations used by the driver.
>
> The driver is used by Ubuntu for Phones and Sailfish and is quite stable
> at the moment.
>
> Alfonso Sanchez-Beato (5):
>    include: Add definitions for phone number types
>    infineon: Definitions for infineon modem
>    infineon: Plugin for infineon modems
>    rildev: plugin that creates ril-type modems
>    build: Add rilmodem to the build
>
> Tony Espy (4):
>    src: make bearer/operator enums public
>    gril: Library to communicate with rild
>    rilmodem: driver for Android modems
>    ril: Plugin for Android modems
>

All applied, now lets start cleaning it up :)

Regards,
-Denis


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

end of thread, other threads:[~2015-10-14 15:46 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-13 16:07 [PATCH 0/9] Rilmodem driver Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 1/9] src: make bearer/operator enums public Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 2/9] include: Add definitions for phone number types Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 3/9] gril: Library to communicate with rild Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 4/9] rilmodem: driver for Android modems Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 5/9] ril: Plugin " Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 6/9] infineon: Definitions for infineon modem Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 7/9] infineon: Plugin for infineon modems Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 8/9] rildev: plugin that creates ril-type modems Alfonso Sanchez-Beato
2015-10-13 16:07 ` [PATCH 9/9] build: Add rilmodem to the build Alfonso Sanchez-Beato
2015-10-14 15:46 ` [PATCH 0/9] Rilmodem driver Denis Kenzior

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.