All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5
@ 2010-12-08  8:34 Jessica Nilsson
  2010-12-08  9:30 ` Marcel Holtmann
  2010-12-09  6:26 ` Aki Niemi
  0 siblings, 2 replies; 8+ messages in thread
From: Jessica Nilsson @ 2010-12-08  8:34 UTC (permalink / raw)
  To: ofono

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

Updates in Makefile.am - adding of isimodem2.5
Adding of drivers/isimodem2.5/ files to fully listed functionality.

Regards,
Jessica Nilsson

---
 Makefile.am                                |   36 +-
 drivers/isimodem2.5/call-barring.c         |  503 ++
 drivers/isimodem2.5/call-forwarding.c      |  613 +++
 drivers/isimodem2.5/call-settings.c        | 1093 +++++
 drivers/isimodem2.5/call.h                 |  237 +
 drivers/isimodem2.5/cbs.c                  |  433 ++
 drivers/isimodem2.5/checkpatch.pl          | 2789 ++++++++++++
 drivers/isimodem2.5/debug.c                |  694 +++
 drivers/isimodem2.5/debug.h                |   66 +
 drivers/isimodem2.5/devinfo.c              |  246 +
 drivers/isimodem2.5/gpds-context.c         |  788 ++++
 drivers/isimodem2.5/gpds.c                 |  395 ++
 drivers/isimodem2.5/gpds.h                 |  295 ++
 drivers/isimodem2.5/gss.h                  |   84 +
 drivers/isimodem2.5/info.h                 |   53 +
 drivers/isimodem2.5/isimodem.c             |  534 +++
 drivers/isimodem2.5/isimodem.h             |   69 +
 drivers/isimodem2.5/isiutil.h              |   64 +
 drivers/isimodem2.5/mce.h                  |   65 +
 drivers/isimodem2.5/network-registration.c | 1158 +++++
 drivers/isimodem2.5/network.h              |  257 ++
 drivers/isimodem2.5/phonebook.c            | 1320 ++++++
 drivers/isimodem2.5/radio-settings.c       |  313 ++
 drivers/isimodem2.5/simu_resps.h           | 6800 ++++++++++++++++++++++++++++
 drivers/isimodem2.5/sms.c                  |  869 ++++
 drivers/isimodem2.5/sms.h                  |  188 +
 drivers/isimodem2.5/ss.h                   |  174 +
 drivers/isimodem2.5/ssn.c                  |  456 ++
 drivers/isimodem2.5/timeout.h              |   33 +
 drivers/isimodem2.5/uicc.c                 | 3316 ++++++++++++++
 drivers/isimodem2.5/uicc.h                 |  253 ++
 drivers/isimodem2.5/uicc_interface.h       |   40 +
 drivers/isimodem2.5/ussd.c                 |  341 ++
 drivers/isimodem2.5/voicecall.c            | 1555 +++++++
 34 files changed, 26128 insertions(+), 2 deletions(-)
 create mode 100644 drivers/isimodem2.5/call-barring.c
 create mode 100644 drivers/isimodem2.5/call-forwarding.c
 create mode 100644 drivers/isimodem2.5/call-settings.c
 create mode 100644 drivers/isimodem2.5/call.h
 create mode 100644 drivers/isimodem2.5/cbs.c
 create mode 100755 drivers/isimodem2.5/checkpatch.pl
 create mode 100644 drivers/isimodem2.5/debug.c
 create mode 100644 drivers/isimodem2.5/debug.h
 create mode 100644 drivers/isimodem2.5/devinfo.c
 create mode 100644 drivers/isimodem2.5/gpds-context.c
 create mode 100644 drivers/isimodem2.5/gpds.c
 create mode 100644 drivers/isimodem2.5/gpds.h
 create mode 100644 drivers/isimodem2.5/gss.h
 create mode 100644 drivers/isimodem2.5/info.h
 create mode 100644 drivers/isimodem2.5/isimodem.c
 create mode 100644 drivers/isimodem2.5/isimodem.h
 create mode 100644 drivers/isimodem2.5/isiutil.h
 create mode 100644 drivers/isimodem2.5/mce.h
 create mode 100644 drivers/isimodem2.5/network-registration.c
 create mode 100644 drivers/isimodem2.5/network.h
 create mode 100644 drivers/isimodem2.5/phonebook.c
 create mode 100644 drivers/isimodem2.5/radio-settings.c
 create mode 100644 drivers/isimodem2.5/simu_resps.h
 create mode 100644 drivers/isimodem2.5/sms.c
 create mode 100644 drivers/isimodem2.5/sms.h
 create mode 100644 drivers/isimodem2.5/ss.h
 create mode 100644 drivers/isimodem2.5/ssn.c
 create mode 100644 drivers/isimodem2.5/timeout.h
 create mode 100644 drivers/isimodem2.5/uicc.c
 create mode 100644 drivers/isimodem2.5/uicc.h
 create mode 100644 drivers/isimodem2.5/uicc_interface.h
 create mode 100644 drivers/isimodem2.5/ussd.c
 create mode 100644 drivers/isimodem2.5/voicecall.c

diff --git a/Makefile.am b/Makefile.am
index caf3306..a5c89f2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -289,9 +289,41 @@ builtin_sources += plugins/caif.c
 endif
 
 if ISIMODEM25
+builtin_modules += isimodem25
 builtin_sources += $(gisi_sources) \
 		gisi/pipe_wg25.h \
-		gisi/pipe_wg25.c
+		gisi/pipe_wg25.c \
+		drivers/isimodem2.5/debug.h \
+		drivers/isimodem2.5/debug.c \
+		drivers/isimodem2.5/isimodem.h \
+		drivers/isimodem2.5/isimodem.c \
+		drivers/isimodem2.5/mce.h \
+		drivers/isimodem2.5/timeout.h \
+		drivers/isimodem2.5/network-registration.c \
+		drivers/isimodem2.5/network.h \
+		drivers/isimodem2.5/call.h \
+		drivers/isimodem2.5/simu_resps.h \
+		drivers/isimodem2.5/voicecall.c \
+		drivers/isimodem2.5/gpds.h \
+		drivers/isimodem2.5/gpds.c \
+		drivers/isimodem2.5/gpds-context.c \
+		drivers/isimodem2.5/devinfo.c \
+		drivers/isimodem2.5/info.h \
+		drivers/isimodem2.5/uicc.h \
+		drivers/isimodem2.5/uicc_interface.h \
+		drivers/isimodem2.5/uicc.c \
+		drivers/isimodem2.5/sms.h \
+		drivers/isimodem2.5/sms.c \
+		drivers/isimodem2.5/call-barring.c \
+		drivers/isimodem2.5/call-settings.c \
+		drivers/isimodem2.5/call-forwarding.c \
+		drivers/isimodem2.5/ssn.c \
+		drivers/isimodem2.5/ss.h \
+		drivers/isimodem2.5/gss.h \
+		drivers/isimodem2.5/radio-settings.c \
+		drivers/isimodem2.5/ussd.c \
+		drivers/isimodem2.5/phonebook.c\
+		drivers/isimodem2.5/cbs.c
 endif
 
 if MAINTAINER_MODE
@@ -484,7 +516,7 @@ unit_objects += $(unit_test_mux_OBJECTS)
 
 unit_test_caif_SOURCES = unit/test-caif.c $(gatchat_sources) \
 					drivers/stemodem/caif_socket.h \
-					drivers/stemodem/if_caif.h 
+					drivers/stemodem/if_caif.h
 unit_test_caif_LDADD = @GLIB_LIBS@
 unit_objects += $(unit_test_caif_OBJECTS)
 
diff --git a/drivers/isimodem2.5/call-barring.c b/drivers/isimodem2.5/call-barring.c
new file mode 100644
index 0000000..da1cd4b
--- /dev/null
+++ b/drivers/isimodem2.5/call-barring.c
@@ -0,0 +1,503 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-barring.h>
+
+#include <glib.h>
+
+
+#include "common.h"
+#include "debug.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "ss.h"
+#include "util.h"
+
+struct barr_data {
+	GIsiClient *client;
+};
+
+static int lock_code_to_mmi(char const *lock)
+{
+	if (strcmp(lock, "AO") == 0)
+		return SS_GSM_BARR_ALL_OUT;
+	else if (strcmp(lock, "OI") == 0)
+		return SS_GSM_BARR_OUT_INTER;
+	else if (strcmp(lock, "OX") == 0)
+		return SS_GSM_BARR_OUT_INTER_EXC_HOME;
+	else if (strcmp(lock, "AI") == 0)
+		return SS_GSM_BARR_ALL_IN;
+	else if (strcmp(lock, "IR") == 0)
+		return SS_GSM_BARR_ALL_IN_ROAM;
+	else if (strcmp(lock, "AB") == 0)
+		return SS_GSM_ALL_BARRINGS;
+	else if (strcmp(lock, "AG") == 0)
+		return SS_GSM_OUTGOING_BARR_SERV;
+	else if (strcmp(lock, "AC") == 0)
+		return SS_GSM_INCOMING_BARR_SERV;
+	else
+		return 0;
+}
+
+static void update_status_mask(guint32 *mask, int bsc)
+{
+	switch (bsc) {
+	case SS_GSM_TELEPHONY:
+		*mask |= 1;
+		break;
+	case SS_GSM_ALL_DATA_TELE:
+		*mask |= 1 << 1;
+		break;
+	case SS_GSM_FACSIMILE:
+		*mask |= 1 << 2;
+		break;
+	case SS_GSM_SMS:
+		*mask |= 1 << 3;
+		break;
+	case SS_GSM_ALL_DATA_CIRCUIT_SYNC:
+		*mask |= 1 << 4;
+		break;
+	case SS_GSM_ALL_DATA_CIRCUIT_ASYNC:
+		*mask |= 1 << 5;
+		break;
+	case SS_GSM_ALL_DATA_PACKET_SYNC:
+		*mask |= 1 << 6;
+		break;
+	case SS_GSM_ALL_PAD_ACCESS:
+		*mask |= 1 << 7;
+		break;
+	default:
+		DBG("Unknown BSC: 0x%04X\n", bsc);
+		break;
+	}
+}
+
+static gboolean decode_gsm_barring_info(const void *restrict data, size_t len,
+					guint32 *mask)
+{
+	GIsiSubBlockIter iter;
+
+	for (g_isi_sb_iter_init(&iter, data, len, 0);
+			g_isi_sb_iter_is_valid(&iter);
+			g_isi_sb_iter_next(&iter)) {
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_GSM_BARRING_FEATURE: {
+			uint8_t status;
+			uint8_t bsc;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &bsc, 2)
+				|| !g_isi_sb_iter_get_byte(&iter, &status, 3))
+				return FALSE;
+
+			if (status & SS_GSM_ACTIVE)
+				update_status_mask(mask, bsc);
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean bearer_class_to_bsc(enum bearer_class cls, guint8 *bsc)
+{
+	switch (cls) {
+	case BEARER_CLASS_VOICE:
+		*bsc = SS_GSM_VOICE_GROUP;
+		return TRUE;
+	case BEARER_CLASS_DATA:
+		*bsc = SS_GSM_ALL_DATA_TELE;
+		return TRUE;
+	case BEARER_CLASS_FAX:
+		*bsc = SS_GSM_FACSIMILE;
+		return TRUE;
+	case BEARER_CLASS_DEFAULT:
+		*bsc = SS_GSM_TELEPHONY;
+		return TRUE;
+	case BEARER_CLASS_SMS:
+		*bsc = SS_GSM_SMS;
+		return TRUE;
+	case BEARER_CLASS_DATA_SYNC:
+		*bsc = SS_GSM_ALL_DATA_CIRCUIT_SYNC;
+		return TRUE;
+	case BEARER_CLASS_DATA_ASYNC:
+		*bsc = SS_GSM_ALL_DATA_CIRCUIT_ASYNC;
+		return TRUE;
+	case BEARER_CLASS_SS_DEFAULT:
+		return FALSE;
+	case BEARER_CLASS_PACKET:
+		*bsc = SS_GSM_ALL_DATA_PACKET_SYNC;
+		return TRUE;
+	case BEARER_CLASS_PAD:
+		*bsc = SS_GSM_ALL_PAD_ACCESS;
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean set_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_barring_set_cb_t cb = cbd->cb;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 3 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	if (msg[1] != SS_ACTIVATION && msg[1] != SS_DEACTIVATION)
+		goto error;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+
+static void isi_set(struct ofono_call_barring *barr, const char *lock,
+			int enable, const char *passwd, int cls,
+			ofono_call_barring_set_cb_t cb, void *data)
+{
+	struct barr_data *bd = ofono_call_barring_get_data(barr);
+	struct isi_cb_data *cbd = isi_cb_data_new(barr, cb, data);
+	int ss_code = lock_code_to_mmi(lock);
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		enable ? SS_ACTIVATION : SS_DEACTIVATION,
+		SS_ALL_TELE_AND_BEARER,
+		ss_code >> 8, ss_code & 0xFF,	/* Service code */
+		SS_SEND_ADDITIONAL_INFO,
+		1,				/* Subblock count */
+		SS_GSM_PASSWORD,
+		28,				/* Subblock length */
+		0, passwd[0], 0, passwd[1],
+		0, passwd[2], 0, passwd[3],
+		0, 0, 0, 0, 0, 0, 0, 0,		/* Filler */
+		0, 0, 0, 0, 0, 0, 0, 0,		/* Filler */
+		0, 0				/* Filler */
+	};
+	DBG("lock code %s enable %d class %d password %s, service code %04x\n",
+	    lock, enable, cls, passwd, ss_code);
+
+	if (cbd && g_isi_request_make(bd->client, msg, sizeof(msg), SS_TIMEOUT,
+				      set_resp_cb, cbd))
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static gboolean query_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_barring_query_cb_t cb = cbd->cb;
+	guint32 mask = 0;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	if (msg[1] != SS_INTERROGATION)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+			g_isi_sb_iter_is_valid(&iter);
+			g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+
+			if (ss_status & SS_GSM_ACTIVE)
+				mask = 1;
+
+			break;
+		}
+		case SS_GSM_BARRING_INFO: {
+			void *info = NULL;
+			size_t infolen;
+
+			if (!g_isi_sb_iter_get_data(&iter, &info, 4))
+				goto error;
+
+			infolen = g_isi_sb_iter_get_len(&iter) - 4;
+
+			if (!decode_gsm_barring_info(info, infolen, &mask))
+				goto error;
+
+			break;
+		}
+		case SS_GSM_BSC_INFO: {
+			guint8 bsc;
+			guint8 count;
+			guint8 i;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &count, 2))
+				goto error;
+
+			for (i = 0; i < count; i++) {
+				if (!g_isi_sb_iter_get_byte(&iter, &bsc, 3 + i))
+					goto error;
+
+				update_status_mask(&mask, bsc);
+			}
+
+			break;
+		}
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		default:
+			DBG("Skipping sub-block: %d (%zd bytes)",
+				(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	DBG("mask=0x%04X\n", mask);
+	CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_query(struct ofono_call_barring *barr, const char *lock,
+			int cls, ofono_call_barring_query_cb_t cb, void *data)
+{
+	struct barr_data *bd = ofono_call_barring_get_data(barr);
+	struct isi_cb_data *cbd = isi_cb_data_new(barr, cb, data);
+	int ss_code = lock_code_to_mmi(lock);
+	guint8 bsc;
+
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_INTERROGATION,
+		SS_ALL_TELE_AND_BEARER,
+		ss_code >> 8, ss_code & 0xFF,	/* services code */
+		SS_SEND_ADDITIONAL_INFO,	/* Get BER-encoded result */
+		0				/* Subblock count */
+	};
+	(void) bearer_class_to_bsc(cls, &bsc);
+	DBG("barring class %d type %s\n", cls, lock);
+
+	if (cbd && g_isi_request_make(bd->client, msg, sizeof(msg), SS_TIMEOUT,
+					query_resp_cb, cbd))
+		return;
+}
+
+static gboolean set_passwd_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_barring_set_cb_t cb = cbd->cb;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 3 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	if (msg[1] != SS_GSM_PASSWORD_REGISTRATION)
+		goto error;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 barr_data *bd = ofono_call_barring_get_data(barr);
+	struct isi_cb_data *cbd = isi_cb_data_new(barr, cb, data);
+	int ss_code = lock_code_to_mmi(lock);
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_GSM_PASSWORD_REGISTRATION,
+		SS_ALL_TELE_AND_BEARER,
+		ss_code >> 8, ss_code & 0xFF,	/* Service code */
+		SS_SEND_ADDITIONAL_INFO,
+		1,				/* Subblock count */
+		SS_GSM_PASSWORD,
+		28,				/* Subblock length */
+		0, old_passwd[0], 0, old_passwd[1],
+		0, old_passwd[2], 0, old_passwd[3],
+		0, new_passwd[0], 0, new_passwd[1],
+		0, new_passwd[2], 0, new_passwd[3],
+		0, new_passwd[0], 0, new_passwd[1],
+		0, new_passwd[2], 0, new_passwd[3],
+		0, 0				/* Filler */
+	};
+	DBG("lock code %s (%u) old password %s new password %s\n",
+		lock, ss_code, old_passwd, new_passwd);
+
+	if (cbd &&
+		g_isi_request_make(bd->client, msg, sizeof(msg), SS_TIMEOUT,
+				set_passwd_resp_cb, cbd))
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+/*========COMMON starts===============================*/
+static gboolean isi_call_barring_register(gpointer user)
+{
+	struct ofono_call_barring *cb = user;
+	ofono_call_barring_register(cb);
+	return FALSE;
+}
+
+static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
+				void *opaque)
+{
+	struct ofono_call_barring *barr = opaque;
+
+	if (!alive) {
+		DBG("Unable to bootstrap call barring driver");
+		return;
+	}
+
+	DBG("%s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_idle_add(isi_call_barring_register, barr);
+}
+
+
+static int isi_call_barring_probe(struct ofono_call_barring *barr,
+					unsigned int vendor, void *user)
+{
+	GIsiModem *idx = user;
+	struct barr_data *data = g_try_new0(struct barr_data, 1);
+
+	if (!data)
+		return -ENOMEM;
+
+	data->client = get_pn_ss_client(idx, PN_SS);
+
+	if (!data->client)
+		return -ENOMEM;
+
+	ofono_call_barring_set_data(barr, data);
+
+	if (!g_isi_verify(data->client, reachable_cb, barr))
+		DBG("Unable to verify reachability");
+
+	return 0;
+}
+
+static void isi_call_barring_remove(struct ofono_call_barring *barr)
+{
+	struct barr_data *data = ofono_call_barring_get_data(barr);
+
+	if (!data)
+		return;
+
+	ofono_call_barring_set_data(barr, NULL);
+	pn_ss_client_destroy(data->client);
+	g_free(data);
+}
+
+static struct ofono_call_barring_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_call_barring_probe,
+	.remove			= isi_call_barring_remove,
+	.set			= isi_set,
+	.query			= isi_query,
+	.set_passwd		= isi_set_passwd
+};
+
+void isi_call_barring_init()
+{
+	ofono_call_barring_driver_register(&driver);
+}
+
+void isi_call_barring_exit()
+{
+	ofono_call_barring_driver_unregister(&driver);
+}
+/*========COMMON ends===============================*/
diff --git a/drivers/isimodem2.5/call-forwarding.c b/drivers/isimodem2.5/call-forwarding.c
new file mode 100644
index 0000000..f712488
--- /dev/null
+++ b/drivers/isimodem2.5/call-forwarding.c
@@ -0,0 +1,613 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-forwarding.h>
+
+#include <glib.h>
+
+#include "debug.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "ss.h"
+
+struct forw_data {
+	GIsiClient *client;
+};
+
+static int forw_type_to_isi_code(int type)
+{
+	int ss_code;
+
+	switch (type) {
+	case 0:
+		ss_code = SS_GSM_FORW_UNCONDITIONAL;
+		break;
+	case 1:
+		ss_code = SS_GSM_FORW_BUSY;
+		break;
+	case 2:
+		ss_code = SS_GSM_FORW_NO_REPLY;
+		break;
+	case 3:
+		ss_code = SS_GSM_FORW_NO_REACH;
+		break;
+	case 4:
+		ss_code = SS_GSM_ALL_FORWARDINGS;
+		break;
+	case 5:
+		ss_code = SS_GSM_ALL_COND_FORWARDINGS;
+		break;
+	default:
+		DBG("Unknown forwarding type %d\n", type);
+		ss_code = -1;
+		break;
+	}
+
+	return ss_code;
+}
+
+static gboolean decode_gsm_forwarding_info(const void *restrict data,
+						size_t len, uint8_t *status,
+						uint8_t *ton, uint8_t *norply,
+						char **number)
+{
+	GIsiSubBlockIter iter;
+
+	for (g_isi_sb_iter_init(&iter, data, len, 0);
+			g_isi_sb_iter_is_valid(&iter);
+			g_isi_sb_iter_next(&iter)) {
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_GSM_FORWARDING_FEATURE: {
+			uint8_t _numlen;
+			uint8_t _status;
+			uint8_t _norply;
+			uint8_t _ton;
+			char *_number = NULL;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &_status, 3)
+				|| !g_isi_sb_iter_get_byte(&iter, &_ton, 4)
+				|| !g_isi_sb_iter_get_byte(&iter, &_norply, 5)
+				|| !g_isi_sb_iter_get_byte(&iter, &_numlen, 7))
+					return FALSE;
+
+			g_isi_sb_iter_get_alpha_tag(&iter,
+						    &_number,
+						    _numlen * 2, /*can be zero*/
+						    10);
+
+			if (status)
+				*status = _status;
+
+			if (ton)
+				*ton = _ton;
+
+			if (norply)
+				*norply = _norply;
+
+			if (number)
+				*number = _number;
+			else
+				g_free(_number);
+
+			return TRUE;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	return FALSE;
+}
+
+static gboolean registration_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_forwarding_set_cb_t cb = cbd->cb;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	if (msg[1] != SS_REGISTRATION)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+			g_isi_sb_iter_is_valid(&iter);
+			g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		case SS_GSM_FORWARDING_INFO: {
+			guint8 status;
+			void *info = NULL;
+			size_t infolen;
+
+			if (!g_isi_sb_iter_get_data(&iter, &info, 4))
+				goto error;
+
+			infolen = g_isi_sb_iter_get_len(&iter) - 4;
+
+			if (!decode_gsm_forwarding_info(info, infolen, &status,
+							NULL, NULL, NULL))
+				goto error;
+
+			if (!(status & SS_GSM_ACTIVE)
+					|| !(status & SS_GSM_REGISTERED))
+				goto error;
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 forw_data *fd = ofono_call_forwarding_get_data(cf);
+	struct isi_cb_data *cbd = isi_cb_data_new(cf, cb, data);
+	int ss_code;
+	int num_filler;
+	char *ucs2 = NULL;
+
+	if (!number)
+		goto error;
+	else {
+
+		unsigned char msg[100] = {
+			SS_SERVICE_REQ,
+			SS_REGISTRATION,
+			SS_GSM_TELEPHONY,
+			0, 0,	/* Supplementary services code */
+			SS_SEND_ADDITIONAL_INFO,
+			1,	/* Subblock count */
+			SS_FORWARDING,
+			0,	/* Variable subblock length (phone number) */
+			number->type,
+			SS_UNDEFINED_TIME,
+			strlen(number->number),
+			0	/* Sub address length */
+		};
+		/*
+		 * Followed by number in UCS-2, zero sub address bytes, and 0
+		 * to 3 bytes of filler
+		 */
+		DBG("SS_REGISTRATION forwarding type=%d class=%d nbr_type=%d,\
+				time=%d len=%d num=%s",
+				type, cls, number->type,
+				time, (int) strlen(number->number),
+				number->number);
+
+		if (!cbd || !number || strlen(number->number) > 28)
+			goto error;
+
+		ss_code = forw_type_to_isi_code(type);
+
+		if (ss_code < 0)
+			goto error;
+
+		msg[3] = ss_code >> 8;
+		msg[4] = ss_code & 0xFF;
+
+		/* Time must not be set for any other than NoReply */
+		if (ss_code == SS_GSM_FORW_NO_REPLY)
+			msg[10] = time;
+
+		num_filler = (6 + 2 * strlen(number->number)) % 4;
+
+		if (num_filler != 0)
+			num_filler = 4 - num_filler;
+
+		msg[8]  = 6 + 2 * strlen(number->number) + num_filler;
+		ucs2 = g_convert(number->number, strlen(number->number),
+				"UCS-2BE",
+				"UTF-8//TRANSLIT", NULL, NULL, NULL);
+
+		if (ucs2 == NULL)
+			goto error;
+
+		memmove((char *) msg + 13, ucs2, strlen(number->number) * 2);
+		g_free(ucs2);
+
+		if (g_isi_request_make(fd->client, msg, 7 + msg[8], SS_TIMEOUT,
+					registration_resp_cb, cbd))
+			return;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static gboolean erasure_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_forwarding_set_cb_t cb = cbd->cb;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	if (msg[1] != SS_ERASURE)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+			g_isi_sb_iter_is_valid(&iter);
+			g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_GSM_FORWARDING_INFO: {
+			guint8 status;
+			void *info = NULL;
+			size_t infolen;
+
+			if (!g_isi_sb_iter_get_data(&iter, &info, 4))
+				goto error;
+
+			infolen = g_isi_sb_iter_get_len(&iter) - 4;
+
+			if (!decode_gsm_forwarding_info(info, infolen, &status,
+							NULL, NULL, NULL)) {
+				DBG("SS_GSM_FORWARDING_INFO \
+				info=%p, len=%d, decoded status=%d",
+					info, (int) infolen, status);
+				goto error;
+			}
+
+			if (status & (SS_GSM_ACTIVE | SS_GSM_REGISTERED))
+				goto error;
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+
+static void isi_erasure(struct ofono_call_forwarding *cf, int type, int cls,
+			ofono_call_forwarding_set_cb_t cb, void *data)
+{
+	struct forw_data *fd = ofono_call_forwarding_get_data(cf);
+	struct isi_cb_data *cbd = isi_cb_data_new(cf, cb, data);
+	int ss_code;
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_ERASURE,
+		SS_GSM_TELEPHONY,
+		0, 0,	/* Supplementary services code */
+		SS_SEND_ADDITIONAL_INFO,
+		0	/* Subblock count */
+	};
+	DBG("forwarding type %d class %d\n", type, cls);
+
+	if (!cbd)
+		goto error;
+
+	ss_code = forw_type_to_isi_code(type);
+
+	if (ss_code < 0)
+		goto error;
+
+	msg[3] = ss_code >> 8;
+	msg[4] = ss_code & 0xFF;
+
+	if (g_isi_request_make(fd->client, msg, sizeof(msg), SS_TIMEOUT,
+				erasure_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static gboolean query_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_forwarding_query_cb_t cb = cbd->cb;
+	struct ofono_call_forwarding_condition list;
+	list.status = 0;
+	list.cls = 7;
+	list.time = 0;
+	list.phone_number.number[0] = 0;
+	list.phone_number.type = 0;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	if (msg[1] != SS_INTERROGATION)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+			g_isi_sb_iter_is_valid(&iter);
+			g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+			list.status = ss_status & (SS_GSM_ACTIVE
+							| SS_GSM_REGISTERED
+							| SS_GSM_PROVISIONED);
+			/* No other info in SS_RESULT */
+			break;
+		}
+		case SS_GSM_FORWARDING_INFO: {
+			guint8 status;
+			void *info = NULL;
+			size_t infolen;
+			guint8 ton;
+			guint8 norply;
+			char *number = NULL;
+
+			if (!g_isi_sb_iter_get_data(&iter, &info, 4))
+				goto error;
+
+			infolen = g_isi_sb_iter_get_len(&iter) - 4;
+
+			if (!decode_gsm_forwarding_info(info, infolen, &status,
+							&ton, &norply, &number))
+				goto error;
+
+			list.status = status & (SS_GSM_ACTIVE
+							| SS_GSM_REGISTERED
+							| SS_GSM_PROVISIONED);
+			list.time = norply;
+			list.phone_number.type = ton | 128;
+			list.phone_number.number[0] = '\0';
+
+			if (number) {
+				strncpy(list.phone_number.number, number,
+					OFONO_MAX_PHONE_NUMBER_LENGTH);
+				list.phone_number.number[
+					OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
+			}
+
+			g_free(number);
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	DBG("forwarding query: status=%d, class=%d, number=%s(%d) - %d sec",
+		list.status, list.cls,
+		list.phone_number.number,
+		list.phone_number.type, list.time);
+	CALLBACK_WITH_SUCCESS(cb, 1, &list, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+
+static void isi_query(struct ofono_call_forwarding *cf, int type, int cls,
+			ofono_call_forwarding_query_cb_t cb,
+			void *data)
+{
+	struct forw_data *fd = ofono_call_forwarding_get_data(cf);
+	struct isi_cb_data *cbd = isi_cb_data_new(cf, cb, data);
+	int ss_code;
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_INTERROGATION,
+		SS_GSM_TELEPHONY,
+		0, 0,	/* Supplementary services code */
+		SS_SEND_ADDITIONAL_INFO,
+		0	/* Subblock count */
+	};
+	DBG("forwarding type %d class %d\n", type, cls);
+
+	if (!cbd || cls != 7)
+		goto error;
+
+	ss_code = forw_type_to_isi_code(type);
+
+	if (ss_code < 0)
+		goto error;
+
+	msg[3] = ss_code >> 8;
+	msg[4] = ss_code & 0xFF;
+
+	if (g_isi_request_make(fd->client, msg, sizeof(msg), SS_TIMEOUT,
+				query_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, NULL, data);
+	g_free(cbd);
+}
+/*========COMMON starts===============================*/
+static gboolean isi_call_forwarding_register(gpointer user)
+{
+	struct ofono_call_forwarding *cf = user;
+	ofono_call_forwarding_register(cf);
+	return FALSE;
+}
+
+static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
+				void *opaque)
+{
+	struct ofono_call_forwarding *cf = opaque;
+
+	if (!alive) {
+		DBG("Unable to bootstrap call forwarding driver");
+		return;
+	}
+
+	DBG("%s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_idle_add(isi_call_forwarding_register, cf);
+}
+
+
+static int isi_call_forwarding_probe(struct ofono_call_forwarding *cf,
+					unsigned int vendor, void *user)
+{
+	GIsiModem *idx = user;
+	struct forw_data *data;
+	data = g_try_new0(struct forw_data, 1);
+
+	if (!data)
+		return -ENOMEM;
+
+	data->client = get_pn_ss_client(idx, PN_SS);
+
+	if (!data->client)
+		return -ENOMEM;
+
+	ofono_call_forwarding_set_data(cf, data);
+
+	if (!g_isi_verify(data->client, reachable_cb, cf))
+		DBG("Unable to verify reachability");
+
+	return 0;
+}
+
+static void isi_call_forwarding_remove(struct ofono_call_forwarding *cf)
+{
+	struct forw_data *data = ofono_call_forwarding_get_data(cf);
+
+	if (!data)
+		return;
+
+	ofono_call_forwarding_set_data(cf, NULL);
+	pn_ss_client_destroy(data->client);
+	g_free(data);
+}
+
+static struct ofono_call_forwarding_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_call_forwarding_probe,
+	.remove			= isi_call_forwarding_remove,
+	.activation		= NULL,
+	.registration		= isi_registration,
+	.deactivation		= NULL,
+	.erasure		= isi_erasure,
+	.query			= isi_query
+};
+
+void isi_call_forwarding_init()
+{
+	ofono_call_forwarding_driver_register(&driver);
+}
+
+void isi_call_forwarding_exit()
+{
+	ofono_call_forwarding_driver_unregister(&driver);
+}
+/*========COMMON end===============================*/
diff --git a/drivers/isimodem2.5/call-settings.c b/drivers/isimodem2.5/call-settings.c
new file mode 100644
index 0000000..8e830ca
--- /dev/null
+++ b/drivers/isimodem2.5/call-settings.c
@@ -0,0 +1,1093 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/call-settings.h>
+
+#include <glib.h>
+
+#include "call.h"
+#include "debug.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "ss.h"
+
+/* File configuration flags */
+
+#define CLIP_ETC
+
+struct settings_data {
+	GIsiClient *client;
+};
+
+#define content_size  40
+static char content[content_size] = {0};
+
+/* For using one client of PN_SS */
+GIsiClient *pn_ss_client;
+
+static void update_status_mask(unsigned int *mask, int bsc)
+{
+	switch (bsc) {
+	case SS_GSM_TELEPHONY:
+		*mask |= 1;
+		break;
+	case SS_GSM_ALL_DATA_TELE:
+		*mask |= 1 << 1;
+		break;
+	case SS_GSM_FACSIMILE:
+		*mask |= 1 << 2;
+		break;
+	case SS_GSM_SMS:
+		*mask |= 1 << 3;
+		break;
+	case SS_GSM_ALL_DATA_CIRCUIT_SYNC:
+		*mask |= 1 << 4;
+		break;
+	case SS_GSM_ALL_DATA_CIRCUIT_ASYNC:
+		*mask |= 1 << 5;
+		break;
+	case SS_GSM_ALL_DATA_PACKET_SYNC:
+		*mask |= 1 << 6;
+		break;
+	case SS_GSM_ALL_PAD_ACCESS:
+		*mask |= 1 << 7;
+		break;
+	default:
+		DBG("Unknown BSC value %d, please report\n", bsc);
+		break;
+	}
+}
+
+#ifdef CLIP_ETC
+static gboolean clip_query_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_settings_status_cb_t cb = cbd->cb;
+	guint32 mask = 0;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	DBG("%s", ss_ss_code_name(msg[3] << 8 | msg[4]));
+
+	if (msg[1] != SS_INTERROGATION)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+	     g_isi_sb_iter_is_valid(&iter);
+	     g_isi_sb_iter_next(&iter)) {
+
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+
+			if (ss_status & SS_GSM_PROVISIONED)
+				mask = 1;
+		}
+		break;
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	DBG("status_mask %d\n", mask);
+	CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_INTERROGATION,
+		SS_ALL_TELE_AND_BEARER,
+		SS_GSM_CLIP >> 8,	/* Supplementary services */
+		SS_GSM_CLIP & 0xFF,	/* code */
+		SS_SEND_ADDITIONAL_INFO,
+		0			/* Subblock count */
+	};
+	DBG("");
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(sd->client, msg, sizeof(msg), SS_TIMEOUT,
+				clip_query_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, data);
+	g_free(cbd);
+}
+
+static int set_clir_status(const char *value)
+{
+	DBG("Setting CLIR status to %s", value);
+	strncpy(content, value, content_size);
+	content[content_size-1] = 0;
+	return EXIT_SUCCESS;
+}
+
+int get_clir_status(void)
+{
+	DBG("Getting CLIR status %s", content);
+
+	if (!strcmp(content, "OFONO_CLIR_OPTION_INVOCATION"))
+		return OFONO_CLIR_OPTION_INVOCATION;
+
+	if (!strcmp(content, "OFONO_CLIR_OPTION_SUPPRESSION"))
+		return OFONO_CLIR_OPTION_SUPPRESSION;
+
+	return OFONO_CLIR_OPTION_DEFAULT;
+}
+
+static gboolean clir_set_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter, iter_info;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_settings_set_cb_t cb = cbd->cb;
+	gint override = OFONO_CLIR_OPTION_DEFAULT;
+	gint network = CLIR_STATUS_UNKNOWN;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	DBG("%s", ss_ss_code_name(msg[3] << 8 | msg[4]));
+
+	if (msg[1] != SS_INTERROGATION)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+	     g_isi_sb_iter_is_valid(&iter);
+	     g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+
+			if (!(ss_status & SS_GSM_PROVISIONED))
+				network = CLIR_STATUS_NOT_PROVISIONED;
+		}
+		break;
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		case SS_GSM_GENERIC_SERVICE_INFO: {
+			guint8 ss_status = 0;
+			guint8 clir_option = 0;
+			void *info = NULL;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			if (!(ss_status & SS_GSM_PROVISIONED))
+				network = CLIR_STATUS_NOT_PROVISIONED;
+
+			if (!g_isi_sb_iter_get_data(&iter, &info, 4))
+				goto error;
+
+			for (g_isi_sb_iter_init(&iter_info, info, len - 7, 0);
+			     g_isi_sb_iter_is_valid(&iter_info);
+			     g_isi_sb_iter_next(&iter_info)) {
+				DBG("Sub-block %s",
+					ss_subblock_name(
+					    g_isi_sb_iter_get_id(&iter_info)));
+
+				switch (g_isi_sb_iter_get_id(&iter_info)) {
+				case SS_GSM_CLIR_INFO: {
+					if (!g_isi_sb_iter_get_byte(&iter_info,
+							&clir_option, 2))
+						goto error;
+				}
+				break;
+				}
+
+				DBG("SS_STATUS_RESULT=%d, CLIR_OPTION=%d",
+				    ss_status, clir_option);
+			}
+
+			if (network != CLIR_STATUS_NOT_PROVISIONED) {
+				int result;
+				DBG("CLIR set successfully.");
+				result =
+					set_clir_status(
+						"OFONO_CLIR_OPTION_INVOCATION");
+
+				if (result == EXIT_FAILURE)
+					goto error;
+			} else {
+				DBG("CLIR option not supported by \
+			  network provider.");
+			}
+		}
+		break;
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+			    ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	DBG("override=%d, network=%d\n", override, network);
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+	int result = 0;
+	/*
+	* CLIR cannot be activated in Network, but we can override it
+	* using local settings - 33GPP TS 24.081 Chapter 2.5
+	*/
+
+	switch (mode) {
+	case(OFONO_CLIR_OPTION_DEFAULT):
+		result = set_clir_status("OFONO_CLIR_OPTION_DEFAULT");
+		break;
+		/* CLIR enabled (number not shown) */
+	case(OFONO_CLIR_OPTION_INVOCATION): {
+		/*
+		 * We send interrogation request to check if Network
+		 * has CLIR option provisioned.
+		 */
+		unsigned char msg[] = {
+			SS_SERVICE_REQ,
+			SS_INTERROGATION,
+			SS_ALL_TELE_AND_BEARER,
+			SS_GSM_CLIR >> 8,	/* Supplementary services */
+			SS_GSM_CLIR & 0xFF,	/* code */
+			SS_SEND_ADDITIONAL_INFO,
+			0			/* Subblock count */
+		};
+
+		DBG("Attempting to set the CLIR - \
+			checking Network Settings...");
+
+		if (!cbd)
+			goto error;
+
+		if (g_isi_request_make(sd->client, msg, sizeof(msg), SS_TIMEOUT,
+					clir_set_cb, cbd))
+			return;
+		else
+			goto error;
+	}
+	break;
+	case(OFONO_CLIR_OPTION_SUPPRESSION): /* CLIR disabled (number shown) */
+		result = set_clir_status("OFONO_CLIR_OPTION_SUPPRESSION");
+		break;
+	default:
+		DBG("CLIR mode not supported %d", mode);
+		break;
+	}
+
+	if (result == EXIT_FAILURE)
+		goto error;
+
+	DBG("CLIR set to mode: %d", mode);
+	CALLBACK_WITH_SUCCESS(cb, data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+out:
+	g_free(cbd);
+	return;
+}
+
+static gboolean clir_query_cb(GIsiClient *client,
+				const void *restrict data, size_t
+				len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter, iter_info;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_settings_clir_cb_t cb = cbd->cb;
+	gint override = OFONO_CLIR_OPTION_DEFAULT;
+	gint network = CLIR_STATUS_UNKNOWN;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	DBG("%s", ss_ss_code_name(msg[3] << 8 | msg[4]));
+
+	if (msg[1] != SS_INTERROGATION)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+		g_isi_sb_iter_is_valid(&iter);
+		g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+
+			if (!(ss_status & SS_GSM_PROVISIONED))
+				network = CLIR_STATUS_NOT_PROVISIONED;
+		}
+		break;
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		case SS_GSM_GENERIC_SERVICE_INFO: {
+			guint8 ss_status = 0;
+			guint8 clir_option = 0;
+			void *info = NULL;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			if (!(ss_status & SS_GSM_PROVISIONED))
+				network = CLIR_STATUS_NOT_PROVISIONED;
+
+			if (!g_isi_sb_iter_get_data(&iter, &info, 4))
+				goto error;
+
+			for (g_isi_sb_iter_init(&iter_info, info, len - 7, 0);
+				g_isi_sb_iter_is_valid(&iter_info);
+				g_isi_sb_iter_next(&iter_info)) {
+				DBG("Sub-sub-block %s",
+					ss_subblock_name(
+					g_isi_sb_iter_get_id(&iter_info)));
+
+				switch (g_isi_sb_iter_get_id(&iter_info)) {
+				case SS_GSM_CLIR_INFO: {
+					if (!g_isi_sb_iter_get_byte(&iter_info,
+							&clir_option, 2))
+						goto error;
+				}
+				break;
+				}
+
+				DBG("SS_STATUS_RESULT=%d, CLIR_OPTION=%d",
+				    ss_status, clir_option);
+			}
+
+			if (network != CLIR_STATUS_NOT_PROVISIONED) {
+				switch (clir_option) {
+				case SS_GSM_CLI_PERMANENT:
+					network =
+					  CLIR_STATUS_PROVISIONED_PERMANENT;
+					break;
+				case SS_GSM_DEFAULT_RESTRICTED:
+					network =
+					  CLIR_STATUS_TEMPORARY_RESTRICTED;
+					break;
+				case SS_GSM_CLI_DEFAULT_ALLOWED:
+					network =
+						CLIR_STATUS_TEMPORARY_ALLOWED;
+					break;
+				case SS_GSM_OVERRIDE_ENABLED:
+					override =
+						OFONO_CLIR_OPTION_SUPPRESSION;
+					break;
+				case SS_GSM_OVERRIDE_DISABLED:
+					override =
+					  OFONO_CLIR_OPTION_INVOCATION;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+		break;
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	/*
+	 * CLIR cannot be activated,registrated in Network, but we can override
+	 * it using local settings - 33GPP TS 24.081 Chapter 2.5
+	 * we have to read status and pass override parameter to Ofono
+	 */
+
+	if (network != CLIR_STATUS_NOT_PROVISIONED) {
+		override = get_clir_status();
+		DBG("CLIR mode queried %d\n", override);
+	}
+
+	DBG("override=%d, network=%d\n", override, network);
+	CALLBACK_WITH_SUCCESS(cb, override, network, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, override, network, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+	int override = 0, network = 2;
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_INTERROGATION,
+		SS_ALL_TELE_AND_BEARER,
+		SS_GSM_CLIR >> 8,	/* Supplementary services */
+		SS_GSM_CLIR & 0xFF,	/* code */
+		SS_SEND_ADDITIONAL_INFO,
+		0			/* Subblock count */
+	};
+	DBG("");
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(sd->client, msg, sizeof(msg), SS_TIMEOUT,
+				clir_query_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, override, network, data);
+	g_free(cbd);
+}
+
+static gboolean colp_query_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_settings_status_cb_t cb = cbd->cb;
+	guint32 mask = 0;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP) {
+		if (msg[0] == SS_SERVICE_FAILED_RESP) {
+			DBG("Sub-block nbr=%d, name=%s",
+				msg[2], ss_subblock_name(msg[3]));
+		}
+
+		goto error;
+	}
+
+	DBG("%s", ss_ss_code_name(msg[3] << 8 | msg[4]));
+
+	if (msg[1] != SS_INTERROGATION)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+		g_isi_sb_iter_is_valid(&iter);
+		g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+
+			if (ss_status & SS_GSM_PROVISIONED)
+				mask = 1;
+		}
+		break;
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		case SS_GSM_BSC_INFO: {
+			guint8 bsc;
+			guint8 count;
+			guint8 i;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &count, 2))
+				goto error;
+
+			for (i = 0; i < count; i++) {
+				if (!g_isi_sb_iter_get_byte(&iter, &bsc, 3 + i))
+					goto error;
+
+				update_status_mask(&mask, bsc);
+			}
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	DBG("status_mask %d\n", mask);
+	CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_colp_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 isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_INTERROGATION,
+		SS_ALL_TELE_AND_BEARER,
+		SS_GSM_COLP >> 8,	/* Supplementary services */
+		SS_GSM_COLP & 0xFF,	/* code */
+		SS_SEND_ADDITIONAL_INFO,
+		0			/* Subblock count */
+	};
+	DBG("");
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(sd->client, msg, sizeof(msg), SS_TIMEOUT,
+				colp_query_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, data);
+	g_free(cbd);
+}
+
+static gboolean colr_query_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_settings_status_cb_t cb = cbd->cb;
+	guint32 mask = 0;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP) {
+		if (msg[0] == SS_SERVICE_FAILED_RESP) {
+			DBG("Sub-block nbr=%d, name=%s",
+				msg[2], ss_subblock_name(msg[3]));
+		}
+
+		goto error;
+	}
+
+	DBG("%s", ss_ss_code_name(msg[3] << 8 | msg[4]));
+	DBG("%s", ss_ss_code_name(msg[3] << 8 | msg[4]));
+
+	if (msg[1] != SS_INTERROGATION)
+		goto error;
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+		g_isi_sb_iter_is_valid(&iter);
+		g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+
+			if (ss_status & SS_GSM_PROVISIONED)
+				mask = 1;
+		}
+		break;
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		case SS_GSM_BSC_INFO: {
+			guint8 bsc;
+			guint8 count;
+			guint8 i;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &count, 2))
+				goto error;
+
+			for (i = 0; i < count; i++) {
+				if (!g_isi_sb_iter_get_byte(&iter, &bsc, 3 + i))
+					goto error;
+
+				update_status_mask(&mask, bsc);
+			}
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	DBG("status_mask %d\n", mask);
+	CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_colr_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 isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_INTERROGATION,
+		SS_ALL_TELE_AND_BEARER,
+		SS_GSM_COLR >> 8,	/* Supplementary services */
+		SS_GSM_COLR & 0xFF,	/* code */
+		SS_SEND_ADDITIONAL_INFO,
+		0			/* Subblock count */
+	};
+	DBG("");
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(sd->client, msg, sizeof(msg), SS_TIMEOUT,
+				colr_query_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, data);
+	g_free(cbd);
+}
+#endif
+
+static gboolean cw_query_resp_cb(GIsiClient *client, const void *restrict data,
+					size_t len,
+					uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_settings_status_cb_t cb = cbd->cb;
+	guint32 mask = 0;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	if (msg[1] != SS_INTERROGATION)
+		goto error;
+
+	DBG("%s", ss_ss_code_name(msg[3] << 8 | msg[4]));
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+		g_isi_sb_iter_is_valid(&iter);
+		g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+
+			if (ss_status & SS_GSM_ACTIVE)
+				mask = 1;
+			else
+				mask = 0;
+		}
+		break;
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		case SS_GSM_BSC_INFO: {
+			guint8 bsc;
+			guint8 count;
+			guint8 i;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &count, 2))
+				goto error;
+
+			for (i = 0; i < count; i++) {
+				if (!g_isi_sb_iter_get_byte(&iter, &bsc, 3 + i))
+					goto error;
+
+				update_status_mask(&mask, bsc);
+			}
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+			    g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	DBG("status_mask %d\n", mask);
+	CALLBACK_WITH_SUCCESS(cb, mask, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		SS_INTERROGATION,
+		SS_ALL_TELE_AND_BEARER,
+		SS_GSM_CALL_WAITING >> 8,	/* Supplementary services */
+		SS_GSM_CALL_WAITING & 0xFF,	/* code */
+		SS_SEND_ADDITIONAL_INFO,
+		0				/* Subblock count */
+	};
+	DBG("waiting class %d\n", cls);
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(sd->client, msg, sizeof(msg), SS_TIMEOUT,
+				cw_query_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, data);
+	g_free(cbd);
+}
+
+static gboolean cw_set_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	GIsiSubBlockIter iter;
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_call_settings_set_cb_t cb = cbd->cb;
+	DBG("%s %s", ss_message_id_name(msg[0]), ss_operation_name(msg[1]));
+
+	if (len < 7 || msg[0] != SS_SERVICE_COMPLETED_RESP)
+		goto error;
+
+	if (msg[1] != SS_ACTIVATION && msg[1] != SS_DEACTIVATION)
+		goto error;
+
+	DBG("%s", ss_ss_code_name(msg[3] << 8 | msg[4]));
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 7);
+		g_isi_sb_iter_is_valid(&iter);
+		g_isi_sb_iter_next(&iter)) {
+		DBG("Sub-block %s",
+			ss_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SS_STATUS_RESULT: {
+			guint8 ss_status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &ss_status, 2))
+				goto error;
+
+			DBG("SS_STATUS_RESULT=%d", ss_status);
+		}
+		break;
+		case SS_GSM_ADDITIONAL_INFO:
+			break;
+		case SS_GSM_DATA: {
+			guint8 status;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &status, 2))
+				goto error;
+
+			if ((status & SS_GSM_ACTIVE)
+			    && (msg[1] == SS_DEACTIVATION))
+				goto error;
+
+			if (!(status & SS_GSM_ACTIVE)
+			    && (msg[1] == SS_ACTIVATION))
+				goto error;
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				ss_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(cs, cb, data);
+	unsigned char msg[] = {
+		SS_SERVICE_REQ,
+		mode ? SS_ACTIVATION : SS_DEACTIVATION,
+		SS_ALL_TELE_AND_BEARER,
+		SS_GSM_CALL_WAITING >> 8,	/* Supplementary services */
+		SS_GSM_CALL_WAITING & 0xFF,	/* code */
+		SS_SEND_ADDITIONAL_INFO,
+		0				/* Subblock count */
+	};
+	DBG("waiting mode %d class %d\n", mode, cls);
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(sd->client, msg, sizeof(msg), SS_TIMEOUT,
+				cw_set_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+
+/* COMMON starts */
+static gboolean isi_call_settings_register(gpointer user)
+{
+	struct ofono_call_settings *cs = user;
+	ofono_call_settings_register(cs);
+	return FALSE;
+}
+
+static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
+				void *opaque)
+{
+	struct ofono_call_settings *cs = opaque;
+
+	if (!alive) {
+		DBG("Unable to bootstrap call settings driver");
+		return;
+	}
+
+	DBG("%s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_idle_add(isi_call_settings_register, cs);
+}
+
+
+static int isi_call_settings_probe(struct ofono_call_settings *cs,
+					unsigned int vendor, void *user)
+{
+	GIsiModem *idx = user;
+	struct settings_data *data;
+	data = g_try_new0(struct settings_data, 1);
+
+	if (!data)
+		return -ENOMEM;
+
+	data->client = get_pn_ss_client(idx, PN_SS);
+
+	if (!data->client)
+		return -ENOMEM;
+
+	ofono_call_settings_set_data(cs, data);
+
+	if (!g_isi_verify(data->client, reachable_cb, cs))
+		DBG("Unable to verify reachability");
+
+	return 0;
+}
+
+static void isi_call_settings_remove(struct ofono_call_settings *cs)
+{
+	struct settings_data *data = ofono_call_settings_get_data(cs);
+
+	if (!data)
+		return;
+
+	ofono_call_settings_set_data(cs, NULL);
+	pn_ss_client_destroy(data->client);
+	g_free(data);
+}
+
+static struct ofono_call_settings_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_call_settings_probe,
+	.remove			= isi_call_settings_remove,
+	.clip_query		= isi_clip_query,
+	.colp_query		= isi_colp_query,
+	.clir_query		= isi_clir_query,
+	.colr_query		= isi_colr_query,
+	.clir_set		= isi_clir_set,
+	.cw_query		= isi_cw_query,
+	.cw_set			= isi_cw_set
+};
+
+void isi_call_settings_init()
+{
+	pn_ss_client = NULL;
+	ofono_call_settings_driver_register(&driver);
+}
+
+void isi_call_settings_exit()
+{
+	ofono_call_settings_driver_unregister(&driver);
+}
+
+GIsiClient *get_pn_ss_client(GIsiModem *modem, uint8_t resource)
+{
+	if (!pn_ss_client)
+		pn_ss_client = g_isi_client_create(modem, resource);
+
+	return pn_ss_client;
+}
+
+void pn_ss_client_destroy(GIsiClient *client)
+{
+	if (pn_ss_client) {
+		g_isi_client_destroy(client);
+		pn_ss_client = NULL;
+	}
+}
+/* COMMON end */
diff --git a/drivers/isimodem2.5/call.h b/drivers/isimodem2.5/call.h
new file mode 100644
index 0000000..a0ba50c
--- /dev/null
+++ b/drivers/isimodem2.5/call.h
@@ -0,0 +1,237 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_CALL_H
+#define __ISIMODEM25_CALL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PN_MODEM_CALL					0xC9
+
+enum call_subblock {
+	CALL_MODEM_SB_ORIGIN_ADDRESS =			0x01,
+	CALL_MODEM_SB_DESTINATION_ADDRESS =		0x03,
+	CALL_MODEM_SB_DESTINATION_SUBADDRESS =		0x04,
+	CALL_MODEM_SB_DESTINATION_PRE_ADDRESS =		0x05,
+	CALL_MODEM_SB_DESTINATION_POST_ADDRESS =	0x06,
+	CALL_MODEM_SB_MODE =				0x07,
+	CALL_MODEM_SB_CAUSE =				0x08,
+	CALL_MODEM_SB_OPERATION =			0x09,
+	CALL_MODEM_SB_DTMF_STRING =			0x10,
+	CALL_MODEM_SB_STATUS =				0x0A,
+	CALL_MODEM_SB_STATUS_INFO =			0x0B,
+	CALL_MODEM_SB_DTMF_INFO =			0x1A,
+	CALL_MODEM_SB_ADDR_AND_STATUS_INFO =		0x1D,
+	CALL_MODEM_SB_DTMF_TIMERS =			0x1E,
+	CALL_MODEM_SB_STATUS_MODE =			0x1C,
+	CALL_MODEM_SB_NW_CAUSE =			0x20,
+	CALL_MODEM_SB_LINE_ID =				0x47,
+	CALL_MODEM_SB_DETAILED_CAUSE =			0xBF
+};
+
+enum call_message_id {
+	CALL_MODEM_CREATE_REQ =				0x01,
+	CALL_MODEM_CREATE_RESP =			0x02,
+	CALL_MODEM_MT_ALERT_IND =			0x05,
+	CALL_MODEM_ANSWER_REQ =				0x07,
+	CALL_MODEM_ANSWER_RESP =			0x08,
+	CALL_MODEM_RELEASE_REQ =			0x09,
+	CALL_MODEM_RELEASE_RESP =			0x0A,
+	CALL_MODEM_STATUS_REQ =				0x0D,
+	CALL_MODEM_STATUS_RESP =			0x0E,
+	CALL_MODEM_STATUS_IND =				0x0F,
+	CALL_MODEM_CONTROL_REQ =			0x11,
+	CALL_MODEM_CONTROL_RESP =			0x12,
+	CALL_MODEM_CONTROL_IND =			0x13,
+	CALL_MODEM_DTMF_SEND_REQ =			0x17,
+	CALL_MODEM_DTMF_SEND_RESP =			0x18,
+	CALL_MODEM_NOTIFICATION_IND =			0xA0
+};
+
+enum call_modem_mode {
+	CALL_MODEM_MODE_SPEECH =			0x01
+};
+
+enum call_modem_line_id {
+	CALL_MODEM_PRESENT_DEFAULT =			0x00,
+	CALL_MODEM_PRESENT_ALLOWED =			0x01,
+	CALL_MODEM_PRESENT_RESTRICTED =			0x02
+};
+
+enum call_modem_mode_info {
+	CALL_MODEM_MODE_ORIGINATOR =			0x01
+};
+
+enum call_modem_cause {
+	CALL_MODEM_CAUSE_NO_CALL =			0x01,
+	CALL_MODEM_CAUSE_RELEASE_BY_USER =		0x03,
+	CALL_MODEM_CAUSE_BUSY_USER_REQUEST =		0x04,
+	CALL_MODEM_NW_CAUSE_NORMAL =			0x10,
+	CALL_MODEM_NW_CAUSE_FACILITY_REJECTED =		0x1D
+};
+
+enum call_modem_operation {
+	CALL_MODEM_OP_UNKNOWN =				0x00,
+	CALL_MODEM_OP_HOLD =				0x01,
+	CALL_MODEM_OP_RETRIEVE =			0x02,
+	CALL_MODEM_OP_SWAP =				0x03,
+	CALL_MODEM_OP_CONFERENCE_BUILD =		0x04,
+	CALL_MODEM_OP_CONFERENCE_SPLIT =		0x05,
+	CALL_MODEM_OP_TRANSFER =			0xA1
+};
+
+enum call_modem_cause_type_sender {
+	CALL_MODEM_CAUSE_TYPE_CLIENT =			0x01,
+	CALL_MODEM_CAUSE_TYPE_SERVER =			0x02,
+	CALL_MODEM_CAUSE_TYPE_NETWORK =			0x03
+};
+
+enum call_modem_status_mode {
+	CALL_MODEM_STATUS_IDLE =			0x00,
+	CALL_MODEM_STATUS_CREATE =			0x01,
+	CALL_MODEM_STATUS_COMING =			0x02,
+	CALL_MODEM_STATUS_PROCEEDING =			0x03,
+	CALL_MODEM_STATUS_MO_ALERTING =			0x04,
+	CALL_MODEM_STATUS_MT_ALERTING =			0x05,
+	CALL_MODEM_STATUS_WAITING =			0x06,
+	CALL_MODEM_STATUS_ANSWERED =			0x07,
+	CALL_MODEM_STATUS_ACTIVE =			0x08,
+	CALL_MODEM_STATUS_MO_RELEASE =			0x09,
+	CALL_MODEM_STATUS_MT_RELEASE =			0x0A,
+	CALL_MODEM_STATUS_HOLD_INITIATED =		0x0B,
+	CALL_MODEM_STATUS_HOLD =			0x0C,
+	CALL_MODEM_STATUS_RETRIEVE_INITIATED =		0x0D,
+	CALL_MODEM_STATUS_RECONNECT_PENDING =		0x0E
+};
+
+enum call_modem_status_mod {
+	CALL_MODEM_STATUS_MODE_ADDR_AND_ORIGIN =	0x02
+};
+
+enum call_modem_id {
+	CALL_MODEM_ID_NONE =				0x00,
+	CALL_MODEM_ID_1 =				0x01,
+	CALL_MODEM_ID_2 =				0x02,
+	CALL_MODEM_ID_3 =				0x03,
+	CALL_MODEM_ID_4 =				0x04,
+	CALL_MODEM_ID_WAITING =				0x20,
+	CALL_MODEM_ID_HOLD =				0x40,
+	CALL_MODEM_ID_ACTIVE =				0x80,
+	CALL_MODEM_ID_ALL =				0xF0
+};
+
+enum call_modem_dtmf_pause_values {
+	CALL_MODEM_DTMF_PAUSE_1S =			0x01
+};
+
+enum call_modem_dtmf_info_values {
+	CALL_MODEM_DTMF_ENABLE_TONE_IND_SEND =		0x01
+};
+
+enum call_modem_notification_sb_values {
+	CALL_MODEM_SB_NOTIFY =				0xB1,
+	CALL_MODEM_SB_SS_NOTIFY =			0xB2,
+	CALL_MODEM_SB_SS_CODE =				0xB3,
+	CALL_MODEM_SB_SS_STATUS =			0xB4,
+	CALL_MODEM_SB_SS_NOTIFY_INDICATOR =		0xB5,
+	CALL_MODEM_SB_SS_HOLD_INDICATOR =		0xB6,
+	CALL_MODEM_SB_SS_ECT_INDICATOR =		0xB7,
+	CALL_MODEM_SB_REMOTE_ADDRESS =			0xA6,
+	CALL_MODEM_SB_REMOTE_SUBADDRESS =		0xA7,
+	CALL_MODEM_SB_CUG_INFO =			0xA0,
+	CALL_MODEM_SB_ORIGIN_INFO =			0x0E,
+	CALL_MODEM_SB_ALERTING_PATTERN =		0xA1,
+	CALL_MODEM_SB_ALERTING_INFO =			0x0C
+};
+
+enum call_modem_notification_indicator {
+	CALL_MODEM_NOTIFY_USER_SUSPENDED =		0x00,
+	CALL_MODEM_NOTIFY_USER_RESUMED =		0x01,
+	CALL_MODEM_NOTIFY_BEARER_CHANGE =		0x02
+};
+
+enum call_modem_mmi_ss_codes {
+	CALL_MODEM_SSC_ALL_FWDS =			0x0002,
+	CALL_MODEM_SSC_ALL_COND_FWD =			0x0004,
+	CALL_MODEM_SSC_CFU =				0x0015,
+	CALL_MODEM_SSC_CFB =				0x0043,
+	CALL_MODEM_SSC_CFNRY =				0x003D,
+	CALL_MODEM_SSC_CFGNC =				0x003E,
+	CALL_MODEM_SSC_OUTGOING_BARR_SERV =		0x014D,
+	CALL_MODEM_SSC_INCOMING_BARR_SERV =		0x0161,
+	CALL_MODEM_SSC_CALL_WAITING =			0x002B,
+	CALL_MODEM_SSC_CLIR =				0x001F,
+	CALL_MODEM_SSC_ETC =				0x0060,
+	CALL_MODEM_SSC_MPTY =				0xFFFE,
+	CALL_MODEM_SSC_CALL_HOLD =			0xFFFF
+};
+
+enum call_modem_ss_status {
+	CALL_MODEM_SS_STATUS_ACTIVE =			0x01,
+	CALL_MODEM_SS_STATUS_REGISTERED =		0x02,
+	CALL_MODEM_SS_STATUS_PROVISIONED =		0x04,
+	CALL_MODEM_SS_STATUS_QUIESCENT =		0x08
+};
+
+enum call_modem_ss_notification {
+	CALL_MODEM_SSN_INCOMING_IS_FWD =		0x01,
+	CALL_MODEM_SSN_INCOMING_FWD =			0x02,
+	CALL_MODEM_SSN_OUTGOING_FWD =			0x04
+};
+
+enum call_modem_ss_indicator {
+	CALL_MODEM_SSI_CALL_IS_WAITING =		0x01,
+	CALL_MODEM_SSI_MPTY =				0x02,
+	CALL_MODEM_SSI_CLIR_SUPPR_REJ =			0x04
+};
+
+enum call_modem_ss_hold_indicator {
+	CALL_MODEM_HOLD_IND_RETRIEVED =			0x00,
+	CALL_MODEM_HOLD_IND_ON_HOLD =			0x01
+};
+
+enum call_modem_ss_ect_indicator {
+	CALL_MODEM_ECT_CALL_STATE_ALERT =		0x00,
+	CALL_MODEM_ECT_CALL_STATE_ACTIVE =		0x01
+};
+
+/* 27.007 Section 7.7 */
+enum clir_status {
+	CLIR_STATUS_NOT_PROVISIONED =			0,
+	CLIR_STATUS_PROVISIONED_PERMANENT,
+	CLIR_STATUS_UNKNOWN,
+	CLIR_STATUS_TEMPORARY_RESTRICTED,
+	CLIR_STATUS_TEMPORARY_ALLOWED
+};
+
+int get_clir_status(void);
+
+GIsiClient *get_pn_callserver_client(GIsiModem *modem, uint8_t resource);
+void pn_callserver_client_destroy(GIsiClient *client);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* !__ISIMODEM25_CALL_H */
diff --git a/drivers/isimodem2.5/cbs.c b/drivers/isimodem2.5/cbs.c
new file mode 100644
index 0000000..c0087a5
--- /dev/null
+++ b/drivers/isimodem2.5/cbs.c
@@ -0,0 +1,433 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/cbs.h>
+
+#include <glib.h>
+
+#include "debug.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "sms.h"
+
+int cbs_subscription_nr;
+
+struct cbs_data {
+	GIsiClient *client;
+};
+
+GIsiClient *pn_sms_client;
+
+static void reset_buf(char *buf, char *buf_2, int buf_len)
+{
+	memset(buf, '\0', buf_len);
+	memset(buf_2, '\0', buf_len);
+}
+
+static int get_topics_len(const char *topics)
+{
+	int i = 0;
+	int k = 0;
+	int length = 0;
+	char buf[6];
+	char buf_2[6];
+
+	reset_buf(buf, buf_2, 6);
+
+	while (*topics != '\0') {
+		if (*topics == ',') {
+			reset_buf(buf, buf_2, 6);
+			k = 0;
+			length++;
+		} else if (*topics != ',' && *topics != '-') {
+			buf[k] = *topics;
+			k++;
+		} else if (*topics == '-') {
+			topics++;
+			i++;
+			k = 0;
+
+			while (*topics != ',' && *topics != '\0') {
+				buf_2[k] = *topics;
+				topics++;
+				i++;
+				k++;
+			}
+
+			length = length + atoi(buf_2) - atoi(buf) + 1;
+			k = 0;
+		}
+
+		topics++;
+		i++;
+	}
+
+	topics = topics - i;
+	return length;
+}
+
+static void parse_topics(const char *topics, gint16 *topics_parsed)
+{
+	int j = 0;
+	int k = 0;
+	char buf[6];
+	char buf_2[6];
+
+	reset_buf(buf, buf_2, 6);
+
+	while (*topics != '\0') {
+		if (*topics != ',' && *topics != '-') {
+			buf[j] = *topics;
+			j++;
+		} else if (*topics == '-') {
+			topics++;
+			j = 0;
+
+			while (*topics != ',' && *topics != '\0') {
+				buf_2[j] = *topics;
+				topics++;
+				j++;
+			}
+
+			for (j = 0; j <= (atoi(buf_2) - atoi(buf)); j++) {
+				topics_parsed[k] = atoi(buf) + j;
+				topics_parsed[k] = g_ntohs(topics_parsed[k]);
+				k++;
+			}
+
+			j = 0;
+		} else if (*topics == ',') {
+			topics_parsed[k] = atoi(buf);
+			topics_parsed[k] = g_ntohs(topics_parsed[k]);
+			reset_buf(buf, buf_2, 6);
+			j = 0;
+			k++;
+		}
+
+		topics++;
+	}
+}
+
+static gboolean set_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_cbs_set_cb_t cb = cbd->cb;
+
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if (len < 3 || msg[0] != SMS_CB_ROUTING_RESP)
+		goto error;
+
+	if (msg[2] != SMS_OK)
+		goto error;
+
+	cbs_subscription_nr = msg[1];
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_set_topics(struct ofono_cbs *cbs, const char *topics,
+				ofono_cbs_set_cb_t cb, void *data)
+{
+	struct cbs_data *cd = ofono_cbs_get_data(cbs);
+	struct isi_cb_data *cbd = isi_cb_data_new(cbs, cb, data);
+	int topics_len = get_topics_len(topics);
+	gint16 topics_out[topics_len];
+
+	uint8_t msg[] = {
+		SMS_CB_ROUTING_REQ,
+		SMS_ROUTING_SET,
+		cbs_subscription_nr,
+		0x00,			/*Subscription type*/
+		0x00,			/*Fillers*/
+		0x00,
+		0x01,			/*Number of subblocks*/
+		0x00,
+		0x26,			/*Subblock*/
+		0x00,
+		topics_len * 2 + 6,	/*Subblock length*/
+		0x00,
+		topics_len,		/*Number of topics*/
+	};
+	struct iovec iov[2] = {
+		{ msg, sizeof(msg) },
+		{ topics_out, sizeof(topics_out) },
+	};
+	parse_topics(topics, topics_out);
+
+	DBG("");
+
+	if (g_isi_request_vmake(cd->client, iov, 2, CBS_TIMEOUT,
+				set_resp_cb, cbd))
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static gboolean clear_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_cbs_set_cb_t cb = cbd->cb;
+	DBG("");
+
+	if (!msg)
+		DBG("ISI client error: %d", g_isi_client_error(client));
+
+	cbs_subscription_nr = 0;
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_clear_topics(struct ofono_cbs *cbs,
+				ofono_cbs_set_cb_t cb, void *data)
+{
+	struct cbs_data *cd = ofono_cbs_get_data(cbs);
+	struct isi_cb_data *cbd = isi_cb_data_new(cbs, cb, data);
+	uint8_t msg[] = {
+		SMS_CB_ROUTING_REQ,
+		SMS_ROUTING_RELEASE,
+		cbs_subscription_nr,	/* Subscription number */
+		0x00,			/* Subscription type */
+		0x00,			/* Fillers */
+		0x00,
+		0x00			/*No subblocks*/
+	};
+
+	DBG("");
+
+	if (g_isi_request_make(cd->client, msg, sizeof(msg), CBS_TIMEOUT,
+				clear_resp_cb, cbd))
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static void routing_ntf_cb(GIsiClient *client,
+				const void *restrict data, size_t len,
+				uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_cbs *cbs = opaque;
+	GIsiSubBlockIter iter;
+	gboolean message_received = FALSE;
+	guint16 subblock_len;
+	guint8 i;
+	DBG("");
+
+	if (!msg || len < 3 || msg[0] != SMS_CB_ROUTING_IND)
+		return;
+
+	for (g_isi_sb_iter_init_full(&iter, msg, len, 3, TRUE, msg[2]);
+	     g_isi_sb_iter_is_valid(&iter);
+	     g_isi_sb_iter_next(&iter)) {
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case SMS_SB_CB_MESSAGE: {
+			msg = iter.start + 4;
+			len = len - 4;
+			message_received = TRUE;
+			break;
+		}
+		case SMS_SB_CBS_SUBSCRIPTION: {
+			g_isi_sb_iter_get_word(&iter, &subblock_len, 2);
+			len = len - subblock_len;
+			break;
+		}
+		default:
+			break;
+		}
+	}
+
+	if (message_received) {
+		unsigned char *buf_msg = g_try_new(unsigned char, 91);
+		/*91 is a fixed size of CBS message including fillers*/
+
+		DBG("CBS Message received");
+		len = len - 7; /*exclude message header and fillers*/
+
+		for (i = 0; i < 91; i++) {
+			if (i < 6)
+				buf_msg[i] = msg[i];
+			else
+				buf_msg[i] = msg[i+1];
+		}
+
+		ofono_cbs_notify(cbs, buf_msg, len);
+		g_free(buf_msg);
+	} else
+		DBG("Error reading CBS message");
+}
+
+static gboolean routing_resp_cb(GIsiClient *client,
+				const void *restrict data, size_t len,
+				uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_cbs *cbs = opaque;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return TRUE;
+	}
+
+	if (len < 3 || msg[0] != SMS_CB_ROUTING_RESP)
+		return FALSE;
+
+	if (msg[1] != SMS_OK) {
+		if (msg[1] == SMS_ERR_PP_RESERVED) {
+			DBG("Request failed:CBS already registered");
+			return TRUE;
+		}
+	}
+
+	g_isi_subscribe(client, SMS_CB_ROUTING_IND, routing_ntf_cb,
+			cbs);
+	ofono_cbs_register(cbs);
+	return TRUE;
+}
+
+
+static int isi_cbs_probe(struct ofono_cbs *cbs, unsigned int vendor, void *user)
+{
+	GIsiModem *idx = user;
+	struct cbs_data *cd = g_try_new0(struct cbs_data, 1);
+	unsigned char msg[] = {
+		SMS_CB_ROUTING_REQ,
+		SMS_ROUTING_QUERRY_ALL,
+		0x00,			/* New subscription*/
+		0x00,			/* Subscription type */
+		0x00,			/* Fillers */
+		0x00,
+		0x00			/* No subblocks*/
+	};
+
+	DBG("");
+
+	if (!cd)
+		return -ENOMEM;
+
+	cd->client = get_pn_sms_client(idx, PN_SMS);
+
+	if (!cd->client) {
+		g_free(cd);
+		return -ENOMEM;
+	}
+
+	ofono_cbs_set_data(cbs, cd);
+
+	if (!g_isi_request_make(cd->client, msg, sizeof(msg), CBS_TIMEOUT,
+				routing_resp_cb, cbs))
+		DBG("Failed to set CBS routing.");
+
+	return 0;
+}
+
+static gboolean isi_cbs_remove_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object, void *opaque)
+{
+	DBG("CBS subscription released.");
+	return TRUE;
+}
+
+static void isi_cbs_remove(struct ofono_cbs *cbs)
+{
+	struct cbs_data *data = ofono_cbs_get_data(cbs);
+	uint8_t msg[] = {
+		SMS_CB_ROUTING_REQ,
+		SMS_ROUTING_RELEASE,
+		cbs_subscription_nr,	/* Subscription number */
+		0x00,			/* Subscription type */
+		0x00,			/* Fillers */
+		0x00,
+		0x00			/* No subblocks*/
+	};
+
+	DBG("");
+
+	if (!data)
+		return;
+
+	if (is_pn_sms_client()) {
+		/* Release of modem resources for CBS subscription. */
+		cbs_subscription_nr = 0;
+		g_isi_request_make(data->client, msg, sizeof(msg),
+				CBS_TIMEOUT, isi_cbs_remove_cb, NULL);
+		pn_sms_client_destroy(data->client);
+	}
+	g_free(data);
+}
+
+static struct ofono_cbs_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_cbs_probe,
+	.remove			= isi_cbs_remove,
+	.set_topics		= isi_set_topics,
+	.clear_topics		= isi_clear_topics
+};
+
+void isi_cbs_init()
+{
+	ofono_cbs_driver_register(&driver);
+}
+
+void isi_cbs_exit()
+{
+	ofono_cbs_driver_unregister(&driver);
+}
+
diff --git a/drivers/isimodem2.5/checkpatch.pl b/drivers/isimodem2.5/checkpatch.pl
new file mode 100755
index 0000000..a4d7434
--- /dev/null
+++ b/drivers/isimodem2.5/checkpatch.pl
@@ -0,0 +1,2789 @@
+#!/usr/bin/perl -w
+# (c) 2001, Dave Jones. (the file handling bit)
+# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
+# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
+# (c) 2008,2009, Andy Whitcroft <apw@canonical.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+$P =~ s(a).*/@@g;
+
+my $V = '0.30';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $quiet = 0;
+my $tree = 1;
+my $chk_signoff = 1;
+my $chk_patch = 1;
+my $tst_only;
+my $emacs = 0;
+my $terse = 0;
+my $file = 0;
+my $check = 0;
+my $summary = 1;
+my $mailback = 0;
+my $summary_file = 0;
+my $root;
+my %debug;
+my $help = 0;
+
+sub help {
+	my ($exitcode) = @_;
+
+	print << "EOM";
+Usage: $P [OPTION]... [FILE]...
+Version: $V
+
+Options:
+  -q, --quiet                quiet
+  --no-tree                  run without a kernel tree
+  --no-signoff               do not check for 'Signed-off-by' line
+  --patch                    treat FILE as patchfile (default)
+  --emacs                    emacs compile window format
+  --terse                    one line per report
+  -f, --file                 treat FILE as regular source file
+  --subjective, --strict     enable more subjective tests
+  --root=PATH                PATH to the kernel tree root
+  --no-summary               suppress the per-file summary
+  --mailback                 only produce a report in case of warnings/errors
+  --summary-file             include the filename in summary
+  --debug KEY=[0|1]          turn on/off debugging of KEY, where KEY is one of
+                             'values', 'possible', 'type', and 'attr' (default
+                             is all off)
+  --test-only=WORD           report only warnings/errors containing WORD
+                             literally
+  -h, --help, --version      display this help and exit
+
+When FILE is - read standard input.
+EOM
+
+	exit($exitcode);
+}
+
+GetOptions(
+	'q|quiet+'	=> \$quiet,
+	'tree!'		=> \$tree,
+	'signoff!'	=> \$chk_signoff,
+	'patch!'	=> \$chk_patch,
+	'emacs!'	=> \$emacs,
+	'terse!'	=> \$terse,
+	'f|file!'	=> \$file,
+	'subjective!'	=> \$check,
+	'strict!'	=> \$check,
+	'root=s'	=> \$root,
+	'summary!'	=> \$summary,
+	'mailback!'	=> \$mailback,
+	'summary-file!'	=> \$summary_file,
+
+	'debug=s'	=> \%debug,
+	'test-only=s'	=> \$tst_only,
+	'h|help'	=> \$help,
+	'version'	=> \$help
+) or help(1);
+
+help(0) if ($help);
+
+my $exit = 0;
+
+if ($#ARGV < 0) {
+	print "$P: no input files\n";
+	exit(1);
+}
+
+my $dbg_values = 0;
+my $dbg_possible = 0;
+my $dbg_type = 0;
+my $dbg_attr = 0;
+for my $key (keys %debug) {
+	## no critic
+	eval "\${dbg_$key} = '$debug{$key}';";
+	die "$@" if ($@);
+}
+
+if ($terse) {
+	$emacs = 1;
+	$quiet++;
+}
+
+if ($tree) {
+	if (defined $root) {
+		if (!top_of_kernel_tree($root)) {
+			die "$P: $root: --root does not point@a valid tree\n";
+		}
+	} else {
+		if (top_of_kernel_tree('.')) {
+			$root = '.';
+		} elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
+						top_of_kernel_tree($1)) {
+			$root = $1;
+		}
+	}
+
+	if (!defined $root) {
+		print "Must be run from the top-level dir. of a kernel tree\n";
+		exit(2);
+	}
+}
+
+my $emitted_corrupt = 0;
+
+our $Ident	= qr{
+			[A-Za-z_][A-Za-z\d_]*
+			(?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
+		}x;
+our $Storage	= qr{extern|static|asmlinkage};
+our $Sparse	= qr{
+			__user|
+			__kernel|
+			__force|
+			__iomem|
+			__must_check|
+			__init_refok|
+			__kprobes|
+			__ref
+		}x;
+
+# Notes to $Attribute:
+# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
+our $Attribute	= qr{
+			const|
+			__read_mostly|
+			__kprobes|
+			__(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
+			____cacheline_aligned|
+			____cacheline_aligned_in_smp|
+			____cacheline_internodealigned_in_smp|
+			__weak
+		  }x;
+our $Modifier;
+our $Inline	= qr{inline|__always_inline|noinline};
+our $Member	= qr{->$Ident|\.$Ident|\[[^]]*\]};
+our $Lval	= qr{$Ident(?:$Member)*};
+
+our $Constant	= qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*};
+our $Assignment	= qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};
+our $Compare    = qr{<=|>=|==|!=|<|>};
+our $Operators	= qr{
+			<=|>=|==|!=|
+			=>|->|<<|>>|<|>|!|~|
+			&&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+		  }x;
+
+our $NonptrType;
+our $Type;
+our $Declare;
+
+our $UTF8	= qr {
+	[\x09\x0A\x0D\x20-\x7E]              # ASCII
+	| [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
+	|  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
+	| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
+	|  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
+	|  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
+	| [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
+	|  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
+}x;
+
+our $typeTypedefs = qr{(?x:
+	(?:__)?(?:u|s|be|le)(?:8|16|32|64)|
+	atomic_t
+)};
+
+our $logFunctions = qr{(?x:
+	printk|
+	pr_(debug|dbg|vdbg|devel|info|warning|err|notice|alert|crit|emerg|cont)|
+	dev_(printk|dbg|vdbg|info|warn|err|notice|alert|crit|emerg|WARN)|
+	WARN|
+	panic
+)};
+
+our @typeList = (
+	qr{void},
+	qr{(?:unsigned\s+)?char},
+	qr{(?:unsigned\s+)?short},
+	qr{(?:unsigned\s+)?int},
+	qr{(?:unsigned\s+)?long},
+	qr{(?:unsigned\s+)?long\s+int},
+	qr{(?:unsigned\s+)?long\s+long},
+	qr{(?:unsigned\s+)?long\s+long\s+int},
+	qr{unsigned},
+	qr{float},
+	qr{double},
+	qr{bool},
+	qr{struct\s+$Ident},
+	qr{union\s+$Ident},
+	qr{enum\s+$Ident},
+	qr{${Ident}_t},
+	qr{${Ident}_handler},
+	qr{${Ident}_handler_fn},
+);
+our @modifierList = (
+	qr{fastcall},
+);
+
+sub build_types {
+	my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";
+	my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";
+	$Modifier	= qr{(?:$Attribute|$Sparse|$mods)};
+	$NonptrType	= qr{
+			(?:$Modifier\s+|const\s+)*
+			(?:
+				(?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+				(?:$typeTypedefs\b)|
+				(?:${all}\b)
+			)
+			(?:\s+$Modifier|\s+const)*
+		  }x;
+	$Type	= qr{
+			$NonptrType
+			(?:[\s\*]+\s*const|[\s\*]+|(?:\s*\[\s*\])+)?
+			(?:\s+$Inline|\s+$Modifier)*
+		  }x;
+	$Declare	= qr{(?:$Storage\s+)?$Type};
+}
+build_types();
+
+$chk_signoff = 0 if ($file);
+
+my @dep_includes = ();
+my @dep_functions = ();
+my $removal = "Documentation/feature-removal-schedule.txt";
+if ($tree && -f "$root/$removal") {
+	open(my $REMOVE, '<', "$root/$removal") ||
+				die "$P: $removal: open failed - $!\n";
+	while (<$REMOVE>) {
+		if (/^Check:\s+(.*\S)/) {
+			for my $entry (split(/[, ]+/, $1)) {
+				if ($entry =~ m(a)include/(.*)@) {
+					push(@dep_includes, $1);
+
+				} elsif ($entry !~ m@/@) {
+					push(@dep_functions, $entry);
+				}
+			}
+		}
+	}
+	close($REMOVE);
+}
+
+my @rawlines = ();
+my @lines = ();
+my $vname;
+for my $filename (@ARGV) {
+	my $FILE;
+	if ($file) {
+		open($FILE, '-|', "diff -u /dev/null $filename") ||
+			die "$P: $filename: diff failed - $!\n";
+	} elsif ($filename eq '-') {
+		open($FILE, '<&STDIN');
+	} else {
+		open($FILE, '<', "$filename") ||
+			die "$P: $filename: open failed - $!\n";
+	}
+	if ($filename eq '-') {
+		$vname = 'Your patch';
+	} else {
+		$vname = $filename;
+	}
+	while (<$FILE>) {
+		chomp;
+		push(@rawlines, $_);
+	}
+	close($FILE);
+	if (!process($filename)) {
+		$exit = 1;
+	}
+	@rawlines = ();
+	@lines = ();
+}
+
+exit($exit);
+
+sub top_of_kernel_tree {
+	my ($root) = @_;
+
+	my @tree_check = (
+		"COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile",
+		"README", "Documentation", "arch", "include", "drivers",
+		"fs", "init", "ipc", "kernel", "lib", "scripts",
+	);
+
+	foreach my $check (@tree_check) {
+		if (! -e $root . '/' . $check) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
+sub expand_tabs {
+	my ($str) = @_;
+
+	my $res = '';
+	my $n = 0;
+	for my $c (split(//, $str)) {
+		if ($c eq "\t") {
+			$res .= ' ';
+			$n++;
+			for (; ($n % 8) != 0; $n++) {
+				$res .= ' ';
+			}
+			next;
+		}
+		$res .= $c;
+		$n++;
+	}
+
+	return $res;
+}
+sub copy_spacing {
+	(my $res = shift) =~ tr/\t/ /c;
+	return $res;
+}
+
+sub line_stats {
+	my ($line) = @_;
+
+	# Drop the diff line leader and expand tabs
+	$line =~ s/^.//;
+	$line = expand_tabs($line);
+
+	# Pick the indent from the front of the line.
+	my ($white) = ($line =~ /^(\s*)/);
+
+	return (length($line), length($white));
+}
+
+my $sanitise_quote = '';
+
+sub sanitise_line_reset {
+	my ($in_comment) = @_;
+
+	if ($in_comment) {
+		$sanitise_quote = '*/';
+	} else {
+		$sanitise_quote = '';
+	}
+}
+sub sanitise_line {
+	my ($line) = @_;
+
+	my $res = '';
+	my $l = '';
+
+	my $qlen = 0;
+	my $off = 0;
+	my $c;
+
+	# Always copy over the diff marker.
+	$res = substr($line, 0, 1);
+
+	for ($off = 1; $off < length($line); $off++) {
+		$c = substr($line, $off, 1);
+
+		# Comments we are wacking completly including the begin
+		# and end, all to $;.
+		if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
+			$sanitise_quote = '*/';
+
+			substr($res, $off, 2, "$;$;");
+			$off++;
+			next;
+		}
+		if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
+			$sanitise_quote = '';
+			substr($res, $off, 2, "$;$;");
+			$off++;
+			next;
+		}
+		if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') {
+			$sanitise_quote = '//';
+
+			substr($res, $off, 2, $sanitise_quote);
+			$off++;
+			next;
+		}
+
+		# A \ in a string means ignore the next character.
+		if (($sanitise_quote eq "'" || $sanitise_quote eq '"') &&
+		    $c eq "\\") {
+			substr($res, $off, 2, 'XX');
+			$off++;
+			next;
+		}
+		# Regular quotes.
+		if ($c eq "'" || $c eq '"') {
+			if ($sanitise_quote eq '') {
+				$sanitise_quote = $c;
+
+				substr($res, $off, 1, $c);
+				next;
+			} elsif ($sanitise_quote eq $c) {
+				$sanitise_quote = '';
+			}
+		}
+
+		#print "c<$c> SQ<$sanitise_quote>\n";
+		if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") {
+			substr($res, $off, 1, $;);
+		} elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") {
+			substr($res, $off, 1, $;);
+		} elsif ($off != 0 && $sanitise_quote && $c ne "\t") {
+			substr($res, $off, 1, 'X');
+		} else {
+			substr($res, $off, 1, $c);
+		}
+	}
+
+	if ($sanitise_quote eq '//') {
+		$sanitise_quote = '';
+	}
+
+	# The pathname on a #include may be surrounded by '<' and '>'.
+	if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) {
+		my $clean = 'X' x length($1);
+		$res =~ s@\<.*\>@<$clean>@;
+
+	# The whole of a #error is a string.
+	} elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
+		my $clean = 'X' x length($1);
+		$res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
+	}
+
+	return $res;
+}
+
+sub ctx_statement_block {
+	my ($linenr, $remain, $off) = @_;
+	my $line = $linenr - 1;
+	my $blk = '';
+	my $soff = $off;
+	my $coff = $off - 1;
+	my $coff_set = 0;
+
+	my $loff = 0;
+
+	my $type = '';
+	my $level = 0;
+	my @stack = ();
+	my $p;
+	my $c;
+	my $len = 0;
+
+	my $remainder;
+	while (1) {
+		@stack = (['', 0]) if ($#stack == -1);
+
+		#warn "CSB: blk<$blk> remain<$remain>\n";
+		# If we are about to drop off the end, pull in more
+		# context.
+		if ($off >= $len) {
+			for (; $remain > 0; $line++) {
+				last if (!defined $lines[$line]);
+				next if ($lines[$line] =~ /^-/);
+				$remain--;
+				$loff = $len;
+				$blk .= $lines[$line] . "\n";
+				$len = length($blk);
+				$line++;
+				last;
+			}
+			# Bail if there is no further context.
+			#warn "CSB: blk<$blk> off<$off> len<$len>\n";
+			if ($off >= $len) {
+				last;
+			}
+		}
+		$p = $c;
+		$c = substr($blk, $off, 1);
+		$remainder = substr($blk, $off);
+
+		#warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
+
+		# Handle nested #if/#else.
+		if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) {
+			push(@stack, [ $type, $level ]);
+		} elsif ($remainder =~ /^#\s*(?:else|elif)\b/) {
+			($type, $level) = @{$stack[$#stack - 1]};
+		} elsif ($remainder =~ /^#\s*endif\b/) {
+			($type, $level) = @{pop(@stack)};
+		}
+
+		# Statement ends at the ';' or a close '}' at the
+		# outermost level.
+		if ($level == 0 && $c eq ';') {
+			last;
+		}
+
+		# An else is really a conditional as long as its not else if
+		if ($level == 0 && $coff_set == 0 &&
+				(!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
+				$remainder =~ /^(else)(?:\s|{)/ &&
+				$remainder !~ /^else\s+if\b/) {
+			$coff = $off + length($1) - 1;
+			$coff_set = 1;
+			#warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
+			#warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
+		}
+
+		if (($type eq '' || $type eq '(') && $c eq '(') {
+			$level++;
+			$type = '(';
+		}
+		if ($type eq '(' && $c eq ')') {
+			$level--;
+			$type = ($level != 0)? '(' : '';
+
+			if ($level == 0 && $coff < $soff) {
+				$coff = $off;
+				$coff_set = 1;
+				#warn "CSB: mark coff<$coff>\n";
+			}
+		}
+		if (($type eq '' || $type eq '{') && $c eq '{') {
+			$level++;
+			$type = '{';
+		}
+		if ($type eq '{' && $c eq '}') {
+			$level--;
+			$type = ($level != 0)? '{' : '';
+
+			if ($level == 0) {
+				last;
+			}
+		}
+		$off++;
+	}
+	# We are truly at the end, so shuffle to the next line.
+	if ($off == $len) {
+		$loff = $len + 1;
+		$line++;
+		$remain--;
+	}
+
+	my $statement = substr($blk, $soff, $off - $soff + 1);
+	my $condition = substr($blk, $soff, $coff - $soff + 1);
+
+	#warn "STATEMENT<$statement>\n";
+	#warn "CONDITION<$condition>\n";
+
+	#print "coff<$coff> soff<$off> loff<$loff>\n";
+
+	return ($statement, $condition,
+			$line, $remain + 1, $off - $loff + 1, $level);
+}
+
+sub statement_lines {
+	my ($stmt) = @_;
+
+	# Strip the diff line prefixes and rip blank lines at start and end.
+	$stmt =~ s/(^|\n)./$1/g;
+	$stmt =~ s/^\s*//;
+	$stmt =~ s/\s*$//;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+
+	return $#stmt_lines + 2;
+}
+
+sub statement_rawlines {
+	my ($stmt) = @_;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+
+	return $#stmt_lines + 2;
+}
+
+sub statement_block_size {
+	my ($stmt) = @_;
+
+	$stmt =~ s/(^|\n)./$1/g;
+	$stmt =~ s/^\s*{//;
+	$stmt =~ s/}\s*$//;
+	$stmt =~ s/^\s*//;
+	$stmt =~ s/\s*$//;
+
+	my @stmt_lines = ($stmt =~ /\n/g);
+	my @stmt_statements = ($stmt =~ /;/g);
+
+	my $stmt_lines = $#stmt_lines + 2;
+	my $stmt_statements = $#stmt_statements + 1;
+
+	if ($stmt_lines > $stmt_statements) {
+		return $stmt_lines;
+	} else {
+		return $stmt_statements;
+	}
+}
+
+sub ctx_statement_full {
+	my ($linenr, $remain, $off) = @_;
+	my ($statement, $condition, $level);
+
+	my (@chunks);
+
+	# Grab the first conditional/block pair.
+	($statement, $condition, $linenr, $remain, $off, $level) =
+				ctx_statement_block($linenr, $remain, $off);
+	#print "F: c<$condition> s<$statement> remain<$remain>\n";
+	push(@chunks, [ $condition, $statement ]);
+	if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
+		return ($level, $linenr, @chunks);
+	}
+
+	# Pull in the following conditional/block pairs and see if they
+	# could continue the statement.
+	for (;;) {
+		($statement, $condition, $linenr, $remain, $off, $level) =
+				ctx_statement_block($linenr, $remain, $off);
+		#print "C: c<$condition> s<$statement> remain<$remain>\n";
+		last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
+		#print "C: push\n";
+		push(@chunks, [ $condition, $statement ]);
+	}
+
+	return ($level, $linenr, @chunks);
+}
+
+sub ctx_block_get {
+	my ($linenr, $remain, $outer, $open, $close, $off) = @_;
+	my $line;
+	my $start = $linenr - 1;
+	my $blk = '';
+	my @o;
+	my @c;
+	my @res = ();
+
+	my $level = 0;
+	my @stack = ($level);
+	for ($line = $start; $remain > 0; $line++) {
+		next if ($rawlines[$line] =~ /^-/);
+		$remain--;
+
+		$blk .= $rawlines[$line];
+
+		# Handle nested #if/#else.
+		if ($rawlines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
+			push(@stack, $level);
+		} elsif ($rawlines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
+			$level = $stack[$#stack - 1];
+		} elsif ($rawlines[$line] =~ /^.\s*#\s*endif\b/) {
+			$level = pop(@stack);
+		}
+
+		foreach my $c (split(//, $rawlines[$line])) {
+			##print "C<$c>L<$level><$open$close>O<$off>\n";
+			if ($off > 0) {
+				$off--;
+				next;
+			}
+
+			if ($c eq $close && $level > 0) {
+				$level--;
+				last if ($level == 0);
+			} elsif ($c eq $open) {
+				$level++;
+			}
+		}
+
+		if (!$outer || $level <= 1) {
+			push(@res, $rawlines[$line]);
+		}
+
+		last if ($level == 0);
+	}
+
+	return ($level, @res);
+}
+sub ctx_block_outer {
+	my ($linenr, $remain) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
+	return @r;
+}
+sub ctx_block {
+	my ($linenr, $remain) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+	return @r;
+}
+sub ctx_statement {
+	my ($linenr, $remain, $off) = @_;
+
+	my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+	return @r;
+}
+sub ctx_block_level {
+	my ($linenr, $remain) = @_;
+
+	return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+}
+sub ctx_statement_level {
+	my ($linenr, $remain, $off) = @_;
+
+	return ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+}
+
+sub ctx_locate_comment {
+	my ($first_line, $end_line) = @_;
+
+	# Catch a comment on the end of the line itself.
+	my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@);
+	return $current_comment if (defined $current_comment);
+
+	# Look through the context and try and figure out if there is a
+	# comment.
+	my $in_comment = 0;
+	$current_comment = '';
+	for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {
+		my $line = $rawlines[$linenr - 1];
+		#warn "           $line\n";
+		if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
+			$in_comment = 1;
+		}
+		if ($line =~ m@/\*@) {
+			$in_comment = 1;
+		}
+		if (!$in_comment && $current_comment ne '') {
+			$current_comment = '';
+		}
+		$current_comment .= $line . "\n" if ($in_comment);
+		if ($line =~ m@\*/@) {
+			$in_comment = 0;
+		}
+	}
+
+	chomp($current_comment);
+	return($current_comment);
+}
+sub ctx_has_comment {
+	my ($first_line, $end_line) = @_;
+	my $cmt = ctx_locate_comment($first_line, $end_line);
+
+	##print "LINE: $rawlines[$end_line - 1 ]\n";
+	##print "CMMT: $cmt\n";
+
+	return ($cmt ne '');
+}
+
+sub raw_line {
+	my ($linenr, $cnt) = @_;
+
+	my $offset = $linenr - 1;
+	$cnt++;
+
+	my $line;
+	while ($cnt) {
+		$line = $rawlines[$offset++];
+		next if (defined($line) && $line =~ /^-/);
+		$cnt--;
+	}
+
+	return $line;
+}
+
+sub cat_vet {
+	my ($vet) = @_;
+	my ($res, $coded);
+
+	$res = '';
+	while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {
+		$res .= $1;
+		if ($2 ne '') {
+			$coded = sprintf("^%c", unpack('C', $2) + 64);
+			$res .= $coded;
+		}
+	}
+	$res =~ s/$/\$/;
+
+	return $res;
+}
+
+my $av_preprocessor = 0;
+my $av_pending;
+my @av_paren_type;
+my $av_pend_colon;
+
+sub annotate_reset {
+	$av_preprocessor = 0;
+	$av_pending = '_';
+	@av_paren_type = ('E');
+	$av_pend_colon = 'O';
+}
+
+sub annotate_values {
+	my ($stream, $type) = @_;
+
+	my $res;
+	my $var = '_' x length($stream);
+	my $cur = $stream;
+
+	print "$stream\n" if ($dbg_values > 1);
+
+	while (length($cur)) {
+		@av_paren_type = ('E') if ($#av_paren_type < 0);
+		print " <" . join('', @av_paren_type) .
+				"> <$type> <$av_pending>" if ($dbg_values > 1);
+		if ($cur =~ /^(\s+)/o) {
+			print "WS($1)\n" if ($dbg_values > 1);
+			if ($1 =~ /\n/ && $av_preprocessor) {
+				$type = pop(@av_paren_type);
+				$av_preprocessor = 0;
+			}
+
+		} elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\()/) {
+			print "DECLARE($1)\n" if ($dbg_values > 1);
+			$type = 'T';
+
+		} elsif ($cur =~ /^($Modifier)\s*/) {
+			print "MODIFIER($1)\n" if ($dbg_values > 1);
+			$type = 'T';
+
+		} elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
+			print "DEFINE($1,$2)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+			push(@av_paren_type, $type);
+			if ($2 ne '') {
+				$av_pending = 'N';
+			}
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
+			print "UNDEF($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+			push(@av_paren_type, $type);
+
+		} elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
+			print "PRE_START($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+
+			push(@av_paren_type, $type);
+			push(@av_paren_type, $type);
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
+			print "PRE_RESTART($1)\n" if ($dbg_values > 1);
+			$av_preprocessor = 1;
+
+			push(@av_paren_type, $av_paren_type[$#av_paren_type]);
+
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\#\s*(?:endif))/o) {
+			print "PRE_END($1)\n" if ($dbg_values > 1);
+
+			$av_preprocessor = 1;
+
+			# Assume all arms of the conditional end as this
+			# one does, and continue as if the #endif was not here.
+			pop(@av_paren_type);
+			push(@av_paren_type, $type);
+			$type = 'E';
+
+		} elsif ($cur =~ /^(\\\n)/o) {
+			print "PRECONT($1)\n" if ($dbg_values > 1);
+
+		} elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
+			print "ATTR($1)\n" if ($dbg_values > 1);
+			$av_pending = $type;
+			$type = 'N';
+
+		} elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
+			print "SIZEOF($1)\n" if ($dbg_values > 1);
+			if (defined $2) {
+				$av_pending = 'V';
+			}
+			$type = 'N';
+
+		} elsif ($cur =~ /^(if|while|for)\b/o) {
+			print "COND($1)\n" if ($dbg_values > 1);
+			$av_pending = 'E';
+			$type = 'N';
+
+		} elsif ($cur =~/^(case)/o) {
+			print "CASE($1)\n" if ($dbg_values > 1);
+			$av_pend_colon = 'C';
+			$type = 'N';
+
+		} elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
+			print "KEYWORD($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(\()/o) {
+			print "PAREN('$1')\n" if ($dbg_values > 1);
+			push(@av_paren_type, $av_pending);
+			$av_pending = '_';
+			$type = 'N';
+
+		} elsif ($cur =~ /^(\))/o) {
+			my $new_type = pop(@av_paren_type);
+			if ($new_type ne '_') {
+				$type = $new_type;
+				print "PAREN('$1') -> $type\n"
+							if ($dbg_values > 1);
+			} else {
+				print "PAREN('$1')\n" if ($dbg_values > 1);
+			}
+
+		} elsif ($cur =~ /^($Ident)\s*\(/o) {
+			print "FUNC($1)\n" if ($dbg_values > 1);
+			$type = 'V';
+			$av_pending = 'V';
+
+		} elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) {
+			if (defined $2 && $type eq 'C' || $type eq 'T') {
+				$av_pend_colon = 'B';
+			} elsif ($type eq 'E') {
+				$av_pend_colon = 'L';
+			}
+			print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1);
+			$type = 'V';
+
+		} elsif ($cur =~ /^($Ident|$Constant)/o) {
+			print "IDENT($1)\n" if ($dbg_values > 1);
+			$type = 'V';
+
+		} elsif ($cur =~ /^($Assignment)/o) {
+			print "ASSIGN($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~/^(;|{|})/) {
+			print "END($1)\n" if ($dbg_values > 1);
+			$type = 'E';
+			$av_pend_colon = 'O';
+
+		} elsif ($cur =~/^(,)/) {
+			print "COMMA($1)\n" if ($dbg_values > 1);
+			$type = 'C';
+
+		} elsif ($cur =~ /^(\?)/o) {
+			print "QUESTION($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(:)/o) {
+			print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1);
+
+			substr($var, length($res), 1, $av_pend_colon);
+			if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {
+				$type = 'E';
+			} else {
+				$type = 'N';
+			}
+			$av_pend_colon = 'O';
+
+		} elsif ($cur =~ /^(\[)/o) {
+			print "CLOSE($1)\n" if ($dbg_values > 1);
+			$type = 'N';
+
+		} elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
+			my $variant;
+
+			print "OPV($1)\n" if ($dbg_values > 1);
+			if ($type eq 'V') {
+				$variant = 'B';
+			} else {
+				$variant = 'U';
+			}
+
+			substr($var, length($res), 1, $variant);
+			$type = 'N';
+
+		} elsif ($cur =~ /^($Operators)/o) {
+			print "OP($1)\n" if ($dbg_values > 1);
+			if ($1 ne '++' && $1 ne '--') {
+				$type = 'N';
+			}
+
+		} elsif ($cur =~ /(^.)/o) {
+			print "C($1)\n" if ($dbg_values > 1);
+		}
+		if (defined $1) {
+			$cur = substr($cur, length($1));
+			$res .= $type x length($1);
+		}
+	}
+
+	return ($res, $var);
+}
+
+sub possible {
+	my ($possible, $line) = @_;
+	my $notPermitted = qr{(?:
+		^(?:
+			$Modifier|
+			$Storage|
+			$Type|
+			DEFINE_\S+
+		)$|
+		^(?:
+			goto|
+			return|
+			case|
+			else|
+			asm|__asm__|
+			do
+		)(?:\s|$)|
+		^(?:typedef|struct|enum)\b
+	    )}x;
+	warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+	if ($possible !~ $notPermitted) {
+		# Check for modifiers.
+		$possible =~ s/\s*$Storage\s*//g;
+		$possible =~ s/\s*$Sparse\s*//g;
+		if ($possible =~ /^\s*$/) {
+
+		} elsif ($possible =~ /\s/) {
+			$possible =~ s/\s*$Type\s*//g;
+			for my $modifier (split(' ', $possible)) {
+				if ($modifier !~ $notPermitted) {
+					warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible);
+					push(@modifierList, $modifier);
+				}
+			}
+
+		} else {
+			warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
+			push(@typeList, $possible);
+		}
+		build_types();
+	} else {
+		warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
+	}
+}
+
+my $prefix = '';
+
+sub report {
+	if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) {
+		return 0;
+	}
+	my $line = $prefix . $_[0];
+
+	$line = (split('\n', $line))[0] . "\n" if ($terse);
+
+	push(our @report, $line);
+
+	return 1;
+}
+sub report_dump {
+	our @report;
+}
+sub ERROR {
+	if (report("ERROR: $_[0]\n")) {
+		our $clean = 0;
+		our $cnt_error++;
+	}
+}
+sub WARN {
+	if (report("WARNING: $_[0]\n")) {
+		our $clean = 0;
+		our $cnt_warn++;
+	}
+}
+sub CHK {
+	if ($check && report("CHECK: $_[0]\n")) {
+		our $clean = 0;
+		our $cnt_chk++;
+	}
+}
+
+sub check_absolute_file {
+	my ($absolute, $herecurr) = @_;
+	my $file = $absolute;
+
+	##print "absolute<$absolute>\n";
+
+	# See if any suffix of this path is a path within the tree.
+	while ($file =~ s@^[^/]*/@@) {
+		if (-f "$root/$file") {
+			##print "file<$file>\n";
+			last;
+		}
+	}
+	if (! -f _)  {
+		return 0;
+	}
+
+	# It is, so see if the prefix is acceptable.
+	my $prefix = $absolute;
+	substr($prefix, -length($file)) = '';
+
+	##print "prefix<$prefix>\n";
+	if ($prefix ne ".../") {
+		WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr);
+	}
+}
+
+sub process {
+	my $filename = shift;
+
+	my $linenr=0;
+	my $prevline="";
+	my $prevrawline="";
+	my $stashline="";
+	my $stashrawline="";
+
+	my $length;
+	my $indent;
+	my $previndent=0;
+	my $stashindent=0;
+
+	our $clean = 1;
+	my $signoff = 0;
+	my $is_patch = 0;
+
+	our @report = ();
+	our $cnt_lines = 0;
+	our $cnt_error = 0;
+	our $cnt_warn = 0;
+	our $cnt_chk = 0;
+
+	# Trace the real file/line as we go.
+	my $realfile = '';
+	my $realline = 0;
+	my $realcnt = 0;
+	my $here = '';
+	my $in_comment = 0;
+	my $comment_edge = 0;
+	my $first_line = 0;
+	my $p1_prefix = '';
+
+	my $prev_values = 'E';
+
+	# suppression flags
+	my %suppress_ifbraces;
+	my %suppress_whiletrailers;
+	my %suppress_export;
+
+	# Pre-scan the patch sanitizing the lines.
+	# Pre-scan the patch looking for any __setup documentation.
+	#
+	my @setup_docs = ();
+	my $setup_docs = 0;
+
+	sanitise_line_reset();
+	my $line;
+	foreach my $rawline (@rawlines) {
+		$linenr++;
+		$line = $rawline;
+
+		if ($rawline=~/^\+\+\+\s+(\S+)/) {
+			$setup_docs = 0;
+			if ($1 =~ m(a)Documentation/kernel-parameters.txt$@) {
+				$setup_docs = 1;
+			}
+			#next;
+		}
+		if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+			$realline=$1-1;
+			if (defined $2) {
+				$realcnt=$3+1;
+			} else {
+				$realcnt=1+1;
+			}
+			$in_comment = 0;
+
+			# Guestimate if this is a continuing comment.  Run
+			# the context looking for a comment "edge".  If this
+			# edge is a close comment then we must be in a comment
+			# at context start.
+			my $edge;
+			my $cnt = $realcnt;
+			for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+				next if (defined $rawlines[$ln - 1] &&
+					 $rawlines[$ln - 1] =~ /^-/);
+				$cnt--;
+				#print "RAW<$rawlines[$ln - 1]>\n";
+				last if (!defined $rawlines[$ln - 1]);
+				if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
+				    $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
+					($edge) = $1;
+					last;
+				}
+			}
+			if (defined $edge && $edge eq '*/') {
+				$in_comment = 1;
+			}
+
+			# Guestimate if this is a continuing comment.  If this
+			# is the start of a diff block and this line starts
+			# ' *' then it is very likely a comment.
+			if (!defined $edge &&
+			    $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
+			{
+				$in_comment = 1;
+			}
+
+			##print "COMMENT:$in_comment edge<$edge> $rawline\n";
+			sanitise_line_reset($in_comment);
+
+		} elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
+			# Standardise the strings and chars within the input to
+			# simplify matching -- only bother with positive lines.
+			$line = sanitise_line($rawline);
+		}
+		push(@lines, $line);
+
+		if ($realcnt > 1) {
+			$realcnt-- if ($line =~ /^(?:\+| |$)/);
+		} else {
+			$realcnt = 0;
+		}
+
+		#print "==>$rawline\n";
+		#print "-->$line\n";
+
+		if ($setup_docs && $line =~ /^\+/) {
+			push(@setup_docs, $line);
+		}
+	}
+
+	$prefix = '';
+
+	$realcnt = 0;
+	$linenr = 0;
+	foreach my $line (@lines) {
+		$linenr++;
+
+		my $rawline = $rawlines[$linenr - 1];
+
+#extract the line range in the file after the patch is applied
+		if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+			$is_patch = 1;
+			$first_line = $linenr + 1;
+			$realline=$1-1;
+			if (defined $2) {
+				$realcnt=$3+1;
+			} else {
+				$realcnt=1+1;
+			}
+			annotate_reset();
+			$prev_values = 'E';
+
+			%suppress_ifbraces = ();
+			%suppress_whiletrailers = ();
+			%suppress_export = ();
+			next;
+
+# track the line number as we move through the hunk, note that
+# new versions of GNU diff omit the leading space on completely
+# blank context lines so we need to count that too.
+		} elsif ($line =~ /^( |\+|$)/) {
+			$realline++;
+			$realcnt-- if ($realcnt != 0);
+
+			# Measure the line length and indent.
+			($length, $indent) = line_stats($rawline);
+
+			# Track the previous line.
+			($prevline, $stashline) = ($stashline, $line);
+			($previndent, $stashindent) = ($stashindent, $indent);
+			($prevrawline, $stashrawline) = ($stashrawline, $rawline);
+
+			#warn "line<$line>\n";
+
+		} elsif ($realcnt == 1) {
+			$realcnt--;
+		}
+
+		my $hunk_line = ($realcnt != 0);
+
+#make up the handle for any error we report on this line
+		$prefix = "$filename:$realline: " if ($emacs && $file);
+		$prefix = "$filename:$linenr: " if ($emacs && !$file);
+
+		$here = "#$linenr: " if (!$file);
+		$here = "#$realline: " if ($file);
+
+		# extract the filename as it passes
+		if ($line=~/^\+\+\+\s+(\S+)/) {
+			$realfile = $1;
+			$realfile =~ s@^([^/]*)/@@;
+
+			$p1_prefix = $1;
+			if (!$file && $tree && $p1_prefix ne '' &&
+			    -e "$root/$p1_prefix") {
+				WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
+			}
+
+			if ($realfile =~ m@^include/asm/@) {
+				ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
+			}
+			next;
+		}
+
+		$here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
+
+		my $hereline = "$here\n$rawline\n";
+		my $herecurr = "$here\n$rawline\n";
+		my $hereprev = "$here\n$prevrawline\n$rawline\n";
+
+		$cnt_lines++ if ($realcnt != 0);
+
+#check the patch for a signoff:
+		if ($line =~ /^\s*signed-off-by:/i) {
+			# This is a signoff, if ugly, so do not double report.
+			$signoff++;
+			if (!($line =~ /^\s*Signed-off-by:/)) {
+				WARN("Signed-off-by: is the preferred form\n" .
+					$herecurr);
+			}
+			if ($line =~ /^\s*signed-off-by:\S/i) {
+				WARN("space required after Signed-off-by:\n" .
+					$herecurr);
+			}
+		}
+
+# Check for wrappage within a valid hunk of the file
+		if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
+			ERROR("patch seems to be corrupt (line wrapped?)\n" .
+				$herecurr) if (!$emitted_corrupt++);
+		}
+
+# Check for absolute kernel paths.
+		if ($tree) {
+			while ($line =~ m{(?:^|\s)(/\S*)}g) {
+				my $file = $1;
+
+				if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+				    check_absolute_file($1, $herecurr)) {
+					#
+				} else {
+					check_absolute_file($file, $herecurr);
+				}
+			}
+		}
+
+# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
+		if (($realfile =~ /^$/ || $line =~ /^\+/) &&
+		    $rawline !~ m/^$UTF8*$/) {
+			my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/);
+
+			my $blank = copy_spacing($rawline);
+			my $ptr = substr($blank, 0, length($utf8_prefix)) . "^";
+			my $hereptr = "$hereline$ptr\n";
+
+			ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
+		}
+
+# ignore non-hunk lines and lines being removed
+		next if (!$hunk_line || $line =~ /^-/);
+
+#trailing whitespace
+		if ($line =~ /^\+.*\015/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("DOS line endings\n" . $herevet);
+
+		} elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("trailing whitespace\n" . $herevet);
+		}
+
+# check we are in a valid source file if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
+#80 column limit
+		if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
+		    $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
+		    $line !~ /^\+\s*$logFunctions\s*\(\s*(?:KERN_\S+\s*)?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ &&
+		    $length > 80)
+		{
+			WARN("line over 80 characters\n" . $herecurr);
+		}
+
+# check for spaces before a quoted newline
+		if ($rawline =~ /^.*\".*\s\\n/) {
+			WARN("unnecessary whitespace before a quoted newline\n" . $herecurr);
+		}
+
+# check for adding lines without a newline.
+		if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) {
+			WARN("adding a line without newline at end of file\n" . $herecurr);
+		}
+
+# Blackfin: use hi/lo macros
+		if ($realfile =~ m(a)arch/blackfin/.*\.S$@) {
+			if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
+				my $herevet = "$here\n" . cat_vet($line) . "\n";
+				ERROR("use the LO() macro, not (... & 0xFFFF)\n" . $herevet);
+			}
+			if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
+				my $herevet = "$here\n" . cat_vet($line) . "\n";
+				ERROR("use the HI() macro, not (... >> 16)\n" . $herevet);
+			}
+		}
+
+# check we are in a valid source file C or perl if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c|pl)$/);
+
+# at the beginning of a line any tabs must come first and anything
+# more than 8 must use tabs.
+		if ($rawline =~ /^\+\s* \t\s*\S/ ||
+		    $rawline =~ /^\+\s*        \s*/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			ERROR("code indent should use tabs where possible\n" . $herevet);
+		}
+
+# check for space before tabs.
+		if ($rawline =~ /^\+/ && $rawline =~ / \t/) {
+			my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+			WARN("please, no space before tabs\n" . $herevet);
+		}
+
+# check we are in a valid C source file if not then ignore this hunk
+		next if ($realfile !~ /\.(h|c)$/);
+
+# check for RCS/CVS revision markers
+		if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
+			WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
+		}
+
+# Blackfin: don't use __builtin_bfin_[cs]sync
+		if ($line =~ /__builtin_bfin_csync/) {
+			my $herevet = "$here\n" . cat_vet($line) . "\n";
+			ERROR("use the CSYNC() macro in asm/blackfin.h\n" . $herevet);
+		}
+		if ($line =~ /__builtin_bfin_ssync/) {
+			my $herevet = "$here\n" . cat_vet($line) . "\n";
+			ERROR("use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
+		}
+
+# Check for potential 'bare' types
+		my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
+		    $realline_next);
+		if ($realcnt && $line =~ /.\s*\S/) {
+			($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+				ctx_statement_block($linenr, $realcnt, 0);
+			$stat =~ s/\n./\n /g;
+			$cond =~ s/\n./\n /g;
+
+			# Find the real next line.
+			$realline_next = $line_nr_next;
+			if (defined $realline_next &&
+			    (!defined $lines[$realline_next - 1] ||
+			     substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) {
+				$realline_next++;
+			}
+
+			my $s = $stat;
+			$s =~ s/{.*$//s;
+
+			# Ignore goto labels.
+			if ($s =~ /$Ident:\*$/s) {
+
+			# Ignore functions being called
+			} elsif ($s =~ /^.\s*$Ident\s*\(/s) {
+
+			} elsif ($s =~ /^.\s*else\b/s) {
+
+			# declarations always start with types
+			} elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) {
+				my $type = $1;
+				$type =~ s/\s+/ /g;
+				possible($type, "A:" . $s);
+
+			# definitions in global scope can only start with types
+			} elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
+				possible($1, "B:" . $s);
+			}
+
+			# any (foo ... *) is a pointer cast, and foo is a type
+			while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) {
+				possible($1, "C:" . $s);
+			}
+
+			# Check for any sort of function declaration.
+			# int foo(something bar, other baz);
+			# void (*store_gdt)(x86_descr_ptr *);
+			if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) {
+				my ($name_len) = length($1);
+
+				my $ctx = $s;
+				substr($ctx, 0, $name_len + 1, '');
+				$ctx =~ s/\)[^\)]*$//;
+
+				for my $arg (split(/\s*,\s*/, $ctx)) {
+					if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) {
+
+						possible($1, "D:" . $s);
+					}
+				}
+			}
+
+		}
+
+#
+# Checks which may be anchored in the context.
+#
+
+# Check for switch () and associated case and default
+# statements should be at the same indent.
+		if ($line=~/\bswitch\s*\(.*\)/) {
+			my $err = '';
+			my $sep = '';
+			my @ctx = ctx_block_outer($linenr, $realcnt);
+			shift(@ctx);
+			for my $ctx (@ctx) {
+				my ($clen, $cindent) = line_stats($ctx);
+				if ($ctx =~ /^\+\s*(case\s+|default:)/ &&
+							$indent != $cindent) {
+					$err .= "$sep$ctx\n";
+					$sep = '';
+				} else {
+					$sep = "[...]\n";
+				}
+			}
+			if ($err ne '') {
+				ERROR("switch and case should be at the same indent\n$hereline$err");
+			}
+		}
+
+# if/while/etc brace do not go on next line, unless defining a do while loop,
+# or if that brace on the next line is for something else
+		if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
+			my $pre_ctx = "$1$2";
+
+			my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
+			my $ctx_cnt = $realcnt - $#ctx - 1;
+			my $ctx = join("\n", @ctx);
+
+			my $ctx_ln = $linenr;
+			my $ctx_skip = $realcnt;
+
+			while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt &&
+					defined $lines[$ctx_ln - 1] &&
+					$lines[$ctx_ln - 1] =~ /^-/)) {
+				##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n";
+				$ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/);
+				$ctx_ln++;
+			}
+
+			#print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+			#print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
+
+			if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+				ERROR("that open brace { should be on the previous line\n" .
+					"$here\n$ctx\n$lines[$ctx_ln - 1]\n");
+			}
+			if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
+			    $ctx =~ /\)\s*\;\s*$/ &&
+			    defined $lines[$ctx_ln - 1])
+			{
+				my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
+				if ($nindent > $indent) {
+					WARN("trailing semicolon indicates no statements, indent implies otherwise\n" .
+						"$here\n$ctx\n$lines[$ctx_ln - 1]\n");
+				}
+			}
+		}
+
+# Check relative indent for conditionals and blocks.
+		if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+			my ($s, $c) = ($stat, $cond);
+
+			substr($s, 0, length($c), '');
+
+			# Make sure we remove the line prefixes as we have
+			# none on the first line, and are going to readd them
+			# where necessary.
+			$s =~ s/\n./\n/gs;
+
+			# Find out how long the conditional actually is.
+			my @newlines = ($c =~ /\n/gs);
+			my $cond_lines = 1 + $#newlines;
+
+			# We want to check the first line inside the block
+			# starting at the end of the conditional, so remove:
+			#  1) any blank line termination
+			#  2) any opening brace { on end of the line
+			#  3) any do (...) {
+			my $continuation = 0;
+			my $check = 0;
+			$s =~ s/^.*\bdo\b//;
+			$s =~ s/^\s*{//;
+			if ($s =~ s/^\s*\\//) {
+				$continuation = 1;
+			}
+			if ($s =~ s/^\s*?\n//) {
+				$check = 1;
+				$cond_lines++;
+			}
+
+			# Also ignore a loop construct at the end of a
+			# preprocessor statement.
+			if (($prevline =~ /^.\s*#\s*define\s/ ||
+			    $prevline =~ /\\\s*$/) && $continuation == 0) {
+				$check = 0;
+			}
+
+			my $cond_ptr = -1;
+			$continuation = 0;
+			while ($cond_ptr != $cond_lines) {
+				$cond_ptr = $cond_lines;
+
+				# If we see an #else/#elif then the code
+				# is not linear.
+				if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+					$check = 0;
+				}
+
+				# Ignore:
+				#  1) blank lines, they should be at 0,
+				#  2) preprocessor lines, and
+				#  3) labels.
+				if ($continuation ||
+				    $s =~ /^\s*?\n/ ||
+				    $s =~ /^\s*#\s*?/ ||
+				    $s =~ /^\s*$Ident\s*:/) {
+					$continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+					if ($s =~ s/^.*?\n//) {
+						$cond_lines++;
+					}
+				}
+			}
+
+			my (undef, $sindent) = line_stats("+" . $s);
+			my $stat_real = raw_line($linenr, $cond_lines);
+
+			# Check if either of these lines are modified, else
+			# this is not this patch's fault.
+			if (!defined($stat_real) ||
+			    $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+				$check = 0;
+			}
+			if (defined($stat_real) && $cond_lines > 1) {
+				$stat_real = "[...]\n$stat_real";
+			}
+
+			#print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+			if ($check && (($sindent % 8) != 0 ||
+			    ($sindent <= $indent && $s ne ''))) {
+				WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+			}
+		}
+
+		# Track the 'values' across context and added lines.
+		my $opline = $line; $opline =~ s/^./ /;
+		my ($curr_values, $curr_vars) =
+				annotate_values($opline . "\n", $prev_values);
+		$curr_values = $prev_values . $curr_values;
+		if ($dbg_values) {
+			my $outline = $opline; $outline =~ s/\t/ /g;
+			print "$linenr > .$outline\n";
+			print "$linenr > $curr_values\n";
+			print "$linenr >  $curr_vars\n";
+		}
+		$prev_values = substr($curr_values, -1);
+
+#ignore lines not being added
+		if ($line=~/^[^\+]/) {next;}
+
+# TEST: allow direct testing of the type matcher.
+		if ($dbg_type) {
+			if ($line =~ /^.\s*$Declare\s*$/) {
+				ERROR("TEST: is type\n" . $herecurr);
+			} elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
+				ERROR("TEST: is not type ($1 is)\n". $herecurr);
+			}
+			next;
+		}
+# TEST: allow direct testing of the attribute matcher.
+		if ($dbg_attr) {
+			if ($line =~ /^.\s*$Modifier\s*$/) {
+				ERROR("TEST: is attr\n" . $herecurr);
+			} elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
+				ERROR("TEST: is not attr ($1 is)\n". $herecurr);
+			}
+			next;
+		}
+
+# check for initialisation to aggregates open brace on the next line
+		if ($line =~ /^.\s*{/ &&
+		    $prevline =~ /(?:^|[^=])=\s*$/) {
+			ERROR("that open brace { should be on the previous line\n" . $hereprev);
+		}
+
+#
+# Checks which are anchored on the added line.
+#
+
+# check for malformed paths in #include statements (uses RAW line)
+		if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
+			my $path = $1;
+			if ($path =~ m{//}) {
+				ERROR("malformed #include filename\n" .
+					$herecurr);
+			}
+		}
+
+# no C99 // comments
+		if ($line =~ m{//}) {
+			ERROR("do not use C99 // comments\n" . $herecurr);
+		}
+		# Remove C99 comments.
+		$line =~ s@//.*@@;
+		$opline =~ s@//.*@@;
+
+# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
+# the whole statement.
+#print "APW <$lines[$realline_next - 1]>\n";
+		if (defined $realline_next &&
+		    exists $lines[$realline_next - 1] &&
+		    !defined $suppress_export{$realline_next} &&
+		    ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+		     $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+			my $name = $1;
+			if ($stat !~ /(?:
+				\n.}\s*$|
+				^.DEFINE_$Ident\(\Q$name\E\)|
+				^.DECLARE_$Ident\(\Q$name\E\)|
+				^.LIST_HEAD\(\Q$name\E\)|
+				^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+				\b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\()
+			    )/x) {
+#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n";
+				$suppress_export{$realline_next} = 2;
+			} else {
+				$suppress_export{$realline_next} = 1;
+			}
+		}
+		if (!defined $suppress_export{$linenr} &&
+		    $prevline =~ /^.\s*$/ &&
+		    ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+		     $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+#print "FOO B <$lines[$linenr - 1]>\n";
+			$suppress_export{$linenr} = 2;
+		}
+		if (defined $suppress_export{$linenr} &&
+		    $suppress_export{$linenr} == 2) {
+			WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
+		}
+
+# check for external initialisers.
+		if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
+			ERROR("do not initialise externals to 0 or NULL\n" .
+				$herecurr);
+		}
+# check for static initialisers.
+		if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
+			ERROR("do not initialise statics to 0 or NULL\n" .
+				$herecurr);
+		}
+
+# check for new typedefs, only function parameters and sparse annotations
+# make sense.
+		if ($line =~ /\btypedef\s/ &&
+		    $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
+		    $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
+		    $line !~ /\b$typeTypedefs\b/ &&
+		    $line !~ /\b__bitwise(?:__|)\b/) {
+			WARN("do not add new typedefs\n" . $herecurr);
+		}
+
+# * goes on variable not on type
+		# (char*[ const])
+		if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) {
+			my ($from, $to) = ($1, $1);
+
+			# Should start with a space.
+			$to =~ s/^(\S)/ $1/;
+			# Should not end with a space.
+			$to =~ s/\s+$//;
+			# '*'s should not have spaces between.
+			while ($to =~ s/\*\s+\*/\*\*/) {
+			}
+
+			#print "from<$from> to<$to>\n";
+			if ($from ne $to) {
+				ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" .  $herecurr);
+			}
+		} elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) {
+			my ($from, $to, $ident) = ($1, $1, $2);
+
+			# Should start with a space.
+			$to =~ s/^(\S)/ $1/;
+			# Should not end with a space.
+			$to =~ s/\s+$//;
+			# '*'s should not have spaces between.
+			while ($to =~ s/\*\s+\*/\*\*/) {
+			}
+			# Modifiers should have spaces.
+			$to =~ s/(\b$Modifier$)/$1 /;
+
+			#print "from<$from> to<$to> ident<$ident>\n";
+			if ($from ne $to && $ident !~ /^$Modifier$/) {
+				ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" .  $herecurr);
+			}
+		}
+
+# # no BUG() or BUG_ON()
+# 		if ($line =~ /\b(BUG|BUG_ON)\b/) {
+# 			print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n";
+# 			print "$herecurr";
+# 			$clean = 0;
+# 		}
+
+		if ($line =~ /\bLINUX_VERSION_CODE\b/) {
+			WARN("LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
+		}
+
+# printk should use KERN_* levels.  Note that follow on printk's on the
+# same line do not need a level, so we use the current block context
+# to try and find and validate the current printk.  In summary the current
+# printk includes all preceeding printk's which have no newline on the end.
+# we assume the first bad printk is the one to report.
+		if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
+			my $ok = 0;
+			for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
+				#print "CHECK<$lines[$ln - 1]\n";
+				# we have a preceeding printk if it ends
+				# with "\n" ignore it, else it is to blame
+				if ($lines[$ln - 1] =~ m{\bprintk\(}) {
+					if ($rawlines[$ln - 1] !~ m{\\n"}) {
+						$ok = 1;
+					}
+					last;
+				}
+			}
+			if ($ok == 0) {
+				WARN("printk() should include KERN_ facility level\n" . $herecurr);
+			}
+		}
+
+# function brace can't be on same line, except for #defines of do while,
+# or if closed on same line
+		if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and
+		    !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) {
+			ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr);
+		}
+
+# open braces for enum, union and struct go on the same line.
+		if ($line =~ /^.\s*{/ &&
+		    $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
+			ERROR("open brace '{' following $1 go on the same line\n" . $hereprev);
+		}
+
+# check for spacing round square brackets; allowed:
+#  1. with a type on the left -- int [] a;
+#  2.@the beginning of a line for slice initialisers -- [0...10] = 5,
+#  3. inside a curly brace -- = { [0...10] = 5 }
+		while ($line =~ /(.*?\s)\[/g) {
+			my ($where, $prefix) = ($-[1], $1);
+			if ($prefix !~ /$Type\s+$/ &&
+			    ($where != 0 || $prefix !~ /^.\s+$/) &&
+			    $prefix !~ /{\s+$/) {
+				ERROR("space prohibited before open square bracket '['\n" . $herecurr);
+			}
+		}
+
+# check for spaces between functions and their parentheses.
+		while ($line =~ /($Ident)\s+\(/g) {
+			my $name = $1;
+			my $ctx_before = substr($line, 0, $-[1]);
+			my $ctx = "$ctx_before$name";
+
+			# Ignore those directives where spaces _are_ permitted.
+			if ($name =~ /^(?:
+				if|for|while|switch|return|case|
+				volatile|__volatile__|
+				__attribute__|format|__extension__|
+				asm|__asm__)$/x)
+			{
+
+			# cpp #define statements have non-optional spaces, ie
+			# if there is a space between the name and the open
+			# parenthesis it is simply not a parameter group.
+			} elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) {
+
+			# cpp #elif statement condition may start with a (
+			} elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) {
+
+			# If this whole things ends with a type its most
+			# likely a typedef for a function.
+			} elsif ($ctx =~ /$Type$/) {
+
+			} else {
+				WARN("space prohibited between function name and open parenthesis '('\n" . $herecurr);
+			}
+		}
+# Check operator spacing.
+		if (!($line=~/\#\s*include/)) {
+			my $ops = qr{
+				<<=|>>=|<=|>=|==|!=|
+				\+=|-=|\*=|\/=|%=|\^=|\|=|&=|
+				=>|->|<<|>>|<|>|=|!|~|
+				&&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%|
+				\?|:
+			}x;
+			my @elements = split(/($ops|;)/, $opline);
+			my $off = 0;
+
+			my $blank = copy_spacing($opline);
+
+			for (my $n = 0; $n < $#elements; $n += 2) {
+				$off += length($elements[$n]);
+
+				# Pick up the preceeding and succeeding characters.
+				my $ca = substr($opline, 0, $off);
+				my $cc = '';
+				if (length($opline) >= ($off + length($elements[$n + 1]))) {
+					$cc = substr($opline, $off + length($elements[$n + 1]));
+				}
+				my $cb = "$ca$;$cc";
+
+				my $a = '';
+				$a = 'V' if ($elements[$n] ne '');
+				$a = 'W' if ($elements[$n] =~ /\s$/);
+				$a = 'C' if ($elements[$n] =~ /$;$/);
+				$a = 'B' if ($elements[$n] =~ /(\[|\()$/);
+				$a = 'O' if ($elements[$n] eq '');
+				$a = 'E' if ($ca =~ /^\s*$/);
+
+				my $op = $elements[$n + 1];
+
+				my $c = '';
+				if (defined $elements[$n + 2]) {
+					$c = 'V' if ($elements[$n + 2] ne '');
+					$c = 'W' if ($elements[$n + 2] =~ /^\s/);
+					$c = 'C' if ($elements[$n + 2] =~ /^$;/);
+					$c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
+					$c = 'O' if ($elements[$n + 2] eq '');
+					$c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/);
+				} else {
+					$c = 'E';
+				}
+
+				my $ctx = "${a}x${c}";
+
+				my $at = "(ctx:$ctx)";
+
+				my $ptr = substr($blank, 0, $off) . "^";
+				my $hereptr = "$hereline$ptr\n";
+
+				# Pull out the value of this operator.
+				my $op_type = substr($curr_values, $off + 1, 1);
+
+				# Get the full operator variant.
+				my $opv = $op . substr($curr_vars, $off, 1);
+
+				# Ignore operators passed as parameters.
+				if ($op_type ne 'V' &&
+				    $ca =~ /\s$/ && $cc =~ /^\s*,/) {
+
+#				# Ignore comments
+#				} elsif ($op =~ /^$;+$/) {
+
+				# ; should have either the end of line or a space or \ after it
+				} elsif ($op eq ';') {
+					if ($ctx !~ /.x[WEBC]/ &&
+					    $cc !~ /^\\/ && $cc !~ /^;/) {
+						ERROR("space required after that '$op' $at\n" . $hereptr);
+					}
+
+				# // is a comment
+				} elsif ($op eq '//') {
+
+				# No spaces for:
+				#   ->
+				#   :   when part of a bitfield
+				} elsif ($op eq '->' || $opv eq ':B') {
+					if ($ctx =~ /Wx.|.xW/) {
+						ERROR("spaces prohibited around that '$op' $at\n" . $hereptr);
+					}
+
+				# , must have a space on the right.
+				} elsif ($op eq ',') {
+					if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
+						ERROR("space required after that '$op' $at\n" . $hereptr);
+					}
+
+				# '*' as part of a type definition -- reported already.
+				} elsif ($opv eq '*_') {
+					#warn "'*' is part of type\n";
+
+				# unary operators should have a space before and
+				# none after.  May be left adjacent to another
+				# unary operator, or a cast
+				} elsif ($op eq '!' || $op eq '~' ||
+					 $opv eq '*U' || $opv eq '-U' ||
+					 $opv eq '&U' || $opv eq '&&U') {
+					if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
+						ERROR("space required before that '$op' $at\n" . $hereptr);
+					}
+					if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
+						# A unary '*' may be const
+
+					} elsif ($ctx =~ /.xW/) {
+						ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+					}
+
+				# unary ++ and unary -- are allowed no space on one side.
+				} elsif ($op eq '++' or $op eq '--') {
+					if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
+						ERROR("space required one side of that '$op' $at\n" . $hereptr);
+					}
+					if ($ctx =~ /Wx[BE]/ ||
+					    ($ctx =~ /Wx./ && $cc =~ /^;/)) {
+						ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+					}
+					if ($ctx =~ /ExW/) {
+						ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+					}
+
+
+				# << and >> may either have or not have spaces both sides
+				} elsif ($op eq '<<' or $op eq '>>' or
+					 $op eq '&' or $op eq '^' or $op eq '|' or
+					 $op eq '+' or $op eq '-' or
+					 $op eq '*' or $op eq '/' or
+					 $op eq '%')
+				{
+					if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
+						ERROR("need consistent spacing around '$op' $at\n" .
+							$hereptr);
+					}
+
+				# A colon needs no spaces before when it is
+				# terminating a case value or a label.
+				} elsif ($opv eq ':C' || $opv eq ':L') {
+					if ($ctx =~ /Wx./) {
+						ERROR("space prohibited before that '$op' $at\n" . $hereptr);
+					}
+
+				# All the others need spaces both sides.
+				} elsif ($ctx !~ /[EWC]x[CWE]/) {
+					my $ok = 0;
+
+					# Ignore email addresses <foo@bar>
+					if (($op eq '<' &&
+					     $cc =~ /^\S+\@\S+>/) ||
+					    ($op eq '>' &&
+					     $ca =~ /<\S+\@\S+$/))
+					{
+						$ok = 1;
+					}
+
+					# Ignore ?:
+					if (($opv eq ':O' && $ca =~ /\?$/) ||
+					    ($op eq '?' && $cc =~ /^:/)) {
+						$ok = 1;
+					}
+
+					if ($ok == 0) {
+						ERROR("spaces required around that '$op' $at\n" . $hereptr);
+					}
+				}
+				$off += length($elements[$n + 1]);
+			}
+		}
+
+# check for multiple assignments
+		if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
+			CHK("multiple assignments should be avoided\n" . $herecurr);
+		}
+
+## # check for multiple declarations, allowing for a function declaration
+## # continuation.
+## 		if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
+## 		    $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
+##
+## 			# Remove any bracketed sections to ensure we do not
+## 			# falsly report the parameters of functions.
+## 			my $ln = $line;
+## 			while ($ln =~ s/\([^\(\)]*\)//g) {
+## 			}
+## 			if ($ln =~ /,/) {
+## 				WARN("declaring multiple variables together should be avoided\n" . $herecurr);
+## 			}
+## 		}
+
+#need space before brace following if, while, etc
+		if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) ||
+		    $line =~ /do{/) {
+			ERROR("space required before the open brace '{'\n" . $herecurr);
+		}
+
+# closing brace should have a space following it when it has anything
+# on the line
+		if ($line =~ /}(?!(?:,|;|\)))\S/) {
+			ERROR("space required after that close brace '}'\n" . $herecurr);
+		}
+
+# check spacing on square brackets
+		if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
+			ERROR("space prohibited after that open square bracket '['\n" . $herecurr);
+		}
+		if ($line =~ /\s\]/) {
+			ERROR("space prohibited before that close square bracket ']'\n" . $herecurr);
+		}
+
+# check spacing on parentheses
+		if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
+		    $line !~ /for\s*\(\s+;/) {
+			ERROR("space prohibited after that open parenthesis '('\n" . $herecurr);
+		}
+		if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
+		    $line !~ /for\s*\(.*;\s+\)/ &&
+		    $line !~ /:\s+\)/) {
+			ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr);
+		}
+
+#goto labels aren't indented, allow a single space however
+		if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
+		   !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
+			WARN("labels should not be indented\n" . $herecurr);
+		}
+
+# Return is not a function.
+		if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
+			my $spacing = $1;
+			my $value = $2;
+
+			# Flatten any parentheses
+			$value =~ s/\)\(/\) \(/g;
+			while ($value =~ s/\[[^\{\}]*\]/1/ ||
+			       $value !~ /(?:$Ident|-?$Constant)\s*
+					     $Compare\s*
+					     (?:$Ident|-?$Constant)/x &&
+			       $value =~ s/\([^\(\)]*\)/1/) {
+			}
+
+			if ($value =~ /^(?:$Ident|-?$Constant)$/) {
+				ERROR("return is not a function, parentheses are not required\n" . $herecurr);
+
+			} elsif ($spacing !~ /\s+/) {
+				ERROR("space required before the open parenthesis '('\n" . $herecurr);
+			}
+		}
+
+# Need a space before open parenthesis after if, while etc
+		if ($line=~/\b(if|while|for|switch)\(/) {
+			ERROR("space required before the open parenthesis '('\n" . $herecurr);
+		}
+
+# Check for illegal assignment in if conditional -- and check for trailing
+# statements after the conditional.
+		if ($line =~ /do\s*(?!{)/) {
+			my ($stat_next) = ctx_statement_block($line_nr_next,
+						$remain_next, $off_next);
+			$stat_next =~ s/\n./\n /g;
+			##print "stat<$stat> stat_next<$stat_next>\n";
+
+			if ($stat_next =~ /^\s*while\b/) {
+				# If the statement carries leading newlines,
+				# then count those as offsets.
+				my ($whitespace) =
+					($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+				my $offset =
+					statement_rawlines($whitespace) - 1;
+
+				$suppress_whiletrailers{$line_nr_next +
+								$offset} = 1;
+			}
+		}
+		if (!defined $suppress_whiletrailers{$linenr} &&
+		    $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
+			my ($s, $c) = ($stat, $cond);
+
+			if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
+				ERROR("do not use assignment in if condition\n" . $herecurr);
+			}
+
+			# Find out what is on the end of the line after the
+			# conditional.
+			substr($s, 0, length($c), '');
+			$s =~ s/\n.*//g;
+			$s =~ s/$;//g; 	# Remove any comments
+			if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
+			    $c !~ /}\s*while\s*/)
+			{
+				# Find out how long the conditional actually is.
+				my @newlines = ($c =~ /\n/gs);
+				my $cond_lines = 1 + $#newlines;
+				my $stat_real = '';
+
+				$stat_real = raw_line($linenr, $cond_lines)
+							. "\n" if ($cond_lines);
+				if (defined($stat_real) && $cond_lines > 1) {
+					$stat_real = "[...]\n$stat_real";
+				}
+
+				ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real);
+			}
+		}
+
+# Check for bitwise tests written as boolean
+		if ($line =~ /
+			(?:
+				(?:\[|\(|\&\&|\|\|)
+				\s*0[xX][0-9]+\s*
+				(?:\&\&|\|\|)
+			|
+				(?:\&\&|\|\|)
+				\s*0[xX][0-9]+\s*
+				(?:\&\&|\|\||\)|\])
+			)/x)
+		{
+			WARN("boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
+		}
+
+# if and else should not have general statements after it
+		if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
+			my $s = $1;
+			$s =~ s/$;//g; 	# Remove any comments
+			if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
+				ERROR("trailing statements should be on next line\n" . $herecurr);
+			}
+		}
+# if should not continue a brace
+		if ($line =~ /}\s*if\b/) {
+			ERROR("trailing statements should be on next line\n" .
+				$herecurr);
+		}
+# case and default should not have general statements after them
+		if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+		    $line !~ /\G(?:
+			(?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+			\s*return\s+
+		    )/xg)
+		{
+			ERROR("trailing statements should be on next line\n" . $herecurr);
+		}
+
+		# Check for }<nl>else {, these must be at the same
+		# indent level to be relevant to each other.
+		if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
+						$previndent == $indent) {
+			ERROR("else should follow close brace '}'\n" . $hereprev);
+		}
+
+		if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and
+						$previndent == $indent) {
+			my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
+
+			# Find out what is on the end of the line after the
+			# conditional.
+			substr($s, 0, length($c), '');
+			$s =~ s/\n.*//g;
+
+			if ($s =~ /^\s*;/) {
+				ERROR("while should follow close brace '}'\n" . $hereprev);
+			}
+		}
+
+#studly caps, commented out until figure out how to distinguish between use of existing and adding new
+#		if (($line=~/[\w_][a-z\d]+[A-Z]/) and !($line=~/print/)) {
+#		    print "No studly caps, use _\n";
+#		    print "$herecurr";
+#		    $clean = 0;
+#		}
+
+#no spaces allowed after \ in define
+		if ($line=~/\#\s*define.*\\\s$/) {
+			WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr);
+		}
+
+#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
+		if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
+			my $file = "$1.h";
+			my $checkfile = "include/linux/$file";
+			if (-f "$root/$checkfile" &&
+			    $realfile ne $checkfile &&
+			    $1 ne 'irq')
+			{
+				if ($realfile =~ m{^arch/}) {
+					CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+				} else {
+					WARN("Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+				}
+			}
+		}
+
+# multi-statement macros should be enclosed in a do while loop, grab the
+# first statement and ensure its the whole macro if its not enclosed
+# in a known good container
+		if ($realfile !~ m@/vmlinux.lds.h$@ &&
+		    $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
+			my $ln = $linenr;
+			my $cnt = $realcnt;
+			my ($off, $dstat, $dcond, $rest);
+			my $ctx = '';
+
+			my $args = defined($1);
+
+			# Find the end of the macro and limit our statement
+			# search to that.
+			while ($cnt > 0 && defined $lines[$ln - 1] &&
+				$lines[$ln - 1] =~ /^(?:-|..*\\$)/)
+			{
+				$ctx .= $rawlines[$ln - 1] . "\n";
+				$cnt-- if ($lines[$ln - 1] !~ /^-/);
+				$ln++;
+			}
+			$ctx .= $rawlines[$ln - 1];
+
+			($dstat, $dcond, $ln, $cnt, $off) =
+				ctx_statement_block($linenr, $ln - $linenr + 1, 0);
+			#print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
+			#print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
+
+			# Extract the remainder of the define (if any) and
+			# rip off surrounding spaces, and trailing \'s.
+			$rest = '';
+			while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) {
+				#print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n";
+				if ($off != 0 || $lines[$ln - 1] !~ /^-/) {
+					$rest .= substr($lines[$ln - 1], $off) . "\n";
+					$cnt--;
+				}
+				$ln++;
+				$off = 0;
+			}
+			$rest =~ s/\\\n.//g;
+			$rest =~ s/^\s*//s;
+			$rest =~ s/\s*$//s;
+
+			# Clean up the original statement.
+			if ($args) {
+				substr($dstat, 0, length($dcond), '');
+			} else {
+				$dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//;
+			}
+			$dstat =~ s/$;//g;
+			$dstat =~ s/\\\n.//g;
+			$dstat =~ s/^\s*//s;
+			$dstat =~ s/\s*$//s;
+
+			# Flatten any parentheses and braces
+			while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+			       $dstat =~ s/\{[^\{\}]*\}/1/ ||
+			       $dstat =~ s/\[[^\{\}]*\]/1/)
+			{
+			}
+
+			my $exceptions = qr{
+				$Declare|
+				module_param_named|
+				MODULE_PARAM_DESC|
+				DECLARE_PER_CPU|
+				DEFINE_PER_CPU|
+				__typeof__\(|
+				union|
+				struct|
+				\.$Ident\s*=\s*|
+				^\"|\"$
+			}x;
+			#print "REST<$rest> dstat<$dstat>\n";
+			if ($rest ne '') {
+				if ($rest !~ /while\s*\(/ &&
+				    $dstat !~ /$exceptions/)
+				{
+					ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
+				}
+
+			} elsif ($ctx !~ /;/) {
+				if ($dstat ne '' &&
+				    $dstat !~ /^(?:$Ident|-?$Constant)$/ &&
+				    $dstat !~ /$exceptions/ &&
+				    $dstat !~ /^\.$Ident\s*=/ &&
+				    $dstat =~ /$Operators/)
+				{
+					ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
+				}
+			}
+		}
+
+# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
+# all assignments may have only one of the following with an assignment:
+#	.
+#	ALIGN(...)
+#	VMLINUX_SYMBOL(...)
+		if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
+			WARN("vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
+		}
+
+# check for redundant bracing round if etc
+		if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
+			my ($level, $endln, @chunks) =
+				ctx_statement_full($linenr, $realcnt, 1);
+			#print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
+			#print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+			if ($#chunks > 0 && $level == 0) {
+				my $allowed = 0;
+				my $seen = 0;
+				my $herectx = $here . "\n";
+				my $ln = $linenr - 1;
+				for my $chunk (@chunks) {
+					my ($cond, $block) = @{$chunk};
+
+					# If the condition carries leading newlines, then count those as offsets.
+					my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
+					my $offset = statement_rawlines($whitespace) - 1;
+
+					#print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
+
+					# We have looked at and allowed this specific line.
+					$suppress_ifbraces{$ln + $offset} = 1;
+
+					$herectx .= "$rawlines[$ln + $offset]\n[...]\n";
+					$ln += statement_rawlines($block) - 1;
+
+					substr($block, 0, length($cond), '');
+
+					$seen++ if ($block =~ /^\s*{/);
+
+					#print "cond<$cond> block<$block> allowed<$allowed>\n";
+					if (statement_lines($cond) > 1) {
+						#print "APW: ALLOWED: cond<$cond>\n";
+						$allowed = 1;
+					}
+					if ($block =~/\b(?:if|for|while)\b/) {
+						#print "APW: ALLOWED: block<$block>\n";
+						$allowed = 1;
+					}
+					if (statement_block_size($block) > 1) {
+						#print "APW: ALLOWED: lines block<$block>\n";
+						$allowed = 1;
+					}
+				}
+				if ($seen && !$allowed) {
+					WARN("braces {} are not necessary for any arm of this statement\n" . $herectx);
+				}
+			}
+		}
+		if (!defined $suppress_ifbraces{$linenr - 1} &&
+					$line =~ /\b(if|while|for|else)\b/) {
+			my $allowed = 0;
+
+			# Check the pre-context.
+			if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+				#print "APW: ALLOWED: pre<$1>\n";
+				$allowed = 1;
+			}
+
+			my ($level, $endln, @chunks) =
+				ctx_statement_full($linenr, $realcnt, $-[0]);
+
+			# Check the condition.
+			my ($cond, $block) = @{$chunks[0]};
+			#print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+			if (defined $cond) {
+				substr($block, 0, length($cond), '');
+			}
+			if (statement_lines($cond) > 1) {
+				#print "APW: ALLOWED: cond<$cond>\n";
+				$allowed = 1;
+			}
+			if ($block =~/\b(?:if|for|while)\b/) {
+				#print "APW: ALLOWED: block<$block>\n";
+				$allowed = 1;
+			}
+			if (statement_block_size($block) > 1) {
+				#print "APW: ALLOWED: lines block<$block>\n";
+				$allowed = 1;
+			}
+			# Check the post-context.
+			if (defined $chunks[1]) {
+				my ($cond, $block) = @{$chunks[1]};
+				if (defined $cond) {
+					substr($block, 0, length($cond), '');
+				}
+				if ($block =~ /^\s*\{/) {
+					#print "APW: ALLOWED: chunk-1 block<$block>\n";
+					$allowed = 1;
+				}
+			}
+			if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
+				my $herectx = $here . "\n";;
+				my $cnt = statement_rawlines($block);
+
+				for (my $n = 0; $n < $cnt; $n++) {
+					$herectx .= raw_line($linenr, $n) . "\n";;
+				}
+
+				WARN("braces {} are not necessary for single statement blocks\n" . $herectx);
+			}
+		}
+
+# don't include deprecated include files (uses RAW line)
+		for my $inc (@dep_includes) {
+			if ($rawline =~ m@^.\s*\#\s*include\s*\<$inc>@) {
+				ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr);
+			}
+		}
+
+# don't use deprecated functions
+		for my $func (@dep_functions) {
+			if ($line =~ /\b$func\b/) {
+				ERROR("Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr);
+			}
+		}
+
+# no volatiles please
+		my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
+		if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
+			WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
+		}
+
+# SPIN_LOCK_UNLOCKED & RW_LOCK_UNLOCKED are deprecated
+		if ($line =~ /\b(SPIN_LOCK_UNLOCKED|RW_LOCK_UNLOCKED)/) {
+			ERROR("Use of $1 is deprecated: see Documentation/spinlocks.txt\n" . $herecurr);
+		}
+
+# warn about #if 0
+		if ($line =~ /^.\s*\#\s*if\s+0\b/) {
+			CHK("if this code is redundant consider removing it\n" .
+				$herecurr);
+		}
+
+# check for needless kfree() checks
+		if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+			my $expr = $1;
+			if ($line =~ /\bkfree\(\Q$expr\E\);/) {
+				WARN("kfree(NULL) is safe this check is probably not required\n" . $hereprev);
+			}
+		}
+# check for needless usb_free_urb() checks
+		if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+			my $expr = $1;
+			if ($line =~ /\busb_free_urb\(\Q$expr\E\);/) {
+				WARN("usb_free_urb(NULL) is safe this check is probably not required\n" . $hereprev);
+			}
+		}
+
+# warn about #ifdefs in C files
+#		if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
+#			print "#ifdef in C files should be avoided\n";
+#			print "$herecurr";
+#			$clean = 0;
+#		}
+
+# warn about spacing in #ifdefs
+		if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
+			ERROR("exactly one space required after that #$1\n" . $herecurr);
+		}
+
+# check for spinlock_t definitions without a comment.
+		if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
+		    $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
+			my $which = $1;
+			if (!ctx_has_comment($first_line, $linenr)) {
+				CHK("$1 definition without comment\n" . $herecurr);
+			}
+		}
+# check for memory barriers without a comment.
+		if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+			if (!ctx_has_comment($first_line, $linenr)) {
+				CHK("memory barrier without comment\n" . $herecurr);
+			}
+		}
+# check of hardware specific defines
+		if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m(a)include/asm-@) {
+			CHK("architecture specific defines should be avoided\n" .  $herecurr);
+		}
+
+# check the location of the inline attribute, that it is between
+# storage class and type.
+		if ($line =~ /\b$Type\s+$Inline\b/ ||
+		    $line =~ /\b$Inline\s+$Storage\b/) {
+			ERROR("inline keyword should sit between storage class and type\n" . $herecurr);
+		}
+
+# Check for __inline__ and __inline, prefer inline
+		if ($line =~ /\b(__inline__|__inline)\b/) {
+			WARN("plain inline is preferred over $1\n" . $herecurr);
+		}
+
+# check for sizeof(&)
+		if ($line =~ /\bsizeof\s*\(\s*\&/) {
+			WARN("sizeof(& should be avoided\n" . $herecurr);
+		}
+
+# check for new externs in .c files.
+		if ($realfile =~ /\.c$/ && defined $stat &&
+		    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
+		{
+			my $function_name = $1;
+			my $paren_space = $2;
+
+			my $s = $stat;
+			if (defined $cond) {
+				substr($s, 0, length($cond), '');
+			}
+			if ($s =~ /^\s*;/ &&
+			    $function_name ne 'uninitialized_var')
+			{
+				WARN("externs should be avoided in .c files\n" .  $herecurr);
+			}
+
+			if ($paren_space =~ /\n/) {
+				WARN("arguments for function declarations should follow identifier\n" . $herecurr);
+			}
+
+		} elsif ($realfile =~ /\.c$/ && defined $stat &&
+		    $stat =~ /^.\s*extern\s+/)
+		{
+			WARN("externs should be avoided in .c files\n" .  $herecurr);
+		}
+
+# checks for new __setup's
+		if ($rawline =~ /\b__setup\("([^"]*)"/) {
+			my $name = $1;
+
+			if (!grep(/$name/, @setup_docs)) {
+				CHK("__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
+			}
+		}
+
+# check for pointless casting of kmalloc return
+		if ($line =~ /\*\s*\)\s*k[czm]alloc\b/) {
+			WARN("unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
+		}
+
+# check for gcc specific __FUNCTION__
+		if ($line =~ /__FUNCTION__/) {
+			WARN("__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
+		}
+
+# check for semaphores used as mutexes
+		if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
+			WARN("mutexes are preferred for single holder semaphores\n" . $herecurr);
+		}
+# check for semaphores used as mutexes
+		if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) {
+			WARN("consider using a completion\n" . $herecurr);
+		}
+# recommend strict_strto* over simple_strto*
+		if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
+			WARN("consider using strict_$1 in preference to simple_$1\n" . $herecurr);
+		}
+# check for __initcall(), use device_initcall() explicitly please
+		if ($line =~ /^.\s*__initcall\s*\(/) {
+			WARN("please use device_initcall() instead of __initcall()\n" . $herecurr);
+		}
+# check for various ops structs, ensure they are const.
+		my $struct_ops = qr{acpi_dock_ops|
+				address_space_operations|
+				backlight_ops|
+				block_device_operations|
+				dentry_operations|
+				dev_pm_ops|
+				dma_map_ops|
+				extent_io_ops|
+				file_lock_operations|
+				file_operations|
+				hv_ops|
+				ide_dma_ops|
+				intel_dvo_dev_ops|
+				item_operations|
+				iwl_ops|
+				kgdb_arch|
+				kgdb_io|
+				kset_uevent_ops|
+				lock_manager_operations|
+				microcode_ops|
+				mtrr_ops|
+				neigh_ops|
+				nlmsvc_binding|
+				pci_raw_ops|
+				pipe_buf_operations|
+				platform_hibernation_ops|
+				platform_suspend_ops|
+				proto_ops|
+				rpc_pipe_ops|
+				seq_operations|
+				snd_ac97_build_ops|
+				soc_pcmcia_socket_ops|
+				stacktrace_ops|
+				sysfs_ops|
+				tty_operations|
+				usb_mon_operations|
+				wd_ops}x;
+		if ($line !~ /\bconst\b/ &&
+		    $line =~ /\bstruct\s+($struct_ops)\b/) {
+			WARN("struct $1 should normally be const\n" .
+				$herecurr);
+		}
+
+# use of NR_CPUS is usually wrong
+# ignore definitions of NR_CPUS and usage to define arrays as likely right
+		if ($line =~ /\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
+		    $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
+		    $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
+		    $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
+		{
+			WARN("usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
+		}
+
+# check for %L{u,d,i} in strings
+		my $string;
+		while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
+			$string = substr($rawline, $-[1], $+[1] - $-[1]);
+			$string =~ s/%%/__/g;
+			if ($string =~ /(?<!%)%L[udi]/) {
+				WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
+				last;
+			}
+		}
+
+# whine mightly about in_atomic
+		if ($line =~ /\bin_atomic\s*\(/) {
+			if ($realfile =~ m@^drivers/@) {
+				ERROR("do not use in_atomic in drivers\n" . $herecurr);
+			} elsif ($realfile !~ m@^kernel/@) {
+				WARN("use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
+			}
+		}
+	}
+
+	# If we have no input@all, then there is nothing to report on
+	# so just keep quiet.
+	if ($#rawlines == -1) {
+		exit(0);
+	}
+
+	# In mailback mode only produce a report in the negative, for
+	# things that appear to be patches.
+	if ($mailback && ($clean == 1 || !$is_patch)) {
+		exit(0);
+	}
+
+	# This is not a patch, and we are are in 'no-patch' mode so
+	# just keep quiet.
+	if (!$chk_patch && !$is_patch) {
+		exit(0);
+	}
+
+	if (!$is_patch) {
+		ERROR("Does not appear to be a unified-diff format patch\n");
+	}
+	if ($is_patch && $chk_signoff && $signoff == 0) {
+		ERROR("Missing Signed-off-by: line(s)\n");
+	}
+
+	print report_dump();
+	if ($summary && !($clean == 1 && $quiet == 1)) {
+		print "$filename " if ($summary_file);
+		print "total: $cnt_error errors, $cnt_warn warnings, " .
+			(($check)? "$cnt_chk checks, " : "") .
+			"$cnt_lines lines checked\n";
+		print "\n" if ($quiet == 0);
+	}
+
+	if ($clean == 1 && $quiet == 0) {
+		print "$vname has no obvious style problems and is ready for submission.\n"
+	}
+	if ($clean == 0 && $quiet == 0) {
+		print "$vname has style problems, please review.  If any of these errors\n";
+		print "are false positives report them to the maintainer, see\n";
+		print "CHECKPATCH in MAINTAINERS.\n";
+	}
+
+	return $clean;
+}
diff --git a/drivers/isimodem2.5/debug.c b/drivers/isimodem2.5/debug.c
new file mode 100644
index 0000000..14c538f
--- /dev/null
+++ b/drivers/isimodem2.5/debug.c
@@ -0,0 +1,694 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/log.h>
+
+#include "debug.h"
+
+#define _(X) case X: return #X
+
+const char *pn_resource_name(int value)
+{
+	switch (value) {
+		_(PN_MODEM_NETWORK);
+		_(PN_MODEM_INFO);
+		_(PN_SS);
+		_(PN_MODEM_CALL);
+		_(PN_SMS);
+		_(PN_UICC);
+		_(PN_MODEM_MCE);
+		_(PN_GSS);
+		_(PN_GPDS);
+	}
+	return "PN_<UNKNOWN>";
+}
+
+const char *ss_message_id_name(uint8_t value)
+{
+	switch (value) {
+		_(SS_SERVICE_REQ);
+		_(SS_SERVICE_COMPLETED_RESP);
+		_(SS_SERVICE_FAILED_RESP);
+		_(SS_SERVICE_NOT_SUPPORTED_RESP);
+		_(SS_GSM_USSD_SEND_REQ);
+		_(SS_GSM_USSD_SEND_RESP);
+		_(SS_GSM_USSD_RECEIVE_IND);
+		_(SS_STATUS_IND);
+		_(SS_SERVICE_COMPLETED_IND);
+		_(SS_CANCEL_REQ);
+		_(SS_CANCEL_RESP);
+		_(SS_RESOURCE_CONTROL_IND);
+		_(SS_RESOURCE_CONTROL_REQ);
+		_(SS_RESOURCE_CONTROL_RESP);
+		_(SS_RESOURCE_CONF_IND);
+		_(SS_RESOURCE_CONF_REQ);
+		_(SS_RESOURCE_CONF_RESP);
+	}
+	return "SS_<UNKNOWN>";
+}
+
+const char *ss_subblock_name(uint8_t value)
+{
+	switch (value) {
+		_(SS_GSM_BARRING_FEATURE);
+		_(SS_GSM_BARRING_INFO);
+		_(SS_GSM_CLIR_INFO);
+		_(SS_GSM_GENERIC_SERVICE_INFO);
+		_(SS_GSM_INDICATE_PROBLEM);
+		_(SS_GSM_INDICATE_MSG_ERROR);
+		_(SS_OTHER_ERROR);
+		_(SS_GSM_MM_RELEASED);
+		_(SS_SB_RESOURCE);
+		_(SS_SB_RESOURCE_SEQ_ID);
+		_(SS_SB_SS_CONTROL);
+		_(SS_SB_USSD_CONTROL);
+		_(SS_SB_RESOURCE_STATUS);
+		_(SS_SB_RESOURCE_CONTROL_INFO);
+		_(SS_SB_CHECK_INFO);
+		_(SS_SB_RESOURCE_CONF_REQUIRED);
+		_(SS_SB_RESOURCE_CONF);
+		_(SS_FORWARDING);
+		_(SS_STATUS_RESULT);
+		_(SS_GSM_PASSWORD);
+		_(SS_GSM_FORWARDING_INFO);
+		_(SS_GSM_FORWARDING_FEATURE);
+		_(SS_GSM_DATA);
+		_(SS_GSM_BSC_INFO);
+		_(SS_GSM_PASSWORD_INFO);
+		_(SS_GSM_INDICATE_PASSWORD_ERROR);
+		_(SS_GSM_INDICATE_ERROR);
+		_(SS_GSM_ADDITIONAL_INFO);
+		_(SS_GSM_USSD_STRING);
+	}
+	return "SS_<UNKNOWN>";
+}
+
+const char *ss_operation_name(uint8_t value)
+{
+	switch (value) {
+		_(SS_ACTIVATION);
+		_(SS_DEACTIVATION);
+		_(SS_REGISTRATION);
+		_(SS_ERASURE);
+		_(SS_INTERROGATION);
+		_(SS_GSM_PASSWORD_REGISTRATION);
+	}
+	return "SS_<UNKNOWN>";
+}
+
+const char *ss_ss_code_name(uint16_t value)
+{
+	switch (value) {
+		_(SS_GSM_ALL_SS);
+		_(SS_GSM_ALL_FORWARDINGS);
+		_(SS_GSM_ALL_COND_FORWARDINGS);
+		_(SS_GSM_FORW_UNCONDITIONAL);
+		_(SS_GSM_FORW_BUSY);
+		_(SS_GSM_FORW_NO_REPLY);
+		_(SS_GSM_FORW_NO_REACH);
+		_(SS_GSM_ALL_BARRINGS);
+		_(SS_GSM_BARR_ALL_OUT);
+		_(SS_GSM_BARR_OUT_INTER);
+		_(SS_GSM_BARR_OUT_INTER_EXC_HOME);
+		_(SS_GSM_BARR_ALL_IN);
+		_(SS_GSM_BARR_ALL_IN_ROAM);
+		_(SS_GSM_OUTGOING_BARR_SERV);
+		_(SS_GSM_INCOMING_BARR_SERV);
+		_(SS_GSM_CALL_WAITING);
+		_(SS_GSM_CLIP);
+		_(SS_GSM_CLIR);
+		_(SS_GSM_COLP);
+		_(SS_GSM_COLR);
+		_(SS_GSM_CNAP);
+		_(SS_GSM_ECT);
+	}
+	return "SS_<UNKNOWN>";
+}
+
+
+const char *mce_isi_cause_name(enum mce_status_info value)
+{
+	switch (value) {
+		_(MCE_OK);
+		_(MCE_FAIL);
+		_(MCE_ALREADY_ACTIVE);
+		_(MCE_TRANSITION_ONGOING);
+	}
+	return "MCE_<UNKNOWN>";
+}
+
+const char *mce_message_id_name(enum mce_message_id value)
+{
+	switch (value) {
+		_(MCE_MODEM_STATE_IND);
+		_(MCE_MODEM_STATE_QUERY_REQ);
+		_(MCE_MODEM_STATE_QUERY_RESP);
+		_(MCE_RF_STATE_REQ);
+		_(MCE_RF_STATE_RESP);
+		_(MCE_RF_STATE_IND);
+		_(MCE_RF_STATE_QUERY_REQ);
+		_(MCE_RF_STATE_QUERY_RESP);
+		_(MCE_POWER_OFF_REQ);
+		_(MCE_POWER_OFF_RESP);
+	}
+	return "MCE_<UNKNOWN>";
+}
+
+const char *mce_modem_state_name(enum mce_modem_state value)
+{
+	switch (value) {
+		_(MCE_NORMAL);
+		_(MCE_LOCAL);
+		_(MCE_SW_RESET);
+		_(MCE_POWER_OFF);
+	}
+	return "MCE_<UNKNOWN>";
+}
+
+const char *uicc_service_type_name(uint8_t value)
+{
+	switch (value) {
+		_(UICC_APPL_LIST);
+		_(UICC_APPL_HOST_ACTIVATE);
+		/*_(UICC_APPL_DEACTIVATE);*/
+		_(UICC_APPL_START_UP_COMPLETE);
+		/*_(UICC_SHUT_DOWN_INITIATED);*/
+		_(UICC_APPL_SHUT_DOWN_INITIATED);
+		_(UICC_APPL_STATUS_GET);
+		_(UICC_APPL_HOST_DEACTIVATE);
+		_(UICC_PIN_VERIFY);
+		_(UICC_PIN_UNBLOCK);
+		_(UICC_PIN_DISABLE);
+		_(UICC_PIN_ENABLE);
+		_(UICC_PIN_CHANGE);
+		_(UICC_PIN_SUBSTITUTE);
+		_(UICC_PIN_INFO);
+		_(UICC_PIN_PROMPT_VERIFY);
+		_(UICC_APPL_READ_TRANSPARENT);
+		_(UICC_APPL_UPDATE_TRANSPARENT);
+		_(UICC_APPL_READ_LINEAR_FIXED);
+		_(UICC_APPL_UPDATE_LINEAR_FIXED);
+		_(UICC_APPL_FILE_INFO);
+		_(UICC_APPL_APDU_SEND);
+		_(UICC_APPL_CLEAR_CACHE);
+		_(UICC_APPL_SESSION_START);
+		_(UICC_APPL_SESSION_END);
+		_(UICC_APPL_READ_CYCLIC);
+		_(UICC_APPL_UPDATE_CYCLIC);
+		/*_(UICC_APPL_CACHE_UPDATED);*/
+		_(UICC_CONNECT);
+		_(UICC_DISCONNECT);
+		_(UICC_RECONNECT);
+		_(UICC_CAT_ENABLE);
+		_(UICC_CAT_DISABLE);
+		_(UICC_CAT_TERMINAL_PROFILE);
+		_(UICC_CAT_TERMINAL_RESPONSE);
+		_(UICC_CAT_ENVELOPE);
+		_(UICC_CAT_POLLING_SET);
+		_(UICC_CAT_REFRESH);
+		_(UICC_CAT_POLL);
+		_(UICC_APDU_SEND);
+		_(UICC_APDU_ATR_GET);
+		_(UICC_APDU_CONTROL);
+		_(UICC_REFRESH_STATUS);
+		_(UICC_APPL_TERMINATED);
+		_(UICC_APPL_RECOVERED);
+		/*_(UICC_APPL_UNAVAILABLE);*/
+		/*_(UICC_APPL_SHUT_DOWN);*/
+		_(UICC_APPL_ACTIVATED);
+		_(UICC_PIN_VERIFY_NEEDED);
+		_(UICC_PIN_UNBLOCK_NEEDED);
+		_(UICC_PIN_PERMANENTLY_BLOCKED);
+		_(UICC_PIN_VERIFIED);
+		_(UICC_CAT_FETCHED_CMD);
+		_(UICC_CAT_NOT_SUPPORTED);
+		_(UICC_CAT_REG_FAILED);
+		_(UICC_CAT_REG_OK);
+		_(UICC_REFRESH_PERMISSION);
+		_(UICC_REFRESH_STARTING);
+		_(UICC_REFRESH_CANCELLED);
+		_(UICC_REFRESH_NOW);
+		_(UICC_START_UP_COMPLETE);
+		_(UICC_STATUS_GET);
+		_(UICC_READY);
+		/*_(UICC_READY_FOR_ACTIVATION);*/
+		_(UICC_INITIALIZED);
+		_(UICC_SHUTTING_DOWN);
+		/*_(UICC_SHUT_DOWN_CONFIG);*/
+		_(UICC_ERROR);
+		_(UICC_CARD_DISCONNECTED);
+		_(UICC_CARD_REMOVED);
+		_(UICC_CARD_NOT_PRESENT);
+		/*_(UICC_CARD_RESET);*/
+		_(UICC_CARD_READY);
+		_(UICC_CARD_STATUS_GET);
+		_(UICC_CARD_REJECTED);
+		_(UICC_CARD_INFO_GET);
+		_(UICC_SIMLOCK_ACTIVE);
+		_(UICC_APDU_SAP_ACTIVATE);
+		_(UICC_APDU_SAP_DEACTIVATE);
+		_(UICC_APDU_SAP_ATR_GET);
+		_(UICC_APDU_SAP_COLD_RESET);
+		_(UICC_APDU_SAP_WARM_RESET);
+		_(UICC_APDU_SAP_APDU_SEND);
+		_(UICC_APDU_SAP_RECOVERY);
+		_(UICC_APDU_SAP_CONFIG_GET);
+		_(UICC_PWR_CTRL_ENABLE);
+		_(UICC_PWR_CTRL_DISABLE);
+		_(UICC_PWR_CTRL_WAIT);
+		_(UICC_PWR_CTRL_PROCEED);
+		_(UICC_PWR_CTRL_PERMISSION);
+	}
+	return "UICC_SERVICE_<UNKNOWN>";
+}
+
+const char *uicc_status_name(uint8_t value)
+{
+	switch (value) {
+		/* Request performed successfully */
+		_(UICC_STATUS_OK);
+		/* Error in performing the command */
+		_(UICC_STATUS_FAIL);
+		/* Status is Unknown */
+		_(UICC_STATUS_UNKNOWN);
+		/* Server is not ready */
+		_(UICC_STATUS_NOT_READY);
+		/* Server start up is completed */
+		_(UICC_STATUS_START_UP_COMPLETED);
+		/* Server is shutting down */
+		_(UICC_STATUS_SHUTTING_DOWN);
+		/* Smart card is not ready */
+		_(UICC_STATUS_CARD_NOT_READY);
+		/* Smart card is ready */
+		_(UICC_STATUS_CARD_READY);
+		/* Smart card is disconnected */
+		_(UICC_STATUS_CARD_DISCONNECTED);
+		/* Smart card is not present */
+		_(UICC_STATUS_CARD_NOT_PRESENT);
+		/* Smart card has been rejected */
+		_(UICC_STATUS_CARD_REJECTED);
+		/* Application is active */
+		_(UICC_STATUS_APPL_ACTIVE);
+		/* Application is not active */
+		_(UICC_STATUS_APPL_NOT_ACTIVE);
+		/* PIN verification used */
+		_(UICC_STATUS_PIN_ENABLED);
+		/* PIN verification not used */
+		_(UICC_STATUS_PIN_DISABLED);
+	}
+	return "UICC_STATUS<UNKNOWN>";
+}
+const char *uicc_message_id_name(uint8_t value)
+{
+	switch (value) {
+		_(UICC_REQ);
+		_(UICC_RESP);
+		_(UICC_IND);
+		_(UICC_CARD_REQ);
+		_(UICC_CARD_RESP);
+		_(UICC_CARD_IND);
+		_(UICC_APPLICATION_REQ);
+		_(UICC_APPLICATION_RESP);
+		_(UICC_APPLICATION_IND);
+		_(UICC_PIN_REQ);
+		_(UICC_PIN_RESP);
+		_(UICC_PIN_IND);
+		_(UICC_APPL_CMD_REQ);
+		_(UICC_APPL_CMD_RESP);
+		_(UICC_APPL_CMD_IND);
+		_(UICC_CONNECTOR_REQ);
+		_(UICC_CONNECTOR_RESP);
+		_(UICC_CAT_REQ);
+		_(UICC_CAT_RESP);
+		_(UICC_CAT_IND);
+		_(UICC_APDU_REQ);
+		_(UICC_APDU_RESP);
+		_(UICC_APDU_RESET_IND);
+		_(UICC_REFRESH_REQ);
+		_(UICC_REFRESH_RESP);
+		_(UICC_REFRESH_IND);
+		_(UICC_SIMLOCK_REQ);
+		_(UICC_SIMLOCK_RESP);
+		_(UICC_APDU_SAP_REQ);
+		_(UICC_APDU_SAP_RESP);
+		_(UICC_APDU_SAP_IND);
+		_(UICC_PWR_CTRL_REQ);
+		_(UICC_PWR_CTRL_RESP);
+		_(UICC_PWR_CTRL_IND);
+	}
+	return "UICC_<UNKNOWN>";
+}
+
+const char *uicc_subblock_name(uint8_t value)
+{
+	switch (value) {
+		_(UICC_SB_SHUT_DOWN_CONFIG);
+		_(UICC_SB_CARD_STATUS);
+		_(UICC_SB_CARD_INFO);
+		_(UICC_SB_CARD_REJECT_CAUSE);
+		_(UICC_SB_CLIENT);
+		_(UICC_SB_APPL_DATA_OBJECT);
+		_(UICC_SB_APPLICATION);
+		_(UICC_SB_APPL_INFO);
+		_(UICC_SB_APPL_STATUS);
+		_(UICC_SB_FCP);
+		_(UICC_SB_FCI);
+		_(UICC_SB_CHV);
+		_(UICC_SB_PIN);
+		_(UICC_SB_PIN_REF);
+		_(UICC_SB_PUK);
+		_(UICC_SB_PIN_SUBST);
+		_(UICC_SB_PIN_INFO);
+		_(UICC_SB_APPL_PATH);
+		_(UICC_SB_SESSION);
+		_(UICC_SB_FILE_DATA);
+		_(UICC_SB_APDU);
+		_(UICC_SB_TRANSPARENT_READ);
+		_(UICC_SB_TRANSPARENT_UPDATE);
+		_(UICC_SB_TRANSPARENT);
+		_(UICC_SB_LINEAR_FIXED);
+		_(UICC_SB_CYCLIC);
+		_(UICC_SB_TERMINAL_PROFILE);
+		_(UICC_SB_TERMINAL_RESPONSE);
+		_(UICC_SB_ENVELOPE);
+		_(UICC_SB_POLLING_SET);
+		_(UICC_SB_REFRESH);
+		_(UICC_SB_AID);
+		_(UICC_SB_REFRESH_RESULT);
+		_(UICC_SB_APDU_ACTIONS);
+		_(UICC_SB_OBJECT_ID);
+		_(UICC_SB_STATUS_WORD);
+		_(UICC_SB_APDU_SAP_INFO);
+		_(UICC_SB_ACCESS_MODE);
+		_(UICC_SB_RESP_INFO);
+		_(UICC_SB_APDU_SAP_CONFIG);
+	}
+	return "SIM_<UNKNOWN>";
+}
+
+const char *net_gsm_cause_name(uint8_t value)
+{
+	switch (value) {
+		_(NET_GSM_IMSI_UNKNOWN_IN_HLR);
+		_(NET_GSM_ILLEGAL_MS);
+		_(NET_GSM_IMSI_UNKNOWN_IN_VLR);
+		_(NET_GSM_IMEI_NOT_ACCEPTED);
+		_(NET_GSM_ILLEGAL_ME);
+		_(NET_GSM_GPRS_SERVICES_NOT_ALLOWED);
+		_(NET_GSM_GPRS_AND_NON_GPRS_NA);
+		_(NET_GSM_MS_ID_CANNOT_BE_DERIVED);
+		_(NET_GSM_IMPLICITLY_DETACHED);
+		_(NET_GSM_PLMN_NOT_ALLOWED);
+		_(NET_GSM_LA_NOT_ALLOWED);
+		_(NET_GSM_ROAMING_NOT_IN_THIS_LA);
+		_(NET_GSM_GPRS_SERV_NA_IN_THIS_PLMN);
+		_(NET_GSM_NO_SUITABLE_CELLS_IN_LA);
+		_(NET_GSM_MSC_TEMP_NOT_REACHABLE);
+		_(NET_GSM_NETWORK_FAILURE);
+		_(NET_GSM_MAC_FAILURE);
+		_(NET_GSM_SYNCH_FAILURE);
+		_(NET_GSM_CONGESTION);
+		_(NET_GSM_AUTH_UNACCEPTABLE);
+		_(NET_GSM_SERV_OPT_NOT_SUPPORTED);
+		_(NET_GSM_SERV_OPT_NOT_SUBSCRIBED);
+		_(NET_GSM_SERV_TEMP_OUT_OF_ORDER);
+		_(NET_GSM_RETRY_ENTRY_NEW_CELL_LOW);
+		_(NET_GSM_RETRY_ENTRY_NEW_CELL_HIGH);
+		_(NET_GSM_SEMANTICALLY_INCORRECT);
+		_(NET_GSM_INVALID_MANDATORY_INFO);
+		_(NET_GSM_MSG_TYPE_NONEXISTENT);
+		_(NET_GSM_CONDITIONAL_IE_ERROR);
+		_(NET_GSM_MSG_TYPE_WRONG_STATE);
+		_(NET_GSM_PROTOCOL_ERROR_UNSPECIFIED);
+	}
+	return "NET_<UNKNOWN>";
+}
+
+const char *net_isi_cause_name(uint8_t value)
+{
+	switch (value) {
+		_(NET_CAUSE_OK);
+		_(NET_CAUSE_COMMUNICATION_ERROR);
+		_(NET_CAUSE_INVALID_PARAMETER);
+		_(NET_CAUSE_NO_SIM);
+		_(NET_CAUSE_SIM_NOT_YET_READY);
+		_(NET_CAUSE_NET_NOT_FOUND);
+		_(NET_CAUSE_REQUEST_NOT_ALLOWED);
+		_(NET_CAUSE_CALL_ACTIVE);
+		_(NET_CAUSE_SERVER_BUSY);
+		_(NET_CAUSE_SECURITY_CODE_REQUIRED);
+		_(NET_CAUSE_NOTHING_TO_CANCEL);
+		_(NET_CAUSE_UNABLE_TO_CANCEL);
+		_(NET_CAUSE_NETWORK_FORBIDDEN);
+		_(NET_CAUSE_REQUEST_REJECTED);
+		_(NET_CAUSE_CS_NOT_SUPPORTED);
+		_(NET_CAUSE_PAR_INFO_NOT_AVAILABLE);
+		_(NET_CAUSE_NOT_DONE);
+		_(NET_CAUSE_NO_SELECTED_NETWORK);
+		_(NET_CAUSE_REQUEST_INTERRUPTED);
+		_(NET_CAUSE_TOO_BIG_INDEX);
+		_(NET_CAUSE_MEMORY_FULL);
+		_(NET_CAUSE_SERVICE_NOT_ALLOWED);
+		_(NET_CAUSE_NOT_SUPPORTED_IN_TECH);
+	}
+	return "NET_<UNKNOWN>";
+}
+
+const char *net_status_name(uint8_t value)
+{
+	switch (value) {
+		_(NET_REG_STATUS_HOME);
+		_(NET_REG_STATUS_ROAM);
+		_(NET_REG_STATUS_NOSERV);
+		_(NET_REG_STATUS_NOSERV_SEARCHING);
+		_(NET_REG_STATUS_NOSERV_NOTSEARCHING);
+		_(NET_REG_STATUS_NOSERV_NOSIM);
+		_(NET_REG_STATUS_POWER_OFF);
+		_(NET_REG_STATUS_NSPS);
+		_(NET_REG_STATUS_NSPS_NO_COVERAGE);
+		_(NET_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW);
+	}
+	return "NET_<UNKNOWN>";
+}
+
+const char *net_message_id_name(uint8_t value)
+{
+	switch (value) {
+		_(NET_MODEM_REG_STATUS_GET_REQ);
+		_(NET_MODEM_REG_STATUS_GET_RESP);
+		_(NET_MODEM_REG_STATUS_IND);
+		_(NET_MODEM_AVAILABLE_GET_REQ);
+		_(NET_MODEM_AVAILABLE_GET_RESP);
+		_(NET_AVAILABLE_CANCEL_REQ);
+		_(NET_AVAILABLE_CANCEL_RESP);
+		_(NET_SET_REQ);
+		_(NET_SET_RESP);
+		_(NET_SET_CANCEL_REQ);
+		_(NET_SET_CANCEL_RESP);
+		_(NET_RSSI_GET_REQ);
+		_(NET_RSSI_GET_RESP);
+		_(NET_CS_CONTROL_REQ);
+		_(NET_CS_CONTROL_RESP);
+		_(NET_CS_WAKEUP_REQ);
+		_(NET_CS_WAKEUP_RESP);
+		_(NET_TEST_CARRIER_REQ);
+		_(NET_TEST_CARRIER_RESP);
+		_(NET_CS_STATE_IND);
+		_(NET_NEIGHBOUR_CELLS_REQ);
+		_(NET_NEIGHBOUR_CELLS_RESP);
+		_(NET_NETWORK_SELECT_MODE_SET_REQ);
+		_(NET_NETWORK_SELECT_MODE_SET_RESP);
+		_(NET_RSSI_IND);
+		_(NET_CIPHERING_IND);
+		_(NET_TIME_IND);
+		_(NET_CHANNEL_INFO_IND);
+		_(NET_CHANNEL_INFO_REQ);
+		_(NET_CHANNEL_INFO_RESP);
+		_(NET_RAT_IND);
+		_(NET_RAT_REQ);
+		_(NET_RAT_RESP);
+		_(NET_CS_STATE_REQ);
+		_(NET_CS_STATE_RESP);
+		_(NET_UMA_INFO_IND);
+		_(NET_RADIO_INFO_IND);
+		_(NET_CELL_INFO_GET_REQ);
+		_(NET_CELL_INFO_GET_RESP);
+		_(NET_CELL_INFO_IND);
+		_(NET_NITZ_NAME_IND);
+		_(NET_SOR_REQ);
+		_(NET_SOR_RESP);
+		_(NET_RSSI_CONF_REQ);
+		_(NET_RSSI_CONF_RESP);
+	}
+	return "NET_<UNKNOWN>";
+}
+
+const char *net_subblock_name(uint8_t value)
+{
+	switch (value) {
+		_(NET_MODEM_REG_INFO_COMMON);
+		_(NET_MODEM_AVAIL_NETWORK_INFO_COMMON);
+		_(NET_OPERATOR_INFO_COMMON);
+		_(NET_RSSI_CURRENT);
+		_(NET_TEST_CARRIER_PARAM);
+		_(NET_TEST_WCDMA_PARAMS);
+		_(NET_CIPHERING_INFO);
+		_(NET_MODEM_GSM_REG_INFO);
+		_(NET_MODEM_CURRENT_CELL_INFO);
+		_(NET_TIME_INFO);
+		_(NET_MODEM_DETAILED_NETWORK_INFO);
+		_(NET_MODEM_GSM_OPERATOR_INFO);
+		_(NET_GSM_HOME_CELLS_INFO);
+		_(NET_GSM_SIM_NMR_INFO);
+		_(NET_MODEM_CAUSE_EXTENSION);
+		_(NET_MODEM_GSM_BAND_INFO);
+		_(NET_UTRAN_SIM_NMR_INFO);
+		_(NET_ECID_GERAN_INFO);
+		_(NET_ECID_UTRAN_FDD_INFO);
+		_(NET_RAT_INFO);
+		_(NET_MODEM_UMA_SERVICE_ZONE_INFO);
+		_(NET_UMA_FAILURE_INFO);
+		_(NET_UTRAN_RADIO_INFO);
+		_(NET_UARFCN_INFO);
+		_(NET_GSM_CELL_INFO);
+		_(NET_WCDMA_CELL_INFO);
+		_(NET_EPS_CELL_INFO);
+		_(NET_FULL_NITZ_NAME);
+		_(NET_SHORT_NITZ_NAME);
+		_(NET_RSSI_CONF_INFO);
+	}
+	return "NET_<UNKNOWN>";
+}
+
+const char *gss_message_id_name(uint8_t value)
+{
+	switch (value) {
+		_(GSS_CS_SERVICE_REQ);
+		_(GSS_CS_SERVICE_RESP);
+		_(GSS_CS_SERVICE_FAIL_RESP);
+		_(GSS_CS_IND);
+		_(GSS_POWER_CLASS_IND);
+		_(GSS_HSXPA_USER_SETTING_WRITE_REQ);
+		_(GSS_HSXPA_USER_SETTING_WRITE_RESP);
+		_(GSS_HSXPA_USER_SETTING_IND);
+		_(GSS_HSXPA_USER_SETTING_READ_REQ);
+		_(GSS_HSXPA_USER_SETTING_READ_RESP);
+		_(GSS_SELECTED_RAT_IND);
+		_(GSS_UMA_PREF_MODE_IND);
+		_(GSS_HAC_MODE_WRITE_REQ);
+		_(GSS_HAC_MODE_WRITE_RESP);
+	}
+	return "GSS_<UNKNOWN>";
+}
+
+const char *gss_subblock_name(uint8_t value)
+{
+	switch (value) {
+		_(GSS_CS_LOCAL_INFO);
+		_(GSS_POWER_CLASS);
+		_(GSS_CS_STATUS);
+		_(GSS_CELL_INFO);
+		_(GSS_LONG_CELL_INFO);
+		_(GSS_BAND_INFO);
+		_(GSS_RAT_INFO);
+		_(GSS_ATK_TIMING_ADVANCE);
+		_(GSS_UMA_PREF_MODE_INFO);
+		_(GSS_PROV_INFO_SB_IDS);
+		_(GSS_SGW_INFO);
+		_(GSS_UNC_INFO);
+		_(GSS_REL_SIGNAL_LEVEL_INFO);
+		_(GSS_THRESHOLD_INFO);
+	}
+	return "GSS_<UNKNOWN>";
+}
+
+const char *gpds_transfer_cause(uint8_t value)
+{
+	switch (value) {
+		_(GPDS_TRANSFER_CAUSE_ATTACHED);
+		_(GPDS_TRANSFER_CAUSE_DETACHED);
+		_(GPDS_TRANSFER_CAUSE_RESUMED);
+		_(GPDS_TRANSFER_CAUSE_SUSPENDED_NO_COVERAGE);
+		_(GPDS_TRANSFER_CAUSE_SUSPENDED_CALL_SMS);
+		_(GPDS_TRANSFER_CAUSE_SUSPENDED_CALL);
+		_(GPDS_TRANSFER_CAUSE_SUSPENDED_RAU);
+		_(GPDS_TRANSFER_CAUSE_SUSPENDED_LU);
+		_(GPDS_TRANSFER_CAUSE_DSAC_RESTRICTION);
+	}
+	return "GPDS_<UNKNOWN>";
+}
+
+const char *gpds_transfer_status(uint8_t value)
+{
+	switch (value) {
+		_(GPDS_TRANSFER_NOT_AVAIL);
+		_(GPDS_TRANSFER_AVAIL);
+	}
+	return "GPDS_<UNKNOWN>";
+}
+
+static void hex_dump(const char *name, const uint8_t m[], size_t len)
+{
+	char hex[3 * 16 + 1];
+	char ascii[16 + 1];
+	size_t i, j, k;
+
+	ofono_debug("%s [%s=0x%02X len=%zu]:", name,
+			"message_id", m[0], len);
+
+	strcpy(hex, " **"), j = 3;
+	strcpy(ascii, "."), k = 1;
+
+	for (i = 0; i < len; i++) {
+		sprintf(hex + j, " %02X", m[i]), j += 3;
+		ascii[k++] = g_ascii_isgraph(m[i]) ? m[i] : '.';
+
+		if ((j & 48) == 48) {
+			ofono_debug("    *%-48s : %.*s", hex, (int)k, ascii);
+			j = 0, k = 0;
+		}
+	}
+
+	if (j)
+		ofono_debug("    *%-48s : %.*s", hex, (int)k, ascii);
+}
+
+void net_debug(const void *restrict buf, size_t len, void *data)
+{
+	const uint8_t *m = buf;
+	hex_dump(net_message_id_name(m[0]), m, len);
+}
+
diff --git a/drivers/isimodem2.5/debug.h b/drivers/isimodem2.5/debug.h
new file mode 100644
index 0000000..b137b6b
--- /dev/null
+++ b/drivers/isimodem2.5/debug.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_DEBUG_H
+#define __ISIMODEM25_DEBUG_H
+
+#include "ss.h"
+#include "mce.h"
+#include "sms.h"
+#include "uicc.h"
+#include "info.h"
+#include "call.h"
+#include "network.h"
+#include "gss.h"
+#include "gpds.h"
+
+const char *ss_message_id_name(uint8_t value);
+const char *ss_subblock_name(uint8_t value);
+const char *ss_operation_name(uint8_t value);
+const char *ss_ss_code_name(uint16_t value);
+
+const char *mce_isi_cause_name(enum mce_status_info value);
+const char *mce_message_id_name(enum mce_message_id value);
+const char *mce_modem_state_name(enum mce_modem_state value);
+
+const char *uicc_service_type_name(uint8_t value);
+const char *uicc_status_name(uint8_t value);
+const char *uicc_message_id_name(uint8_t value);
+const char *uicc_subblock_name(uint8_t value);
+
+const char *net_gsm_cause_name(uint8_t value);
+const char *net_isi_cause_name(uint8_t value);
+const char *net_status_name(uint8_t value);
+const char *net_message_id_name(uint8_t value);
+const char *net_subblock_name(uint8_t value);
+
+const char *gss_message_id_name(uint8_t value);
+const char *gss_subblock_name(uint8_t value);
+
+const char *gpds_transfer_status(uint8_t value);
+const char *gpds_transfer_cause(uint8_t value);
+
+void net_debug(const void *restrict buf, size_t len, void *data);
+
+const char *pn_resource_name(int value);
+
+#endif /* __ISIMODEM25_DEBUG_H */
diff --git a/drivers/isimodem2.5/devinfo.c b/drivers/isimodem2.5/devinfo.c
new file mode 100644
index 0000000..ab596bc
--- /dev/null
+++ b/drivers/isimodem2.5/devinfo.c
@@ -0,0 +1,246 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+
+#include <glib.h>
+
+#include "isimodem.h"
+#include "isiutil.h"
+#include "info.h"
+#include "timeout.h"
+
+
+struct devinfo_data {
+	GIsiClient *client;
+};
+
+static gboolean info_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_devinfo_query_cb_t cb = cbd->cb;
+	GIsiSubBlockIter iter;
+	char *info = NULL;
+	guint8 chars;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if (len < 3) {
+		DBG("truncated message");
+		return FALSE;
+	}
+
+	if (msg[0] != M_INFO_VERSION_READ_RESP)
+		return FALSE;
+
+	if (msg[1] != M_INFO_OK) {
+		DBG("request failed");
+		goto error;
+	}
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 3);
+			g_isi_sb_iter_is_valid(&iter);
+			g_isi_sb_iter_next(&iter)) {
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case M_INFO_SB_MODEMSW_VERSION:
+
+			if (g_isi_sb_iter_get_len(&iter) < 5
+				|| !g_isi_sb_iter_get_byte(&iter,
+						&chars, 3)
+				|| !g_isi_sb_iter_get_latin_tag(&iter,
+							&info, chars, 4))
+				goto error;
+
+			CALLBACK_WITH_SUCCESS(cb, info, cbd->data);
+			g_free(info);
+			g_free(cbd);
+			return TRUE;
+		default:
+			DBG("unindentified subblock id");
+			break;
+		}
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, "", cbd->data);
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_query_model(struct ofono_devinfo *info,
+				ofono_devinfo_query_cb_t cb,
+				void *data)
+{
+	/*
+	 * Temporary solution: Need to return error here othewise revision
+	 * won't get called. ISI specs do not have corresponding ISI
+	 * message for "INFO_PRODUCT_NAME".
+	 */
+	struct ofono_error error = { OFONO_ERROR_TYPE_FAILURE, 0 };
+	DBG("");
+	cb(&error, NULL, info);
+}
+
+static void isi_query_revision(struct ofono_devinfo *info,
+				ofono_devinfo_query_cb_t cb,
+				void *data)
+{
+	struct devinfo_data *dev = ofono_devinfo_get_data(info);
+	struct isi_cb_data *cbd = isi_cb_data_new(dev, cb, data);
+	const unsigned char msg[] = {
+		M_INFO_VERSION_READ_REQ,
+		0x00, 0x00,
+		0x00, 0x00, 0x00, 0x01, /* M_INFO_MODEMSW */
+		0x00, 0x00
+	};
+	DBG("");
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(dev->client, msg, sizeof(msg),
+			       INFO_TIMEOUT, info_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, "", data);
+	g_free(cbd);
+}
+
+static void isi_query_serial(struct ofono_devinfo *info,
+				ofono_devinfo_query_cb_t cb,
+				void *data)
+{
+	char imei[16]; /* IMEI 15 digits + 1 null*/
+	char numbers[] = "1234567890";
+	FILE *fp = fopen("/etc/imei", "r");
+	DBG("");
+
+	if (fp == NULL) {
+		DBG("failed to open /etc/imei file");
+		CALLBACK_WITH_FAILURE(cb, "", data);
+		return;
+	}
+
+	if (fgets(imei, 16, fp)) {
+		DBG(" IMEI = %s", imei);
+
+		if (15 == strspn(imei, numbers))
+			CALLBACK_WITH_SUCCESS(cb, imei, data);
+		else
+			CALLBACK_WITH_FAILURE(cb, "", data);
+	}
+
+	fclose(fp);
+}
+
+static gboolean isi_devinfo_register(gpointer user)
+{
+	struct ofono_devinfo *info = user;
+	ofono_devinfo_register(info);
+	return FALSE;
+}
+
+static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
+				void *opaque)
+{
+	struct ofono_devinfo *info = opaque;
+
+	if (!alive) {
+		DBG("devinfo driver bootstrap failed");
+		return;
+	}
+
+	g_idle_add(isi_devinfo_register, info);
+}
+
+static int isi_devinfo_probe(struct ofono_devinfo *info, unsigned int vendor,
+				void *user)
+{
+	GIsiModem *idx = user;
+	struct devinfo_data *data = g_try_new0(struct devinfo_data, 1);
+	DBG("");
+
+	if (!data)
+		return -ENOMEM;
+
+	data->client = g_isi_client_create(idx, PN_MODEM_INFO);
+
+	if (!data->client) {
+		g_free(data);
+		return -ENOMEM;
+	}
+
+	ofono_devinfo_set_data(info, data);
+	g_isi_verify(data->client, reachable_cb, info);
+	return 0;
+}
+
+static void isi_devinfo_remove(struct ofono_devinfo *info)
+{
+	struct devinfo_data *data = ofono_devinfo_get_data(info);
+
+	if (data) {
+		g_isi_client_destroy(data->client);
+		g_free(data);
+	}
+}
+
+static struct ofono_devinfo_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_devinfo_probe,
+	.remove			= isi_devinfo_remove,
+	.query_manufacturer	= NULL,
+	.query_model		= isi_query_model,
+	.query_revision		= isi_query_revision,
+	.query_serial		= isi_query_serial
+};
+
+void isi_devinfo_init()
+{
+	ofono_devinfo_driver_register(&driver);
+}
+
+void isi_devinfo_exit()
+{
+	ofono_devinfo_driver_unregister(&driver);
+}
diff --git a/drivers/isimodem2.5/gpds-context.c b/drivers/isimodem2.5/gpds-context.c
new file mode 100644
index 0000000..5bc9d17
--- /dev/null
+++ b/drivers/isimodem2.5/gpds-context.c
@@ -0,0 +1,788 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <arpa/inet.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <net/if.h>
+#include <search.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/uio.h>
+
+#include <glib.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include "ofono.h"
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs-context.h>
+#include <gisi/pep.h>
+#include <gisi/pipe_wg25.h>
+
+#include "gpds.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "timeout.h"
+
+# if (GPDS_CID_VOID < GPDS_MAX_CONTEXT_COUNT)
+#       error Uho! This should not happen!
+#endif
+
+struct gprs_context_data {
+	GIsiClient *client;
+	GIsiModem *idx;
+	uint16_t gpds;  /* GPDS object handle */
+	GSList *contexts;
+};
+
+struct context_data {
+	unsigned cid;   /* oFono core context ID */
+	struct ofono_gprs_context *driver;
+	union {
+		ofono_gprs_context_up_cb_t up_cb;
+		ofono_gprs_context_cb_t down_cb;
+	};
+	void *data;
+
+	GIsiPEP *pep;
+	GIsiPipe_wg25 *pipe;
+
+	char apn[GPDS_MAX_APN_STRING_SIZE + 1];
+	char username[GPDS_MAX_USERNAME_SIZE + 1];
+	char password[GPDS_MAX_PASSWORD_SIZE + 1];
+
+	uint8_t handle; /* GPDS context ID */
+	uint8_t type;
+};
+
+uint8_t last_handle;
+
+static struct context_data *find_context_by_cid(GSList *contexts,
+						unsigned int cid) {
+	GSList *m = NULL;
+
+	for (m = contexts; m; m = m->next) {
+		struct context_data *cd = m->data;
+
+		if (cd->cid == cid)
+			return cd;
+	}
+
+	return NULL;
+}
+
+static struct context_data *find_context_by_handle(GSList *contexts,
+						uint8_t handle) {
+	GSList *m = NULL;
+
+	for (m = contexts; m; m = m->next) {
+		struct context_data *cd = m->data;
+
+		if (cd->handle == handle)
+			return cd;
+	}
+
+	return NULL;
+}
+
+static void destroy_context(struct context_data *cd)
+{
+	if (!cd)
+		return;
+
+	DBG("Destroying %p (cid=%u)", cd, cd->cid);
+
+	if (cd->pipe) {
+		g_isi_pipe_destroy_wg25(cd->pipe);
+		cd->pipe = NULL;
+	}
+
+	if (cd->pep) {
+		g_isi_pep_destroy(cd->pep);
+		cd->pep = NULL;
+	}
+
+	g_free(cd);
+}
+
+static gboolean gprs_up_fail(struct context_data *cd)
+{
+	struct gprs_context_data *gcd =
+		ofono_gprs_context_get_data(cd->driver);
+	DBG("");
+
+	CALLBACK_WITH_FAILURE(cd->up_cb, NULL, 0, NULL, NULL, NULL, NULL,
+				cd->data);
+	gcd->contexts = g_slist_remove(gcd->contexts, cd);
+	destroy_context(cd);
+	return TRUE;
+}
+
+static gboolean gprs_down_fail(struct context_data *cd)
+{
+	struct gprs_context_data *gcd =
+		ofono_gprs_context_get_data(cd->driver);
+	DBG("");
+
+	CALLBACK_WITH_FAILURE(cd->down_cb, cd->data);
+	gcd->contexts = g_slist_remove(gcd->contexts, cd);
+	destroy_context(cd);
+	return TRUE;
+}
+
+static gboolean check_resp(GIsiClient *client,
+				const uint8_t *restrict msg, size_t len,
+				uint_fast8_t cmd, struct context_data *cd)
+{
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return FALSE;
+	}
+
+	if (len < 3) {
+		DBG("Truncated message");
+		return FALSE;
+	}
+
+	if (msg[0] != cmd) {
+		DBG("Unexpected message ID: 0x%02"PRIx8"", msg[0]);
+		return FALSE;
+	}
+
+	if ((cd->handle != GPDS_CID_VOID && msg[1] != cd->handle)
+	    || (msg[1] == GPDS_CID_VOID)) {
+		DBG("Invalid context ID: 0x%02"PRIx8"", msg[1]);
+		return FALSE;
+	}
+
+	if (msg[2] != GPDS_OK) {
+		DBG("Context creation error: 0x%02"PRIx8"", msg[2]);
+
+		if (len > 3)
+			DBG(" fail cause: 0x%02"PRIx8"", msg[3]);
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void activate_ind_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	struct gprs_context_data *gcd = opaque;
+	struct context_data *cd;
+	const unsigned char *msg = data;
+	GIsiSubBlockIter iter;
+	char ifname[IF_NAMESIZE];
+	char *ip = NULL;
+	char *pdns = NULL;
+	char *sdns = NULL;
+	const char *dns[3];
+	char *gwip = NULL;
+	char gwaddrstr[] = {0x00, 0x00, 0x00, 0x00,};
+
+	DBG("");
+
+	if (!msg || len < 3 || msg[0] != GPDS_CONTEXT_ACTIVATE_IND)
+		return;
+
+	cd = find_context_by_handle(gcd->contexts, msg[1]);
+
+	if (!cd) {
+		DBG("Unknown context ID: 0x%02"PRIx8"", msg[1]);
+		return;
+	}
+
+	for (g_isi_sb_iter_init(&iter, msg, len, 3);
+	     g_isi_sb_iter_is_valid(&iter);
+	     g_isi_sb_iter_next(&iter)) {
+		uint8_t *addr_value = NULL;
+		uint8_t addr_len = 0;
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+			/* TODO: IPv6 address support */
+		case GPDS_PDP_ADDRESS_INFO:
+			if (!g_isi_sb_iter_get_byte(&iter, &addr_len, 3)
+			    || !g_isi_sb_iter_get_data(&iter,
+						       (void *) &addr_value, 4))
+				goto error;
+
+			ip = alloca(INET_ADDRSTRLEN);
+			/* converts ip address to a text string */
+			inet_ntop(AF_INET, (const void *) addr_value, ip,
+				  INET_ADDRSTRLEN);
+			break;
+		case GPDS_PDNS_ADDRESS_INFO:
+			if (!g_isi_sb_iter_get_byte(&iter, &addr_len, 3)
+			    || !g_isi_sb_iter_get_data(&iter,
+						       (void *) &addr_value, 4))
+				break;
+
+			pdns = alloca(INET_ADDRSTRLEN);
+			/* converts ip address to a text string */
+			inet_ntop(AF_INET, (const void *) addr_value, pdns,
+				  INET_ADDRSTRLEN);
+			break;
+		case GPDS_SDNS_ADDRESS_INFO:
+
+			if (!g_isi_sb_iter_get_byte(&iter, &addr_len, 3)
+			    || !g_isi_sb_iter_get_data(&iter,
+						       (void *) &addr_value, 4))
+				break;
+
+			sdns = alloca(INET_ADDRSTRLEN);
+			/* converts ip address to a text string */
+			inet_ntop(AF_INET, (const void *) addr_value, sdns,
+				  INET_ADDRSTRLEN);
+			break;
+		default:
+			DBG("Skipped sub-block ID: 0x%02"PRIx8"",
+			    g_isi_sb_iter_get_id(&iter));
+		}
+	}
+
+	if (!g_isi_pep_get_ifname(cd->pep, ifname))
+		goto error;
+
+	dns[0] = pdns;
+	dns[1] = sdns;
+	dns[2] = 0;
+
+	gwip = alloca(INET_ADDRSTRLEN);
+	/* converts ip address to a text string */
+	inet_ntop(AF_INET, (const void *) gwaddrstr, gwip, INET_ADDRSTRLEN);
+	DBG("Context 0x%02"PRIx8" activated", msg[1]);
+	CALLBACK_WITH_SUCCESS(cd->up_cb, ifname, TRUE,
+			      (const char *) ip, STATIC_IP_NETMASK,
+			      (const char *) gwip, dns, cd->data);
+	return;
+error:
+	gprs_up_fail(cd);
+}
+
+static void activate_fail_ind_cb(GIsiClient *client, const void *restrict data,
+					size_t len, uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct gprs_context_data *gcd = opaque;
+	struct context_data *cd;
+	DBG("");
+
+	if (!msg || len < 3 || msg[0] != GPDS_CONTEXT_ACTIVATE_FAIL_IND)
+		return;
+
+	cd = find_context_by_handle(gcd->contexts, msg[1]);
+
+	if (cd == NULL) {
+		DBG("Unknown context ID: 0x%02"PRIx8"", msg[1]);
+		return;
+	}
+
+	gprs_up_fail(cd);
+}
+
+static gboolean context_activate_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	struct context_data *cd = opaque;
+	DBG("");
+
+	if (!check_resp(client, data, len, GPDS_CONTEXT_ACTIVATE_RESP, cd))
+		return gprs_up_fail(cd);
+
+	g_isi_pipe_start_wg25(cd->pipe);
+	return TRUE;
+}
+
+static gboolean send_context_activate(GIsiClient *client, void *opaque)
+{
+	struct context_data *cd = opaque;
+	const unsigned char msg[] = {
+		GPDS_CONTEXT_ACTIVATE_REQ,
+		cd->handle,     /* context ID */
+		0,              /* sub blocks */
+	};
+	DBG("");
+
+	if (!g_isi_request_make(client, msg, sizeof(msg), GPDS_TIMEOUT,
+				context_activate_cb, cd))
+		return gprs_up_fail(cd);
+
+	return TRUE;
+}
+
+static gboolean context_auth_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	struct context_data *cd = opaque;
+	DBG("");
+
+	if (!check_resp(client, data, len, GPDS_CONTEXT_AUTH_RESP, cd))
+		return gprs_up_fail(cd);
+
+	send_context_activate(client, cd);
+	return TRUE;
+}
+
+static gboolean send_context_authenticate(GIsiClient *client, void *opaque)
+{
+	struct context_data *cd = opaque;
+	size_t username_len = strlen(cd->username);
+	size_t password_len = strlen(cd->password);
+	const unsigned char top[] = {
+		GPDS_CONTEXT_AUTH_REQ,
+		cd->handle,     /* context ID */
+		2,              /* sub blocks */
+		GPDS_USERNAME_INFO,
+		(3 + username_len + 3) & ~3,
+		username_len,
+		/* Username goes here */
+	};
+	const unsigned char bottom[] = {
+		GPDS_PASSWORD_INFO,
+		(3 + password_len + 3) & ~3,
+		password_len,
+		/* Password goes here */
+	};
+	struct iovec iov[4] = {
+		{ (uint8_t *) top, sizeof(top) },
+		{ cd->username, username_len },
+		{ (uint8_t *) bottom, sizeof(bottom) },
+		{ cd->password, password_len },
+	};
+	DBG("");
+
+	if (!g_isi_request_vmake(client, iov, 4, GPDS_TIMEOUT,
+				 context_auth_cb, cd))
+		return gprs_up_fail(cd);
+
+	return TRUE;
+}
+
+static gboolean context_conf_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	struct context_data *cd = opaque;
+	const unsigned char *resp = data;
+
+	if (!check_resp(client, data, len, GPDS_CONTEXT_CONFIGURE_RESP, cd))
+		return gprs_up_fail(cd);
+
+	DBG("Context 0x%02"PRIx8" configured", resp[1]);
+
+	if (cd->username[0] != '\0')
+		send_context_authenticate(client, cd);
+	else
+		send_context_activate(client, cd);
+
+	return TRUE;
+}
+
+static gboolean link_conf_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	struct context_data *cd = opaque;
+	size_t apn_len = strlen(cd->apn);
+	const unsigned char apn_name[GPDS_MAX_APN_STRING_SIZE + 1];
+	memset(&apn_name, 0x00, sizeof(apn_name));
+	memmove(&apn_name, cd->apn, apn_len);
+	DBG("");
+
+	if (check_resp(client, data, len, GPDS_LL_CONFIGURE_RESP, cd)) {
+
+		const unsigned char msg[] = {
+			GPDS_CONTEXT_CONFIGURE_REQ,
+			cd->handle,		/* context ID */
+			cd->type,		/* PDP type */
+			GPDS_CONT_TYPE_NORMAL,	/*
+						 * No other context types are
+						 * needed since Ofono does not
+						 * support secondary or
+						 * network originated context*/
+			cd->handle,		/* primary context ID */
+			0x00,			/* filler */
+			2,			/* sub blocks */
+			GPDS_DNS_ADDRESS_REQ_INFO,
+			4,			/* subblock length */
+			0, 0,			/* padding */
+			GPDS_APN_INFO,
+			(3 + apn_len + 3) & ~3,
+			apn_len,
+		};
+
+		struct iovec iov[2] = {
+			{ (uint8_t *) msg, sizeof(msg) },
+			{ &apn_name, ((3 + apn_len + 3) & ~3) - 3 },
+		};
+
+		if (last_handle == cd->handle)
+			last_handle = GPDS_CID_VOID;
+
+		DBG("Configuring context 0x%02"PRIx8"", msg[1]);
+
+		if (!g_isi_request_vmake(client, iov, 2, GPDS_TIMEOUT,
+						context_conf_cb, cd))
+			return gprs_up_fail(cd);
+
+	} else
+		return gprs_up_fail(cd);
+
+	return TRUE;
+}
+
+static void create_pipe_cb(GIsiPipe_wg25 *pipe)
+{
+	struct context_data *cd = g_isi_pipe_get_userdata_wg25(pipe);
+	struct gprs_context_data *gcd =
+		ofono_gprs_context_get_data(cd->driver);
+	unsigned char msg[] = {
+		GPDS_LL_CONFIGURE_REQ,
+		cd->handle,     /* GPDS context ID */
+		g_isi_pipe_get_handle_wg25(cd->pipe),
+		GPDS_LL_PLAIN,  /* link type */
+	};
+	DBG("LL Configure, context 0x%02"PRIx8"", cd->handle);
+
+	if (!g_isi_request_make(gcd->client, msg, sizeof(msg), GPDS_TIMEOUT,
+				link_conf_cb, cd))
+		gprs_up_fail(cd);
+}
+
+static gboolean create_context_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object, void *opaque)
+{
+	const unsigned char *resp = data;
+	struct context_data *cd = opaque;
+	struct gprs_context_data *gcd =
+		ofono_gprs_context_get_data(cd->driver);
+	DBG("");
+
+	if (!check_resp(client, data, len, GPDS_CONTEXT_ID_CREATE_RESP, cd))
+		goto error;
+
+	cd->handle = resp[1];
+	last_handle = resp[1];
+	DBG("Context id 0x%02"PRIx8" created", cd->handle);
+	DBG("Creating pipe interface");
+	cd->pep = g_isi_pep_create(gcd->idx, NULL, NULL);
+
+	if (cd->pep == NULL)
+		goto error;
+
+	cd->pipe = g_isi_pipe_create_wg25(gcd->idx, create_pipe_cb);
+
+	if (cd->pipe == NULL)
+		goto error;
+
+	g_isi_pipe_set_userdata_wg25(cd->pipe, cd);
+	return TRUE;
+error:
+	return gprs_up_fail(cd);
+}
+
+static void context_id_delete_ind_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	struct gprs_context_data *gcd = opaque;
+	struct context_data *cd;
+	const unsigned char *msg = data;
+	DBG("");
+
+	if (!msg || len < 2 || msg[0] != GPDS_CONTEXT_ID_DELETE_IND)
+		return;
+
+	cd = find_context_by_handle(gcd->contexts, msg[1]);
+
+	if (cd == NULL) {
+		DBG("Unknown context ID: 0x%02"PRIx8"", msg[1]);
+		return;
+	}
+
+	DBG("Context id 0x%02"PRIx8" deleted", msg[1]);
+	gcd->contexts = g_slist_remove(gcd->contexts, cd);
+	destroy_context(cd);
+}
+
+static void deactivate_ind_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	struct gprs_context_data *gcd = opaque;
+	struct context_data *cd;
+	const unsigned char *msg = data;
+	DBG("Received");
+
+	if (!msg || len < 3 || msg[0] != GPDS_CONTEXT_DEACTIVATE_IND)
+		return;
+
+	cd = find_context_by_handle(gcd->contexts, msg[1]);
+
+	if (cd == NULL) {
+		DBG("Unknown context ID: 0x%02"PRIx8"", msg[1]);
+		return;
+	}
+
+	DBG("Context deactivated with cause: 0x%02"PRIx8"", msg[2]);
+	ofono_gprs_context_deactivated(cd->driver, cd->cid);
+
+	if (cd->pipe)
+		g_isi_pipe_remove_wg25(cd->pipe);
+}
+
+static void isi_gprs_activate_primary(struct ofono_gprs_context *gc,
+				const struct ofono_gprs_primary_context *ctx,
+				ofono_gprs_context_up_cb_t cb,
+				void *data)
+{
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct context_data *cd = g_try_new0(struct context_data, 1);
+	struct context_data *old = NULL;
+	const unsigned char msg[] = {
+		GPDS_CONTEXT_ID_CREATE_REQ,
+	};
+
+	DBG("");
+
+	if (!cd)
+		return;
+
+	cd->cid = ctx->cid;
+	cd->driver = gc;
+	cd->up_cb = cb;
+	cd->data = data;
+	cd->pep = NULL;
+	cd->pipe = NULL;
+	cd->handle = last_handle;
+	cd->type = GPDS_PDP_TYPE_IPV4;
+	old = find_context_by_cid(gcd->contexts, ctx->cid);
+
+	if (old) {
+		DBG("Duplicate context ID: %u", ctx->cid);
+		goto error;
+	}
+
+	gcd->contexts = g_slist_append(gcd->contexts, cd);
+
+	if (strlen(ctx->apn) >= GPDS_MAX_APN_STRING_SIZE
+	    || strlen(ctx->username) >= GPDS_MAX_USERNAME_SIZE
+	    || strlen(ctx->password) >= GPDS_MAX_PASSWORD_SIZE)
+		goto error;
+
+	strncpy(cd->apn, ctx->apn, GPDS_MAX_APN_STRING_SIZE);
+	cd->apn[GPDS_MAX_APN_STRING_SIZE] = '\0';
+	strncpy(cd->username, ctx->username, GPDS_MAX_USERNAME_SIZE);
+	cd->username[GPDS_MAX_USERNAME_SIZE] = '\0';
+	strncpy(cd->password, ctx->password, GPDS_MAX_PASSWORD_SIZE);
+	cd->username[GPDS_MAX_PASSWORD_SIZE] = '\0';
+
+	if (cd->handle != GPDS_CID_VOID) {
+		DBG("Context ID already created");
+		DBG("Creating pipe interface");
+		cd->pep = g_isi_pep_create(gcd->idx, NULL, NULL);
+
+		if (cd->pep == NULL)
+			goto error;
+
+		cd->pipe = g_isi_pipe_create_wg25(gcd->idx, create_pipe_cb);
+
+		if (cd->pipe == NULL)
+			goto error;
+
+		g_isi_pipe_set_userdata_wg25(cd->pipe, cd);
+	} else {
+		DBG("Creating context ID");
+
+		if (!g_isi_request_make(gcd->client, msg, sizeof(msg),
+					GPDS_TIMEOUT, create_context_cb, cd))
+			gprs_up_fail(cd);
+	}
+
+	return;
+error:
+	gprs_up_fail(cd);
+}
+
+static gboolean context_deactivate_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len, uint16_t object,
+					void *opaque)
+{
+	struct context_data *cd = opaque;
+	DBG("");
+
+	if (!check_resp(client, data, len, GPDS_CONTEXT_DEACTIVATE_RESP, cd))
+		return gprs_down_fail(cd);
+
+	CALLBACK_WITH_SUCCESS(cd->down_cb, cd->data);
+
+	if (cd->pipe)
+		g_isi_pipe_remove_wg25(cd->pipe);
+
+	return TRUE;
+}
+
+static void isi_gprs_deactivate_primary(struct ofono_gprs_context *gc,
+					unsigned int cid,
+					ofono_gprs_context_cb_t cb, void *data)
+{
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	struct context_data *cd;
+	unsigned char msg[] = {
+		GPDS_CONTEXT_DEACTIVATE_REQ,
+		0x00,   /* GPDS context ID, added later */
+	};
+	DBG("");
+
+	cd = find_context_by_cid(gcd->contexts, cid);
+
+	if (!cd) {
+		DBG("Unknown context ID: %u", cid);
+		return;
+	}
+
+	cd->down_cb = cb;
+	cd->data = data;
+	msg[1] = cd->handle;
+
+	if (!g_isi_request_make(gcd->client, msg, sizeof(msg), GPDS_TIMEOUT,
+				context_deactivate_cb, cd))
+		gprs_down_fail(cd);
+}
+
+static void gpds_ctx_reachable_cb(GIsiClient *client, gboolean alive,
+					uint16_t object,
+					void *opaque)
+{
+	struct ofono_gprs_context *gc = opaque;
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	DBG("");
+
+	if (!alive) {
+		DBG("Unable to bootstrap gprs context driver");
+		return;
+	}
+
+	DBG("PN_GPDS (v%03d.%03d) for PDP contexts",
+	    g_isi_version_major(client),
+	    g_isi_version_minor(client));
+	gcd->gpds = object;
+	g_isi_subscribe(client, GPDS_CONTEXT_ACTIVATE_IND,
+			activate_ind_cb, gcd);
+	g_isi_subscribe(client, GPDS_CONTEXT_ACTIVATE_FAIL_IND,
+			activate_fail_ind_cb, gcd);
+	g_isi_subscribe(client, GPDS_CONTEXT_DEACTIVATE_IND,
+			deactivate_ind_cb, gcd);
+	g_isi_subscribe(client, GPDS_CONTEXT_ID_DELETE_IND,
+			context_id_delete_ind_cb, gcd);
+}
+
+static int isi_gprs_context_probe(struct ofono_gprs_context *gc,
+					unsigned int vendor, void *user)
+{
+	GIsiModem *idx = user;
+	struct gprs_context_data *gcd = g_try_new0(struct gprs_context_data, 1);
+	struct ofono_atom *gprsa;
+	struct gprs_data *gd;
+
+	DBG("");
+
+	if (!gcd)
+		return -ENOMEM;
+
+	gprsa = __ofono_modem_find_atom(
+			ofono_gprs_context_get_modem(gc),
+			OFONO_ATOM_TYPE_GPRS);
+	gd = ofono_gprs_get_data(
+			__ofono_atom_get_data(gprsa));
+
+	gcd->client = gd->client;
+
+	if (!gcd->client) {
+		g_free(gcd);
+		return -ENOMEM;
+	}
+
+	last_handle = GPDS_CID_VOID;
+	ofono_gprs_context_set_data(gc, gcd);
+	gcd->idx = idx;
+	gcd->contexts = NULL;
+	g_isi_verify(gcd->client, gpds_ctx_reachable_cb, gc);
+	return 0;
+}
+
+static void isi_gprs_context_remove(struct ofono_gprs_context *gc)
+{
+	struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+	GSList *m;
+	DBG("");
+
+	ofono_gprs_context_set_data(gc, NULL);
+
+	for (m = gcd->contexts; m; m = m->next)
+		destroy_context(m->data);
+
+	g_slist_free(gcd->contexts);
+
+	if (gcd->client)
+		gcd->client = NULL;/* Do not destroy, will be done in gpds.c */
+
+	g_free(gcd);
+}
+
+static struct ofono_gprs_context_driver driver = {
+	.name                   = "isimodem25",
+	.probe                  = isi_gprs_context_probe,
+	.remove                 = isi_gprs_context_remove,
+	.activate_primary       = isi_gprs_activate_primary,
+	.deactivate_primary     = isi_gprs_deactivate_primary,
+};
+
+void isi_gprs_context_init()
+{
+	DBG("");
+	g_isi_pipe_init_wg25();
+	ofono_gprs_context_driver_register(&driver);
+}
+
+void isi_gprs_context_exit()
+{
+	DBG("");
+	ofono_gprs_context_driver_unregister(&driver);
+}
diff --git a/drivers/isimodem2.5/gpds.c b/drivers/isimodem2.5/gpds.c
new file mode 100644
index 0000000..64280da
--- /dev/null
+++ b/drivers/isimodem2.5/gpds.c
@@ -0,0 +1,395 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <gisi/client.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs.h>
+
+#include "debug.h"
+#include "gpds.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "timeout.h"
+
+static void transfer_status_ind_cb(GIsiClient *client,
+				   const void *restrict data,
+				   size_t len,
+				   uint16_t object,
+				   void *opaque)
+{
+	const unsigned char *msg = data;
+	DBG("");
+
+	if (!msg || len < 3 || msg[0] != GPDS_TRANSFER_STATUS_IND)
+		return;
+
+	DBG("Transfer status changed: %s with cause: %s",
+	    gpds_transfer_status(msg[1]), gpds_transfer_cause(msg[2]));
+}
+
+static void detach_ind_cb(GIsiClient *client, const void *restrict data,
+			  size_t len, uint16_t object, void *opaque)
+{
+	struct ofono_gprs *gprs = opaque;
+	const unsigned char *msg = data;
+	struct gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct isi_cb_data *cbd = NULL;
+	ofono_gprs_cb_t cb = NULL;
+	DBG("");
+
+	if (!msg || len < 3 || msg[0] != GPDS_DETACH_IND)
+		return;
+
+	DBG("Detached with cause: 0x%02"PRIx8"", msg[1]);
+
+	if (gd)
+		cbd = gd->cbd;
+
+	if (cbd)
+		cb = cbd->cb;
+
+	if (gd->cbd) {
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		gd->cbd = NULL;
+		ofono_gprs_set_data(gprs, gd);
+		g_free(cbd);
+	}
+
+	ofono_gprs_detached_notify(gprs);
+}
+
+static gboolean isi_gprs_register(gpointer user)
+{
+	struct ofono_gprs *gprs = user;
+	struct gprs_data *gd = ofono_gprs_get_data(gprs);
+	DBG("");
+
+	g_isi_subscribe(gd->client, GPDS_DETACH_IND, detach_ind_cb, gprs);
+	g_isi_subscribe(gd->client,
+			GPDS_TRANSFER_STATUS_IND,
+			transfer_status_ind_cb, gprs);
+	ofono_gprs_register(user);
+	return FALSE;
+}
+
+static gboolean configure_resp_cb(GIsiClient *client,
+				  const void *restrict data,
+				  size_t len,
+				  uint16_t object,
+				  void *opaque)
+{
+	const unsigned char *msg = data;
+	DBG("");
+
+	if (!msg || len < 2 || msg[0] != GPDS_CONFIGURE_RESP)
+		return FALSE;
+
+	if (msg[1] != GPDS_OK)
+		DBG("Failed to configure");
+
+	return TRUE;
+}
+
+static void gpds_reachable_cb(GIsiClient *client,
+			      gboolean alive,
+			      uint16_t object,
+			      void *opaque)
+{
+	struct ofono_gprs *gprs = opaque;
+	const unsigned char msg[] = {
+		GPDS_CONFIGURE_REQ,
+		GPDS_ATTACH_MODE_MANUAL,
+		GPDS_MT_ACT_MODE_DEFAULT,
+		GPDS_CLASSC_MODE_DEFAULT,
+		GPDS_AOL_CTX_DEFAULT,
+		0x00, 0x00
+	};
+	DBG("");
+
+	if (!alive) {
+		DBG("Unable to bootsrap gprs driver");
+		return;
+	}
+
+	DBG("PN_GPDS (v%03d.%03d) for PDP contexts",
+	g_isi_version_major(client),
+	g_isi_version_minor(client));
+
+	g_idle_add(isi_gprs_register, gprs);
+
+	DBG("Configure GPDS");
+
+	if (g_isi_request_make(client, msg, sizeof(msg), GPDS_TIMEOUT,
+			       configure_resp_cb, gprs) == NULL)
+		DBG("Send failed");
+}
+
+static int isi_gprs_probe(struct ofono_gprs *gprs,
+			  unsigned int vendor, void *user)
+{
+	GIsiModem *idx = user;
+	struct gprs_data *gd = g_try_new0(struct gprs_data, 1);
+	DBG("");
+
+	if (!gd)
+		return -ENOMEM;
+
+	gd->client = g_isi_client_create(idx, PN_GPDS);
+
+	if (!gd->client) {
+		g_free(gd);
+		return -ENOMEM;
+	}
+
+	ofono_gprs_set_data(gprs, gd);
+	ofono_gprs_set_cid_range(gprs, 1, GPDS_MAX_CONTEXT_COUNT + 1);
+	g_isi_verify(gd->client, gpds_reachable_cb, gprs);
+	return 0;
+}
+
+static void isi_gprs_remove(struct ofono_gprs *gprs)
+{
+	struct gprs_data *data = ofono_gprs_get_data(gprs);
+	DBG("");
+
+	if (!data)
+		return;
+
+	ofono_gprs_set_data(gprs, NULL);
+	g_isi_client_destroy(data->client);
+	g_free(data);
+}
+
+static gboolean attach_resp_cb(GIsiClient *client, const void *restrict data,
+			       size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_gprs_cb_t cb = cbd->cb;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if (len != 4 || msg[0] != GPDS_ATTACH_RESP)
+		return FALSE;
+
+	if (msg[1] != GPDS_OK) {
+		DBG("Attach failed with cause: 0x%02"PRIx8"", msg[2]);
+		goto error;
+	}
+
+	DBG("Attached");
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static gboolean detach_resp_cb(GIsiClient *client, const void *restrict data,
+			       size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_gprs_cb_t cb = NULL;
+	struct ofono_gprs *gprs = NULL;
+	struct gprs_data *gd = NULL;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if (len != 3 || msg[0] != GPDS_DETACH_RESP)
+		return FALSE;
+
+	if (msg[1] == GPDS_OK) {
+		DBG("Detached");
+		goto out;
+	}
+
+error:
+
+	if (cbd) {
+		cb = cbd->cb;
+		gprs = cbd->data;
+		gd = ofono_gprs_get_data(gprs);
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+
+	if (gd) {
+		gd->cbd = NULL;
+		ofono_gprs_set_data(gprs, gd);
+	}
+
+	g_free(cbd);
+out:
+	return TRUE;
+}
+
+static GIsiRequest *attach_request_make(GIsiClient *client, void *data)
+{
+	const unsigned char msg[] = {
+		GPDS_ATTACH_REQ,
+		GPDS_FOLLOW_OFF
+	};
+	DBG("");
+
+	return g_isi_request_make(client, msg, sizeof(msg), GPDS_TIMEOUT,
+				  attach_resp_cb, data);
+}
+
+static GIsiRequest *detach_request_make(GIsiClient *client, void *data)
+{
+	const unsigned char msg[] = {
+		GPDS_DETACH_REQ,
+		0x00,   /* filler */
+		0x00    /* sub-blocks */
+	};
+	DBG("");
+
+	return g_isi_request_make(client, msg, sizeof(msg), GPDS_TIMEOUT,
+				  detach_resp_cb, data);
+}
+
+static void isi_gprs_set_attached(struct ofono_gprs *gprs, int attached,
+				  ofono_gprs_cb_t cb, void *data)
+{
+	struct gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct isi_cb_data *cbd = isi_cb_data_new(NULL, cb, data);
+	GIsiRequest *req;
+	DBG("");
+
+	if (!cbd || !gd)
+		goto error;
+
+	if (attached)
+		req = attach_request_make(gd->client, cbd);
+	else {
+		req = detach_request_make(gd->client, cbd);
+
+		if (req) {
+			gd->cbd = cbd;
+			ofono_gprs_set_data(gprs, gd);
+		}
+	}
+
+	if (req)
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static gboolean status_resp_cb(GIsiClient *client, const void *restrict data,
+			       size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_gprs_status_cb_t cb = cbd->cb;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if (len < 2 || msg[0] != GPDS_STATUS_RESP)
+		return FALSE;
+
+	DBG("Attach status: 0x%02"PRIx8"", msg[1]);
+	/*
+	 * Even though gprs status inside ofono can have several other
+	 * values gboolean value suits here since there is no way to
+	 * get other values than attached or detached from modem.
+	 */
+	CALLBACK_WITH_SUCCESS(cb, msg[1] == GPDS_ATTACHED, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_gprs_attached_status(struct ofono_gprs *gprs,
+				     ofono_gprs_status_cb_t cb,
+				     void *data)
+{
+	struct gprs_data *gd = ofono_gprs_get_data(gprs);
+	struct isi_cb_data *cbd = isi_cb_data_new(NULL, cb, data);
+	const unsigned char msg[] = {
+		GPDS_STATUS_REQ,
+	};
+	DBG("");
+
+	if (!cbd || !gd)
+		goto error;
+
+	if (g_isi_request_make(gd->client, msg, sizeof(msg), GPDS_TIMEOUT,
+			       status_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, data);
+	g_free(cbd);
+}
+
+static struct ofono_gprs_driver driver = {
+	.name                   = "isimodem25",
+	.probe                  = isi_gprs_probe,
+	.remove                 = isi_gprs_remove,
+	.set_attached           = isi_gprs_set_attached,
+	.attached_status        = isi_gprs_attached_status,
+};
+
+void isi_gprs_init(void)
+{
+	DBG("");
+	ofono_gprs_driver_register(&driver);
+}
+
+void isi_gprs_exit(void)
+{
+	DBG("");
+	ofono_gprs_driver_unregister(&driver);
+}
diff --git a/drivers/isimodem2.5/gpds.h b/drivers/isimodem2.5/gpds.h
new file mode 100644
index 0000000..67980d7
--- /dev/null
+++ b/drivers/isimodem2.5/gpds.h
@@ -0,0 +1,295 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_GPDS_H
+#define __ISIMODEM25_GPDS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gisi/client.h>
+
+#define PN_GPDS				0x31
+#define GPDS_MAX_CONTEXT_COUNT		11
+#define GPDS_CID_VOID			0xFF
+#define GPDS_MAX_APN_STRING_SIZE	0x64
+#define GPDS_MAX_USERNAME_SIZE		0x35
+#define GPDS_MAX_PASSWORD_SIZE		0x35
+
+#define STATIC_IP_NETMASK "255.255.255.255"
+
+struct gprs_data {
+	GIsiClient *client;
+	struct isi_cb_data *cbd;
+};
+
+enum gpds_message_id {
+	GPDS_LL_CONFIGURE_REQ =			0x00,
+	GPDS_LL_CONFIGURE_RESP =		0x01,
+	GPDS_CONTEXT_ID_CREATE_REQ =		0x02,
+	GPDS_CONTEXT_ID_CREATE_RESP =		0x03,
+	GPDS_CONTEXT_ID_CREATE_IND =		0x04,
+	GPDS_CONTEXT_ID_DELETE_IND =		0x05,
+	GPDS_CONTEXT_CONFIGURE_REQ =		0x06,
+	GPDS_CONTEXT_CONFIGURE_RESP =		0x07,
+	GPDS_CONTEXT_ACTIVATE_REQ =		0x08,
+	GPDS_CONTEXT_ACTIVATE_RESP =		0x09,
+	GPDS_CONTEXT_ACTIVATE_IND =		0x0A,
+	GPDS_CONTEXT_DEACTIVATE_REQ =		0x0B,
+	GPDS_CONTEXT_DEACTIVATE_RESP =		0x0C,
+	GPDS_CONTEXT_DEACTIVATE_IND =		0x0D,
+	GPDS_CONTEXT_MWI_ACT_REQUEST_IND =	0x0E,
+	GPDS_CONTEXT_NWI_ACT_REJECT_REQ =	0x0F,
+	GPDS_CONTEXT_NWI_ACT_REJECT_RESP =	0x10,
+	GPDS_CONFIGURE_REQ =			0x11,
+	GPDS_CONFIGURE_RESP =			0x12,
+	GPDS_ATTACH_REQ =			0x13,
+	GPDS_ATTACH_RESP =			0x14,
+	GPDS_ATTACH_IND =			0x15,
+	GPDS_DETACH_REQ =			0x16,
+	GPDS_DETACH_RESP =			0x17,
+	GPDS_DETACH_IND =			0x18,
+	GPDS_STATUS_REQ =			0x19,
+	GPDS_STATUS_RESP =			0x1A,
+	GPDS_SMS_PDU_SEND_REQ =			0x1B,
+	GPDS_SMS_PDU_SEND_RESP =		0x1C,
+	GPDS_SMS_PDU_RECEIVE_IND =		0x1D,
+	GPDS_TRANSFER_STATUS_IND =		0x1E,
+	GPDS_CONTEXT_ACTIVATE_FAIL_IND =	0x1F,
+	GPDS_LL_BIND_REQ =			0x20,
+	GPDS_LL_BIND_RESP =			0x21,
+	GPDS_CONTEXT_STATUS_REQ =		0x22,
+	GPDS_CONTEXT_STATUS_RESP =		0x23,
+	GPDS_CONTEXT_STATUS_IND =		0x24,
+	GPDS_CONTEXT_ACTIVATING_IND =		0x25,
+	GPDS_CONTEXT_MODIFY_REQ =		0x2A,
+	GPDS_CONTEXT_MODIFY_RESP =		0x2B,
+	GPDS_CONTEXT_MODIFY_IND =		0x2C,
+	GPDS_ATTACH_FAIL_IND =			0x2D,
+	GPDS_CONTEXT_DEACTIVATING_IND =		0x2F,
+	GPDS_CONFIGURATION_INFO_REQ =		0x30,
+	GPDS_CONFIGURATION_INFO_RESP =		0x31,
+	GPDS_CONFIGURATION_INFO_IND =		0x32,
+	GPDS_CONTEXT_AUTH_REQ =			0x33,
+	GPDS_CONTEXT_AUTH_RESP =		0x34,
+	GPDS_TEST_MODE_REQ =			0x35,
+	GPDS_TEST_MODE_RESP =			0x36,
+	GPDS_RADIO_ACTIVITY_IND =		0x37,
+	GPDS_FORCED_READY_STATE_REQ =		0x38,
+	GPDS_FORCED_READY_STATE_RESP =		0x39,
+	GPDS_CONTEXTS_CLEAR_REQ =		0x3A,
+	GPDS_CONTEXTS_CLEAR_RESP =		0x3B,
+	GPDS_MBMS_SERVICE_SELECTION_REQ =	0x3C,
+	GPDS_MBMS_SERVICE_SELECTION_RESP =	0x3D,
+	GPDS_MBMS_STATUS_IND =			0x3E,
+	GPDS_MBMS_CONTEXT_CREATE_REQ =		0x3F,
+	GPDS_MBMS_CONTEXT_CREATE_RESP =		0x40,
+	GPDS_MBMS_CONTEXT_ACTIVATE_REQ =	0x41,
+	GPDS_MBMS_CONTEXT_ACTIVATE_RESP =	0x42,
+	GPDS_MBMS_CONTEXT_DELETE_REQ =		0x43,
+	GPDS_MBMS_CONTEXT_DELETE_RESP =		0x44,
+	GPDS_MBMS_CONTEXT_DELETE_IND =		0x45,
+	GPDS_MBMS_SERVICE_SELECTION_IND =	0x46,
+	GPDS_MBMS_SERVICE_AVAILABLE_IND =	0x47,
+	GPDS_TEST_REQ =				0x48,
+	GPDS_TEST_RESP =			0x49
+};
+
+enum gpds_subblock {
+	GPDS_COMP_INFO =			0x00,
+	GPDS_QOS_REQ_INFO =			0x01,
+	GPDS_QOS_MIN_INFO =			0x02,
+	GPDS_QOS_NEG_INFO =			0x03,
+	GPDS_PDP_ADDRESS_INFO =			0x04,
+	GPDS_APN_INFO =				0x05,
+	GPDS_QOS99_REQ_INFO =			0x06,
+	GPDS_QOS99_MIN_INFO =			0x07,
+	GPDS_QOS99_NEG_INFO =			0x08,
+	GPDS_TFT_INFO =				0x09,
+	GPDS_TFT_FILTER_INFO =			0x0A,
+	GPDS_USERNAME_INFO =			0x0B,
+	GPDS_PASSWORD_INFO =			0x0C,
+	GPDS_PDNS_ADDRESS_INFO =		0x0D,
+	GPDS_SDNS_ADDRESS_INFO =		0x0E,
+	GPDS_CHALLENGE_INFO =			0x0F,
+	GPDS_DNS_ADDRESS_REQ_INFO =		0x90,
+};
+
+enum gpds_status {
+	GPDS_ERROR =				0x00,
+	GPDS_OK =				0x01,
+	GPDS_FAIL =				0x02
+};
+
+enum gpds_isi_cause {
+	GPDS_CAUSE_UNKNOWN =			0x00,
+	GPDS_CAUSE_IMSI =			0x02,
+	GPDS_CAUSE_MS_ILLEGAL =			0x03,
+	GPDS_CAUSE_ME_ILLEGAL =			0x06,
+	GPDS_CAUSE_GPRS_NOT_ALLOWED =		0x07,
+	GPDS_NOT_ALLOWED =			0x08,
+	GPDS_CAUSE_MS_IDENTITY =		0x09,
+	GPDS_CAUSE_DETACH =			0x0A,
+	GPDS_PLMN_NOT_ALLOWED =			0x0B,
+	GPDS_LA_NOT_ALLOWED =			0x0C,
+	GPDS_ROAMING_NOT_ALLOWED =		0x0D,
+	GPDS_CAUSE_GPRS_NOT_ALLOWED_IN_PLMN =	0x0E,
+	GPDS_CAUSE_NO_SUITABLE_CELLS_IN_LA =	0x0F,
+	GPDS_CAUSE_MSC_NOT_REACH =		0x10,
+	GPDS_CAUSE_PLMN_FAIL =			0x11,
+	GPDS_CAUSE_NETWORK_CONGESTION =		0x16,
+	GPDS_CAUSE_LLC_SNDCP_FAILURE =		0x19,
+	GPDS_CAUSE_RESOURCE_INSUFF =		0x1A,
+	GPDS_CAUSE_APN =			0x1B,
+	GPDS_CAUSE_PDP_UNKNOWN =		0x1C,
+	GPDS_CAUSE_AUTHENTICATION =		0x1D,
+	GPDS_CAUSE_ACT_REJECT_GGSN =		0x1E,
+	GPDS_CAUSE_ACT_REJECT =			0x1F,
+	GPDS_CAUSE_SERV_OPT_NOT_SUPPORTED =	0x20,
+	GPDS_CAUSE_SERV_OPT_NOT_SUBSCRIBED =	0x21,
+	GPDS_CAUSE_SERV_OPT_OUT_OF_ORDER =	0x22,
+	GPDS_CAUSE_NSAPI_ALREADY_USED =		0x23,
+	GPDS_CAUSE_DEACT_REGULAR =		0x24,
+	GPDS_CAUSE_QOS =			0x25,
+	GPDS_CAUSE_NETWORK_FAIL =		0x26,
+	GPDS_CAUSE_REACTIVATION_REQ =		0x27,
+	GPDS_CAUSE_FEAT_NOT_SUPPORTED =		0x28,
+	GPDS_CAUSE_TFT_SEMANTIC_ERROR =		0x29,
+	GPDS_CAUSE_TFT_SYNTAX_ERROR =		0x2A,
+	GPDS_CAUSE_CONTEXT_UNKNOWN =		0x2B,
+	GPDS_CAUSE_FILTER_SEMANTIC_ERROR =	0x2C,
+	GPDS_CAUSE_FILTER_SYNTAX_ERROR =	0x2D,
+	GPDS_CAUSE_CONT_WITHOUT_TFT =		0x2E,
+	GPDS_CAUSE_MULTICAST_MEMBERSHIP_TIMEOUT = 0x2F,
+	GPDS_CAUSE_INVALID_MANDATORY_INFO =	0x60,
+	GPDS_CAUSE_MSG_TYPE_NON_EXISTENTOR_NOT_IMPLTD =	0x61,
+	GPDS_CAUSE_MSG_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 0x62,
+	GPDS_CAUSE_IE_NON_EXISTENT_OR_NOT_IMPLEMENTED =	0x63,
+	GPDS_CAUSE_CONDITIONAL_IE_ERROR =	0x64,
+	GPDS_CUASEMSG_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 0x65,
+	GPDS_CAUSE_UNSPECIFIED =		0x6F,
+	GPDS_CAUSE_APN_INCOMPATIBLE_WITH_CURR_CTXT = 0x70,
+	GPDS_CAUSE_FDN =			0xA0,
+	GPDS_CAUSE_USER_ABORT =			0xA1,
+	GPDS_CAUSE_CS_INACTIVE =		0xA2,
+	GPDS_CAUSE_CSD_OVERRIDE =		0xA3,
+	GPDS_CAUSE_APN_CONTROL =		0xA4,
+	GPDS_CAUSE_CALL_CONTROL =		0xA5,
+	GPDS_CAUSE_TEMPERATURE_LIMIT =		0xA6,
+	GPDS_CAUSE_RETRY_COUNTER_EXPIRED =	0xC8,
+	GPDS_CAUSE_NO_CONNECTION =		0xC9,
+	GPDS_CAUSE_DETACHED =			0xF5,
+	GPDS_CAUSE_NO_SERVICE_POWER_SAVE =	0xF7,
+	GPDS_CAUSE_SIM_REMOVED =		0xF9,
+	GPDS_CAUSE_POWER_OFF =			0xFA,
+	GPDS_CAUSE_LAI_FORBIDDEN_NATIONAL_ROAM_LIST = 0xFB,
+	GPDS_CAUSE_LAI_FORBIDDEN_REG_PROVISION_LIST = 0xFC,
+	GPDS_CAUSE_ACCESS_BARRED =		0xFD,
+	GPDS_CAUSE_FATAL_FAILURE =		0xFE,
+	GPDS_CAUSE_AUT_FAILURE =		0xFF,
+};
+
+enum gpds_context_type {
+	GPDS_CONT_TYPE_NORMAL =			0x00,
+	GPDS_CONT_TYPE_NWI =			0x01,
+	GPDS_CONT_TYPE_SEC =			0x02
+};
+
+enum gpds_ppp_mode {
+	GPDS_LL_FRAMED_PPP =			0x00,
+	GPDS_LL_NONFRAMED_PPP =			0x01,
+	GPDS_LL_PLAIN =				0x02
+};
+
+enum gpds_pdp_type {
+	GPDS_PDP_TYPE_PPP =			0x01,
+	GPDS_PDP_TYPE_IPV4 =			0x21,
+	GPDS_PDP_TYPE_IPV6 =			0x57,
+	GPDS_PDP_TYPE_DEFAULT =			0xFF
+};
+
+enum gpds_request_mode {
+	GPDS_FOLLOW_OFF =			0x00,
+	GPDS_FOLLOW_ON =			0x01
+};
+
+enum gpds_attach_status {
+	GPDS_DETACHED =				0x00,
+	GPDS_ATTACHED =				0x01
+};
+
+enum gpds_attach_type {
+	GPDS_ATTACH_TYPE_GPRS =			0x01
+};
+
+enum gpds_detach_type {
+	GPDS_DETACH_TYPE_GPRS_MO =		0x01
+};
+
+enum gpds_transfer_status {
+	GPDS_TRANSFER_NOT_AVAIL =		0x00,
+	GPDS_TRANSFER_AVAIL =			0x01
+};
+
+enum gpds_transfer_cause {
+	GPDS_TRANSFER_CAUSE_ATTACHED =		0x02,
+	GPDS_TRANSFER_CAUSE_DETACHED =		0x03,
+	GPDS_TRANSFER_CAUSE_RESUMED =		0x04,
+	GPDS_TRANSFER_CAUSE_SUSPENDED_NO_COVERAGE = 0x05,
+	GPDS_TRANSFER_CAUSE_SUSPENDED_CALL_SMS = 0x07,
+	GPDS_TRANSFER_CAUSE_SUSPENDED_CALL =	0x08,
+	GPDS_TRANSFER_CAUSE_SUSPENDED_RAU =	0x09,
+	GPDS_TRANSFER_CAUSE_SUSPENDED_LU =	0x0A,
+	GPDS_TRANSFER_CAUSE_DSAC_RESTRICTION =	0x0B
+};
+
+enum gpds_attach_mode {
+	GPDS_ATTACH_MODE_MANUAL =		0x00,
+	GPDS_ATTACH_MODE_AUTOMATIC =		0x01,
+	GPDS_ATTACH_MODE_DEFAULT =		0xFF
+};
+
+enum gpds_mt_act_mode {
+	GPDS_MT_ACT_MODE_REJECT =		0x00,
+	GPDS_MT_ACT_MODE_ACCEPT =		0x01,
+	GPDS_MT_ACT_MODE_DEFAULT =		0xFF
+};
+
+enum gpds_classc_mode {
+	GPDS_CLASSC_MODE_GPRS =			0x00,
+	GPDS_CLASSC_MODE_GSM =			0x01,
+	GPDS_CLASSC_MODE_DEFAULT =		0xFF
+};
+
+enum gpds_aol_context {
+	GPDS_AOL_CTX_NOT_ACTIVE =		0x00,
+	GPDS_AOL_CTX_HPLMN_ACTIVE =		0x01,
+	GPDS_AOL_CTX_VPLMN_ACTIVE =		0x02,
+	GPDS_AOL_CTX_ACTIVE =			0x03,
+	GPDS_AOL_CTX_DEFAULT =			0xFF
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* !__ISIMODEM25_GPDS_H */
diff --git a/drivers/isimodem2.5/gss.h b/drivers/isimodem2.5/gss.h
new file mode 100644
index 0000000..2c7fc68
--- /dev/null
+++ b/drivers/isimodem2.5/gss.h
@@ -0,0 +1,84 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_GSS_H
+#define __ISIMODEM25_GSS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PN_GSS 0x32
+
+enum gss_message_id {
+	GSS_CS_SERVICE_REQ =			0x00,
+	GSS_CS_SERVICE_RESP =			0x01,
+	GSS_CS_SERVICE_FAIL_RESP =		0x02,
+	GSS_CS_IND =				0x03,
+	GSS_POWER_CLASS_IND =			0x0A,
+	GSS_HSXPA_USER_SETTING_WRITE_REQ =	0x0F,
+	GSS_HSXPA_USER_SETTING_WRITE_RESP =	0x10,
+	GSS_HSXPA_USER_SETTING_IND =		0x11,
+	GSS_HSXPA_USER_SETTING_READ_REQ =	0x12,
+	GSS_HSXPA_USER_SETTING_READ_RESP =	0x13,
+	GSS_SELECTED_RAT_IND =			0x14,
+	GSS_UMA_PREF_MODE_IND =			0x15,
+	GSS_HAC_MODE_WRITE_REQ =		0x17,
+	GSS_HAC_MODE_WRITE_RESP =		0x18,
+	GSS_ENV_INFO_REQ =			0x19,
+	GSS_ENV_INFO_RESP =			0x20,
+	GSS_ENV_INFO_IND =			0x21
+};
+
+enum gss_subblock {
+	GSS_CS_LOCAL_INFO =			0x01,
+	GSS_POWER_CLASS =			0x02,
+	GSS_CS_STATUS =				0x00,
+	GSS_CELL_INFO =				0x03,
+	GSS_LONG_CELL_INFO =			0x11,
+	GSS_BAND_INFO =				0x04,
+	GSS_RAT_INFO =				0x0B,
+	GSS_ATK_TIMING_ADVANCE =		0x0C,
+	GSS_UMA_PREF_MODE_INFO =		0x0D,
+	GSS_PROV_INFO_SB_IDS =			0x10,
+	GSS_SGW_INFO =				0x0E,
+	GSS_UNC_INFO =				0x0F,
+	GSS_REL_SIGNAL_LEVEL_INFO =		0x14,
+	GSS_THRESHOLD_INFO =			0x15
+};
+
+enum gss_selection_mode {
+	GSS_GSM_RAT =				0x01,
+	GSS_UMTS_RAT =				0x02,
+	GSS_DUAL_RAT =				0x03,
+};
+
+enum gss_operation {
+	GSS_SELECTED_RAT_WRITE =		0x0E,
+	GSS_SELECTED_RAT_READ =			0x9C
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* !__ISIMODEM25_GSS_H */
diff --git a/drivers/isimodem2.5/info.h b/drivers/isimodem2.5/info.h
new file mode 100644
index 0000000..58dd118
--- /dev/null
+++ b/drivers/isimodem2.5/info.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_INFO_H
+#define __ISIMODEM25_INFO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PN_MODEM_INFO 0xC5
+
+	enum info_isi_cause {
+		M_INFO_OK = 0x00
+	};
+
+	enum info_message_id {
+		M_INFO_VERSION_READ_REQ = 0x00,
+		M_INFO_VERSION_READ_RESP = 0x01
+	};
+
+	enum info_subblock {
+		M_INFO_SB_MODEMSW_VERSION = 0x00
+	};
+
+	enum info_version_targets {
+		M_INFO_MODEMSW = 0x00000001
+	};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* !__ISIMODEM25_INFO_H */
diff --git a/drivers/isimodem2.5/isimodem.c b/drivers/isimodem2.5/isimodem.c
new file mode 100644
index 0000000..fac4d80
--- /dev/null
+++ b/drivers/isimodem2.5/isimodem.c
@@ -0,0 +1,534 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/modem.h>
+#include <gisi/client.h>
+#include <gisi/netlink.h>
+#include <ofono/log.h>
+#include <ofono/call-forwarding.h>
+#include <ofono/call-settings.h>
+#include <ofono/call-barring.h>
+#include <ofono/call-meter.h>
+#include <ofono/devinfo.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/radio-settings.h>
+#include <ofono/phonebook.h>
+#include <ofono/plugin.h>
+#include <ofono/netreg.h>
+#include <ofono/sms.h>
+#include <ofono/cbs.h>
+#include <ofono/sim.h>
+#include <ofono/ssn.h>
+#include <ofono/ussd.h>
+#include <ofono/voicecall.h>
+
+#include "debug.h"
+#include "mce.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "timeout.h"
+
+struct isi_data {
+	struct ofono_modem *modem;
+	char const *ifname;
+	GIsiModem *idx;
+	GIsiClient *client;
+	GPhonetNetlink *link;
+	unsigned interval;
+	int reported;
+	int iface_up;
+};
+
+static GPhonetNetlink *link;
+static GSList *g_modems;
+
+static struct isi_data *find_modem_by_idx(GSList *modems, GIsiModem *idx)
+{
+	GSList *m = NULL;
+
+	for (m = g_modems; m; m = m->next) {
+		struct isi_data *isi = m->data;
+
+		if (isi->idx == idx)
+			return isi;
+	}
+
+	return NULL;
+}
+
+static void mce_state_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_data *isi = opaque;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return;
+	}
+
+	DBG("%s, state %s, action %d",
+		mce_message_id_name(msg[0]),
+			mce_modem_state_name(msg[1]), msg[2]);
+
+	if (len < 3 || msg[0] != MCE_MODEM_STATE_IND)
+		return;
+
+	DBG("ofono_modem_set_powered-> %d", (msg[1] != MCE_POWER_OFF));
+	ofono_modem_set_powered(isi->modem, (msg[1] != MCE_POWER_OFF));
+	DBG("<-ofono_modem_set_powered");
+}
+
+static gboolean mce_modem_state_query_cb(GIsiClient *client,
+						const void *restrict data,
+						size_t len, uint16_t object,
+						void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_data *isi = opaque;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return TRUE;
+	}
+
+	DBG("%s, current %s, target %s", mce_message_id_name(msg[0]),
+		mce_modem_state_name(msg[1]), mce_modem_state_name(msg[2]));
+
+	if (len < 3 || msg[0] != MCE_MODEM_STATE_QUERY_RESP)
+		return FALSE;
+
+	DBG("ofono_modem_set_powered-> %d", (msg[1] != MCE_POWER_OFF));
+	ofono_modem_set_powered(isi->modem, (msg[1] != MCE_POWER_OFF));
+	DBG("<-ofono_modem_set_powered");
+	return TRUE;
+}
+
+
+
+static gboolean mce_rf_state_query_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len, uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return TRUE;
+	}
+
+	DBG("%s, current=%d, target=%d",
+		mce_message_id_name(msg[0]), msg[1], msg[2]);
+
+	if (len < 3 || msg[0] != MCE_RF_STATE_QUERY_RESP)
+		return FALSE;
+
+	/* There is no proper way to indicate RF status to oFono !! */
+	return TRUE;
+}
+
+static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
+				void *opaque)
+{
+	const unsigned char msg[] = {
+		MCE_MODEM_STATE_QUERY_REQ,
+		0x00, 0x00 /* Filler */
+	};
+	DBG("");
+
+	if (!alive) {
+		DBG("Unable to bootstrap mce driver");
+		return;
+	}
+
+	DBG("Resource %s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_isi_subscribe(client, MCE_MODEM_STATE_IND, mce_state_cb, opaque);
+	g_isi_request_make(client, msg, sizeof(msg), MCE_TIMEOUT,
+			   mce_modem_state_query_cb, opaque);
+}
+
+static void phonet_status_cb(GIsiModem *idx,
+				GPhonetLinkState st,
+				char const *ifname,
+				void *data)
+{
+	struct ofono_modem *modem = data;
+	struct isi_data *isi = ofono_modem_get_data(modem);
+
+	if (!isi)
+		return;
+
+	DBG("Link %s (%u) is %s",
+		isi->ifname, g_isi_modem_index(isi->idx),
+		st == PN_LINK_REMOVED ? "removed" :
+		st == PN_LINK_DOWN ? "down" : "up");
+	isi->iface_up = st == PN_LINK_UP;
+
+	if (st == PN_LINK_UP)
+		g_isi_verify(isi->client, reachable_cb, isi);
+	else if (st == PN_LINK_DOWN)
+		return;
+	else if (st == PN_LINK_REMOVED)
+		ofono_modem_remove(modem);
+}
+
+
+static void netlink_status_cb(GIsiModem *idx,
+				GPhonetLinkState st,
+				char const ifname[],
+				void *data)/* data not used anywhere...*/
+
+{
+	struct isi_data *isi = find_modem_by_idx(g_modems, idx);
+	DBG(" Link state= %d", st);
+
+	if (st == PN_LINK_UP) {
+		if (isi) {
+			DBG("Modem already registered: (0x%02x)",
+				g_isi_modem_index(idx));
+			return;
+		}
+
+		isi = g_new0(struct isi_data, 1);
+
+		if (!isi)
+			return;
+
+		isi->modem = ofono_modem_create(NULL, "isimodem25");
+
+		if (!isi->modem) {
+			g_free(isi);
+			return;
+		}
+
+		isi->idx = idx;
+#ifdef STE_8500_PHONET
+		verify_link_up(TRUE);
+#endif
+		ofono_modem_set_string(isi->modem, "Interface", ifname);
+		g_modems = g_slist_prepend(g_modems, isi);
+		ofono_modem_set_data(isi->modem, isi);
+		ofono_modem_register(isi->modem);
+		DBG("Done regging modem");
+	} else {
+		GPhonetNetlink *netlink;
+
+		if (!isi) {
+			DBG("Unknown modem: (0x%02x)",
+				g_isi_modem_index(idx));
+			return;
+		}
+
+#ifdef STE_8500_PHONET
+		verify_link_up(FALSE);
+#endif
+		netlink = g_pn_netlink_by_modem(idx);
+		g_pn_netlink_stop(netlink);
+		g_modems = g_slist_remove(g_modems, isi);
+		g_isi_client_destroy(isi->client);
+		DBG("Now removing modem");
+		ofono_modem_remove(isi->modem);
+		g_free(isi);
+		isi = NULL;
+	}
+}
+
+static gboolean mce_rf_state_set_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_modem_online_cb_t cb = cbd->cb;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return TRUE;
+	}
+
+	DBG("%s, status %s",
+		mce_message_id_name(msg[0]), mce_isi_cause_name(msg[1]));
+
+	if (len < 2 || msg[0] != MCE_RF_STATE_RESP)
+		goto error;
+
+	if (msg[1] != MCE_OK && msg[1] != MCE_ALREADY_ACTIVE)
+		goto error;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	DBG("Error setting RF on/off");
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static int isi_modem_probe(struct ofono_modem *modem)
+{
+	struct isi_data *isi;
+	char const *ifname = ofono_modem_get_string(modem, "Interface");
+	GIsiModem *idx;
+	GPhonetNetlink *link;
+
+	if (ifname == NULL)
+		return -EINVAL;
+
+	DBG("(%p) with %s", modem, ifname);
+	idx = g_isi_modem_by_name(ifname);
+
+	if (idx == NULL) {
+		DBG("Interface=%s: %s", ifname, strerror(errno));
+		return -errno;
+	}
+
+	link = g_pn_netlink_start(idx, phonet_status_cb, modem);
+
+	if (!link) {
+		DBG("%s: %s", ifname, strerror(errno));
+		return -errno;
+	}
+
+	isi = g_new0(struct isi_data, 1);
+
+	if (isi == NULL)
+		return -ENOMEM;
+
+	ofono_modem_set_data(isi->modem = modem, isi);
+	isi->idx = idx;
+	isi->ifname = ifname;
+	isi->link = link;
+	isi->client = g_isi_client_create(isi->idx, PN_MODEM_MCE);
+	return 0;
+}
+
+static void isi_modem_remove(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	DBG("");
+
+	if (!isi)
+		return;
+
+	ofono_modem_set_data(modem, NULL);
+	g_isi_client_destroy(isi->client);
+	g_free(isi);
+}
+
+static int isi_modem_enable(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	/*
+	 * Modem boots automatically to MCE_POWER_OFF state
+	 * and then moves automatically to MCE_NORMAL or
+	 * MCE_LOCAL mode depending about the configuration.
+	 * I think only thing to do is to listen the state
+	 * indication.
+	 */
+	const unsigned char modem_msg[] = {
+		MCE_MODEM_STATE_QUERY_REQ,
+		0x00, 0x00 /* Filler */
+	};
+	const unsigned char rf_msg[] = {
+		MCE_RF_STATE_QUERY_REQ,
+		0x00, 0x00 /* Filler */
+	};
+	DBG("");
+
+	g_isi_request_make(isi->client, modem_msg, sizeof(modem_msg),
+				MCE_TIMEOUT,
+				mce_modem_state_query_cb, isi);
+
+	g_isi_request_make(isi->client, rf_msg, sizeof(rf_msg), MCE_TIMEOUT,
+			   mce_rf_state_query_cb, modem);
+	g_isi_subscribe(isi->client, MCE_MODEM_STATE_IND, mce_state_cb, isi);
+	return 0;
+}
+
+static int isi_modem_disable(struct ofono_modem *modem)
+{
+	DBG("");
+	return 0;
+}
+
+static void isi_modem_set_online(struct ofono_modem *modem, ofono_bool_t online,
+					ofono_modem_online_cb_t cb, void *data)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	struct isi_cb_data *cbd = isi_cb_data_new(isi, cb, data);
+	const unsigned char msg[] = {
+		MCE_RF_STATE_REQ,
+		online ? MCE_RF_ON : MCE_RF_OFF,
+		0x00    /* Filler */
+	};
+	DBG("");
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(isi->client, msg, sizeof(msg), MCE_TIMEOUT,
+				mce_rf_state_set_cb, cbd))
+		return;
+
+error:
+	DBG("Online/offline setting failed");
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static void isi_modem_pre_sim(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	DBG("(%p) with %s", modem, isi->ifname);
+	ofono_sim_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_devinfo_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_voicecall_create(isi->modem, 0, "isimodem25", isi->idx);
+}
+
+static void isi_modem_post_sim(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	DBG("(%p) with %s", modem, isi->ifname);
+	ofono_phonebook_create(isi->modem, 0, "isimodem25", isi->idx);
+}
+
+static void isi_modem_post_online(struct ofono_modem *modem)
+{
+	struct isi_data *isi = ofono_modem_get_data(modem);
+	struct ofono_gprs *gprs;
+	struct ofono_gprs_context *gc;
+	DBG("(%p) with %s", modem, isi->ifname);
+	ofono_netreg_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_sms_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_cbs_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_ssn_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_ussd_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_call_forwarding_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_call_settings_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_call_barring_create(isi->modem, 0, "isimodem25", isi->idx);
+	ofono_radio_settings_create(isi->modem, 0, "isimodem25", isi->idx);
+	gprs = ofono_gprs_create(isi->modem, 0, "isimodem25", isi->idx);
+	gc = ofono_gprs_context_create(isi->modem, 0, "isimodem25", isi->idx);
+
+	if (gprs && gc)
+		ofono_gprs_add_context(gprs, gc);
+	else
+		DBG("Failed to add context");
+}
+
+static struct ofono_modem_driver driver = {
+	.name = "isimodem25",
+	.probe = isi_modem_probe,
+	.remove = isi_modem_remove,
+	.enable = isi_modem_enable,
+	.disable = isi_modem_disable,
+	.set_online = isi_modem_set_online,
+	.pre_sim = isi_modem_pre_sim,
+	.post_sim = isi_modem_post_sim,
+	.post_online = isi_modem_post_online
+};
+
+static int isimodem_init(void)
+{
+	link = NULL;
+	g_modems = NULL;
+	DBG("");
+	g_pn_netlink_start(NULL, netlink_status_cb, NULL);
+	isi_devinfo_init();
+	isi_phonebook_init();
+	isi_netreg_init();
+	isi_voicecall_init();
+	isi_sms_init();
+	isi_cbs_init();
+	isi_sim_init();
+	isi_ssn_init();
+	isi_ussd_init();
+	isi_call_settings_init();
+	isi_call_barring_init();
+	isi_call_forwarding_init();
+	isi_radio_settings_init();
+	isi_gprs_init();
+	isi_gprs_context_init();
+	ofono_modem_driver_register(&driver);
+	return 0;
+}
+
+static void isimodem_exit(void)
+{
+	GSList *m;
+
+	for (m = g_modems; m; m = m->next) {
+		struct isi_data *isi = m->data;
+		ofono_modem_remove(isi->modem);
+		g_free(isi);
+	}
+
+	g_slist_free(g_modems);
+	g_modems = NULL;
+
+	if (link) {
+		g_pn_netlink_stop(link);
+		link = NULL;
+	}
+
+	ofono_modem_driver_unregister(&driver);
+	isi_devinfo_exit();
+	isi_phonebook_exit();
+	isi_netreg_exit();
+	isi_voicecall_exit();
+	isi_sms_exit();
+	isi_cbs_exit();
+	isi_sim_exit();
+	isi_ssn_exit();
+	isi_ussd_exit();
+	isi_call_settings_exit();
+	isi_call_barring_exit();
+	isi_call_forwarding_exit();
+	isi_radio_settings_exit();
+	isi_gprs_exit();
+	isi_gprs_context_exit();
+}
+
+OFONO_PLUGIN_DEFINE(isimodem25, "PhoNet / ISI modem 2.5 driver", VERSION,
+		    OFONO_PLUGIN_PRIORITY_DEFAULT, isimodem_init, isimodem_exit)
diff --git a/drivers/isimodem2.5/isimodem.h b/drivers/isimodem2.5/isimodem.h
new file mode 100644
index 0000000..4fdd2a8
--- /dev/null
+++ b/drivers/isimodem2.5/isimodem.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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
+ *
+ */
+
+extern void isi_phonebook_init();
+extern void isi_phonebook_exit();
+
+extern void isi_devinfo_init();
+extern void isi_devinfo_exit();
+
+extern void isi_netreg_init();
+extern void isi_netreg_exit();
+
+extern void isi_voicecall_init();
+extern void isi_voicecall_exit();
+
+extern void isi_sms_init();
+extern void isi_sms_exit();
+
+extern void isi_cbs_init();
+extern void isi_cbs_exit();
+
+extern void isi_sim_init();
+extern void isi_sim_exit();
+
+extern void isi_ussd_init();
+extern void isi_ussd_exit();
+
+extern void isi_ssn_init();
+extern void isi_ssn_exit();
+
+extern void isi_call_forwarding_init();
+extern void isi_call_forwarding_exit();
+
+extern void isi_call_settings_init();
+extern void isi_call_settings_exit();
+
+extern void isi_call_barring_init();
+extern void isi_call_barring_exit();
+
+extern void isi_call_meter_init();
+extern void isi_call_meter_exit();
+
+extern void isi_radio_settings_init();
+extern void isi_radio_settings_exit();
+
+extern void isi_gprs_init();
+extern void isi_gprs_exit();
+
+extern void isi_gprs_context_init();
+extern void isi_gprs_context_exit();
diff --git a/drivers/isimodem2.5/isiutil.h b/drivers/isimodem2.5/isiutil.h
new file mode 100644
index 0000000..dd5eed1
--- /dev/null
+++ b/drivers/isimodem2.5/isiutil.h
@@ -0,0 +1,64 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM_UTIL_H
+#define __ISIMODEM_UTIL_H
+
+struct isi_cb_data {
+	void *cb;
+	void *data;
+	void *user;
+};
+
+static inline struct isi_cb_data *isi_cb_data_new(void *user, void *cb,
+							void *data)
+{
+	struct isi_cb_data *ret;
+
+	ret = g_try_new0(struct isi_cb_data, 1);
+
+	if (ret) {
+		ret->cb = cb;
+		ret->data = data;
+		ret->user = user;
+	}
+
+	return ret;
+}
+
+#define CALLBACK_WITH_FAILURE(f, args...)				\
+		do {							\
+				struct ofono_error e;			\
+				e.type = OFONO_ERROR_TYPE_FAILURE;	\
+				e.error = 0;				\
+				f(&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 /* !__ISIMODEM_UTIL_H */
diff --git a/drivers/isimodem2.5/mce.h b/drivers/isimodem2.5/mce.h
new file mode 100644
index 0000000..5584b98
--- /dev/null
+++ b/drivers/isimodem2.5/mce.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_MCE_H
+#define __ISIMODEM25_MCE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PN_MODEM_MCE 0xC2
+
+	enum mce_message_id {
+		MCE_MODEM_STATE_IND =		0x00,
+		MCE_MODEM_STATE_QUERY_REQ =	0x01,
+		MCE_MODEM_STATE_QUERY_RESP =	0x02,
+		MCE_RF_STATE_REQ =		0x03,
+		MCE_RF_STATE_RESP =		0x04,
+		MCE_RF_STATE_IND =		0x05,
+		MCE_RF_STATE_QUERY_REQ =	0x06,
+		MCE_RF_STATE_QUERY_RESP =	0x07,
+		MCE_POWER_OFF_REQ =		0x08,
+		MCE_POWER_OFF_RESP =		0x09
+	};
+	enum mce_rf_state {
+		MCE_RF_OFF =			0x00,
+		MCE_RF_ON =			0x01
+	};
+	enum mce_status_info {
+		MCE_OK =			0x00,
+		MCE_FAIL =			0x01,
+		MCE_ALREADY_ACTIVE =		0x06,
+		MCE_TRANSITION_ONGOING =	0x16
+	};
+	enum mce_modem_state {
+		MCE_NORMAL =			0x00,
+		MCE_LOCAL =			0x01,
+		MCE_SW_RESET =			0x80,
+		MCE_POWER_OFF =			0x81
+	};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __ISIMODEM25_MCE_H */
diff --git a/drivers/isimodem2.5/network-registration.c b/drivers/isimodem2.5/network-registration.c
new file mode 100644
index 0000000..22d6026
--- /dev/null
+++ b/drivers/isimodem2.5/network-registration.c
@@ -0,0 +1,1158 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <ofono/modem.h>
+#include <common.h>
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/netreg.h>
+
+#include "debug.h"
+#include "network.h"
+#include "isimodem.h"
+#include "isiutil.h"
+
+struct netreg_data {
+	GIsiClient *client;
+	guint8 last_reg_mode;
+	guint8 rat;
+	guint8 gsm_compact;
+	gboolean cs_active;	/*
+				 * CS active or inactive. If inactive all
+				 * requests to NET server are rejected.
+				 */
+};
+
+static inline guint8 *mccmnc_to_bcd(const char *mcc, const char *mnc,
+					guint8 *bcd)
+{
+	bcd[0] = (mcc[0] - '0') | (mcc[1] - '0') << 4;
+	bcd[1] = (mcc[2] - '0');
+	bcd[1] |= (mnc[2] == '\0' ? 0x0f : (mnc[2] - '0')) << 4;
+	bcd[2] = (mnc[0] - '0') | (mnc[1] - '0') << 4;
+	return bcd;
+}
+
+static inline int isi_status_to_at_status(guint8 status)
+{
+	switch (status) {
+	case NET_REG_STATUS_NOSERV:
+	case NET_REG_STATUS_NOSERV_NOTSEARCHING:
+	case NET_REG_STATUS_NOSERV_NOSIM:
+	case NET_REG_STATUS_POWER_OFF:
+	case NET_REG_STATUS_NSPS:
+	case NET_REG_STATUS_NSPS_NO_COVERAGE:
+		return NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
+	case NET_REG_STATUS_HOME:
+		return NETWORK_REGISTRATION_STATUS_REGISTERED;
+	case NET_REG_STATUS_NOSERV_SEARCHING:
+		return NETWORK_REGISTRATION_STATUS_SEARCHING;
+	case NET_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW:
+		return NETWORK_REGISTRATION_STATUS_DENIED;
+	case NET_REG_STATUS_ROAM:
+		return NETWORK_REGISTRATION_STATUS_ROAMING;
+	default:
+		return NETWORK_REGISTRATION_STATUS_UNKNOWN;
+	}
+}
+
+static gboolean decode_reg_status(struct netreg_data *nd, const guint8 *msg,
+					size_t len, int *status, int *lac,
+					int *ci, int *tech)
+{
+	GIsiSubBlockIter iter;
+	g_isi_sb_iter_init(&iter, msg, len, 0);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+		    net_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case NET_MODEM_REG_INFO_COMMON: {
+			guint8 byte = 0;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &byte, 2))
+				return FALSE;
+
+			if (!g_isi_sb_iter_get_byte(&iter,
+							&nd->last_reg_mode, 3))
+				return FALSE;
+
+			*status = byte;
+			break;
+		}
+		case NET_MODEM_GSM_REG_INFO: {
+			guint16 word = 0;
+			guint32 dword = 0;
+			guint8 egprs = 0;
+			guint8 hsdpa = 0;
+			guint8 hsupa = 0;
+
+			if (!g_isi_sb_iter_get_word(&iter, &word, 2) ||
+				!g_isi_sb_iter_get_dword(&iter, &dword, 4) ||
+				!g_isi_sb_iter_get_byte(&iter, &egprs, 17) ||
+				!g_isi_sb_iter_get_byte(&iter, &hsdpa, 20) ||
+				!g_isi_sb_iter_get_byte(&iter, &hsupa, 21))
+				return FALSE;
+
+			*ci = (int)dword;
+			*lac = (int)word;
+
+			switch (nd->rat) {
+			case NET_GSM_RAT:
+				*tech = ACCESS_TECHNOLOGY_GSM;
+
+				if (nd->gsm_compact)
+					*tech = ACCESS_TECHNOLOGY_GSM_COMPACT;
+				else if (egprs)
+					*tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
+
+				break;
+			case NET_UMTS_RAT:
+				*tech = 2;
+
+				if (hsdpa)
+					*tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
+
+				if (hsupa)
+					*tech = ACCESS_TECHNOLOGY_UTRAN_HSUPA;
+
+				if (hsdpa && hsupa)
+					*tech =
+					  ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
+
+				break;
+			default:
+				*tech = ACCESS_TECHNOLOGY_GSM;
+			}
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zu bytes)",
+				net_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	DBG("status=%d, lac=%d, ci=%d, tech=%d",
+		(*status), *lac, *ci, *tech);
+	return TRUE;
+}
+
+static void cs_power_on_req(GIsiClient *client)
+{
+	const unsigned char msg[] = {
+		NET_CS_CONTROL_REQ,
+		0x03,
+		0x00, /* Sub-block count */
+	};
+	DBG("");
+
+	/* Just send message, ignore the reponse */
+	g_isi_request_make(client, msg, sizeof(msg),
+				NETWORK_SET_TIMEOUT,
+				NULL , NULL);
+}
+
+static void reg_status_ind_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_netreg *netreg = opaque;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	int status = -1;
+	int lac = -1;
+	int ci = -1;
+	int tech = -1;
+
+	if (!msg || len < 3 || msg[0] != NET_MODEM_REG_STATUS_IND)
+		return;
+
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (decode_reg_status(nd, msg + 3,
+					len - 3,
+					&status,
+					&lac, &ci,
+					&tech)) {
+		status = isi_status_to_at_status(status);
+		ofono_netreg_status_notify(netreg, status, lac, ci, tech);
+	}
+}
+
+static gboolean reg_status_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	struct ofono_netreg *netreg = cbd->user;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	ofono_netreg_status_cb_t cb = cbd->cb;
+	int status = -1;
+	int lac = -1;
+	int ci = -1;
+	int tech = -1;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (len < 3 || msg[0] != NET_MODEM_REG_STATUS_GET_RESP)
+		goto error;
+
+	if (msg[1] != NET_CAUSE_OK) {
+		DBG("Request failed: %s", net_isi_cause_name(msg[1]));
+		goto error;
+	}
+
+	if (decode_reg_status(nd, msg + 3,
+				len - 3,
+				&status,
+				&lac,
+				&ci,
+				&tech)) {
+		DBG("status=%d, lac=%d, ci=%d, tech=%d", status, lac, ci, tech);
+		CALLBACK_WITH_SUCCESS(cb, isi_status_to_at_status(status),
+					lac, ci, tech, cbd->data);
+		goto out;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_registration_status(struct ofono_netreg *netreg,
+					ofono_netreg_status_cb_t cb,
+					void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct isi_cb_data *cbd = isi_cb_data_new(netreg, cb, data);
+	const unsigned char msg[] = {
+		NET_MODEM_REG_STATUS_GET_REQ
+	};
+
+	if (!cbd || !nd)
+		goto error;
+
+	if (g_isi_request_make(nd->client, msg, sizeof(msg),
+				NETWORK_TIMEOUT,
+				reg_status_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data);
+	g_free(cbd);
+}
+
+/* This replaces the isimodem name_get_resp_cb */
+static gboolean cell_info_get_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	struct isi_cb_data *cbd = opaque;
+	const unsigned char *msg = data;
+	ofono_netreg_operator_cb_t cb = cbd->cb;
+	struct ofono_network_operator op;
+	GIsiSubBlockIter iter;
+	memset(&op, 0, sizeof(struct ofono_network_operator));
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (len < 3 || msg[0] != NET_CELL_INFO_GET_RESP)
+		return FALSE;
+
+	if (msg[1] != NET_CAUSE_OK) {
+		DBG("Request failed: %s", net_isi_cause_name(msg[1]));
+		goto error;
+	}
+
+	g_isi_sb_iter_init(&iter, msg, len, 3);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			net_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case NET_GSM_CELL_INFO:
+
+			if (!g_isi_sb_iter_get_oper_code(&iter,
+							 op.mcc, op.mnc, 12))
+				goto error;
+
+			op.tech = 0; /*ACCESS_TECHNOLOGY_GSM;*/
+			/* NOTE: Operator name, status not updated here !!!*/
+			DBG("NET_GSM_CELL_INFO name=%s mcc=%s mnc=%s tech=%d",
+			    op.name, op.mcc, op.mnc, op.tech);
+			break;
+		case NET_WCDMA_CELL_INFO:
+
+			if (!g_isi_sb_iter_get_oper_code(&iter,
+							 op.mcc, op.mnc, 12))
+				goto error;
+
+			op.tech = 2; /*ACCESS_TECHNOLOGY_UTRAN;*/
+			/* NOTE: Operator name, status not updated here */
+			DBG("NET_WCDMA_CELL_INFO name=%s mcc=%s mnc=%s tech=%d",
+			    op.name, op.mcc, op.mnc, op.tech);
+			break;
+		default:
+			DBG("Skipping sub-block: %s (%zu bytes)",
+				net_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, &op, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+
+static void isi_current_operator(struct ofono_netreg *netreg,
+					ofono_netreg_operator_cb_t cb,
+					void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct isi_cb_data *cbd = isi_cb_data_new(netreg, cb, data);
+	const unsigned char msg[] = {
+		NET_CELL_INFO_GET_REQ
+	};
+	DBG("");
+
+	if (!cbd || !nd)
+		goto error;
+
+	if (g_isi_request_make(nd->client, msg, sizeof(msg),
+				NETWORK_TIMEOUT,
+				cell_info_get_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, NULL, data);
+	g_free(cbd);
+}
+
+
+static gboolean available_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_netreg_operator_list_cb_t cb = cbd->cb;
+	struct ofono_network_operator *list = NULL;
+	int total = 0;
+	GIsiSubBlockIter iter;
+	int common = 0;
+	int detail = 0;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (len < 3 || msg[0] != NET_MODEM_AVAILABLE_GET_RESP)
+		return FALSE;
+
+	if (msg[1] != NET_CAUSE_OK) {
+		DBG("Request failed: %s", net_isi_cause_name(msg[1]));
+		goto error;
+	}
+
+	/* Each description of an operator has a pair of sub-blocks */
+	total = msg[2] / 2;
+	list = alloca(total * sizeof(struct ofono_network_operator));
+	memset(list, 0, total * sizeof(struct ofono_network_operator));
+	g_isi_sb_iter_init(&iter, msg, len, 3);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		struct ofono_network_operator *op = NULL;
+		DBG("Sub-block %s",
+			net_subblock_name(g_isi_sb_iter_get_id(&iter)));
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case NET_MODEM_AVAIL_NETWORK_INFO_COMMON: {
+			guint8 status = 0;
+			guint8 mode = 0; /* Not used !!! */
+
+			if (!g_isi_sb_iter_get_byte(&iter, &status, 2))
+				goto error;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &mode, 3))
+				goto error;
+
+			DBG("NET_MODEM_AVAIL_NETWORK_INFO_COMMON \
+				status=%d, mode=%d",
+				status, mode);
+			op = list + common++;
+			op->status = status;
+			break;
+		}
+		case NET_MODEM_DETAILED_NETWORK_INFO: {
+			uint16_t lac = 0;
+			op = list + detail++;
+
+			if (!g_isi_sb_iter_get_oper_code(&iter, op->mcc,
+								op->mnc, 2))
+				goto error;
+
+			if (!g_isi_sb_iter_get_word(&iter, &lac, 8))
+				goto error;
+
+			op->name[0] = 0;
+			DBG("NET_MODEM_DETAILED_NETWORK_INFO name=%s \
+				mcc=%s mnc=%s lac=%d",
+				op->name, op->mcc, op->mnc, lac);
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zu bytes)",
+				net_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	if (common == detail && detail == total) {
+		CALLBACK_WITH_SUCCESS(cb, total, list, cbd->data);
+		goto out;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(netreg, cb, data);
+
+	if (!nd)
+		return;
+	else {
+		const unsigned char msg[] = {
+			NET_MODEM_AVAILABLE_GET_REQ,
+			NET_MANUAL_SEARCH,
+			0x01,	/* Sub-block count */
+			NET_MODEM_GSM_BAND_INFO,
+			0x04,	/* Sub-block length */
+			NET_GSM_BAND_ALL_SUPPORTED_BANDS,
+			0x00
+		};
+		DBG("NET_MODEM_AVAILABLE_GET_REQ");
+
+		/* Activate CS in case inactive */
+		if (nd->cs_active == FALSE)
+			cs_power_on_req(nd->client);
+
+		if (!cbd || !nd)
+			goto error;
+
+		if (g_isi_request_make(nd->client, msg, sizeof(msg),
+					NETWORK_SCAN_TIMEOUT,
+					available_resp_cb, cbd))
+			return;
+	}
+error:
+	CALLBACK_WITH_FAILURE(cb, 0, NULL, data);
+	g_free(cbd);
+}
+
+static gboolean set_auto_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	struct netreg_data *net = cbd->user;
+	ofono_netreg_register_cb_t cb = cbd->cb;
+	int error;
+
+	if (!msg) {
+		error = g_isi_client_error(client);
+		DBG("ISI client error: %d", error);
+
+		if (error == -ESHUTDOWN)
+			goto out;
+
+		goto error;
+	}
+
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (!msg || len < 3 || msg[0] != NET_SET_RESP)
+		goto error;
+
+	if (msg[1] != NET_CAUSE_OK) {
+		DBG("Request failed: %s", net_isi_cause_name(msg[1]));
+		goto error;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	net->last_reg_mode = NET_SELECT_MODE_AUTOMATIC;
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_register_auto(struct ofono_netreg *netreg,
+				ofono_netreg_register_cb_t cb,
+				void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct isi_cb_data *cbd = isi_cb_data_new(netreg, cb, data);
+
+	if (!nd)
+		return;
+	else {
+		const unsigned char msg[] = {
+			NET_SET_REQ,
+			0x00,	/* Registered in another protocol? */
+			0x01,	/* Sub-block count */
+			NET_OPERATOR_INFO_COMMON,
+			0x04,	/* Sub-block length */
+			nd->last_reg_mode == NET_SELECT_MODE_AUTOMATIC
+				? NET_SELECT_MODE_USER_RESELECTION
+				: NET_SELECT_MODE_AUTOMATIC,
+			0x00	/* Index not used */
+		};
+
+		/* Activate CS in case inactive */
+		if (nd->cs_active == FALSE)
+			cs_power_on_req(nd->client);
+
+		if (nd->last_reg_mode == NET_SELECT_MODE_AUTOMATIC)
+			DBG("isi_register_auto: \
+					NET_SELECT_MODE_USER_RESELECTION");
+		else
+			DBG("isi_register_auto: NET_SELECT_MODE_AUTOMATIC");
+
+		if (!cbd || !nd)
+			goto error;
+
+		if (g_isi_request_make(nd->client, msg, sizeof(msg),
+					NETWORK_SET_TIMEOUT,
+					set_auto_resp_cb, cbd))
+			return;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static gboolean set_manual_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	struct ofono_netreg *netreg = cbd->user;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	ofono_netreg_register_cb_t cb = cbd->cb;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (len < 3 || msg[0] != NET_SET_RESP)
+		goto error;
+
+	if (msg[1] != NET_CAUSE_OK) {
+		DBG("Request failed: %s", net_isi_cause_name(msg[1]));
+		goto error;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	nd->last_reg_mode = NET_SELECT_MODE_MANUAL;
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(netreg, cb, data);
+
+	if (!nd)
+		return;
+	else {
+		guint8 buffer[3] = { 0 };
+		guint8 *bcd = mccmnc_to_bcd(mcc, mnc, buffer);
+		const unsigned char msg[] = {
+			NET_SET_REQ,
+			0x00, /* Registered in another protocol? */
+			0x03, /* Sub-block count */
+			NET_OPERATOR_INFO_COMMON,
+			0x04, /* Sub-block length */
+			NET_SELECT_MODE_MANUAL,
+			0x00, /* Index not used */
+			NET_MODEM_GSM_OPERATOR_INFO,
+			0x08, /* Sub-block length */
+			bcd[0], bcd[1], bcd[2],
+			NET_GSM_BAND_INFO_NOT_AVAIL, /* Pick any band */
+			0x00, 0x00, /* Filler */
+		};
+		DBG("NET_SET_REQ manual, mcc=%s, mnc=%s", mcc, mnc);
+
+		/* Activate CS in case inactive */
+		if (nd->cs_active == FALSE)
+			cs_power_on_req(nd->client);
+
+		if (!cbd || !nd)
+			goto error;
+
+		if (g_isi_request_make(nd->client, msg, sizeof(msg),
+					NETWORK_SET_TIMEOUT,
+					set_manual_resp_cb, cbd))
+			return;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static gboolean deregister_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_netreg_register_cb_t cb = cbd->cb;
+	DBG("");
+
+	if (msg[0] != NET_CS_CONTROL_RESP)
+		return FALSE;
+
+	if (msg[2] != NET_CAUSE_OK) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+		return TRUE;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	DBG("EXIT OK");
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_deregister(struct ofono_netreg *netreg,
+				ofono_netreg_register_cb_t cb,
+				void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct isi_cb_data *cbd = isi_cb_data_new(netreg, cb, data);
+	const unsigned char msg[] = {
+		NET_CS_CONTROL_REQ,
+		0x02,
+		0x00,
+	};
+	DBG("");
+
+	if (!cbd || !nd)
+		goto error;
+
+	if (g_isi_request_make(nd->client, msg, sizeof(msg),
+				NETWORK_SET_TIMEOUT,
+				deregister_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+
+static void nitz_name_ind_cb(GIsiClient *client, const void *restrict data,
+			size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_network_operator op;
+	GIsiSubBlockIter iter;
+
+	if (!msg || len < 3 || msg[0] != NET_NITZ_NAME_IND)
+		return;
+
+	memset(&op, 0, sizeof(struct ofono_network_operator));
+	DBG("%s", net_message_id_name(msg[0]));
+	g_isi_sb_iter_init(&iter, msg, len, 7);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			net_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case NET_FULL_NITZ_NAME:
+		case NET_SHORT_NITZ_NAME: {
+			char *tag = NULL;
+			guint8 taglen = 0;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &taglen, 5)
+				|| !g_isi_sb_iter_get_alpha_tag(&iter, &tag,
+								taglen * 2, 7))
+				return;
+
+			strncpy(op.name, tag, OFONO_MAX_OPERATOR_NAME_LENGTH);
+			op.name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0';
+			g_free(tag);
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zu bytes)",
+				net_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	/* TODO Here we should notify framework once it
+	 * supports this indication e.g.
+	 * ofono_netreg_name_notify(netreg, op.name);
+	 */
+}
+
+static void rat_ind_cb(GIsiClient *client, const void *restrict data,
+			size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_netreg *netreg = opaque;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	GIsiSubBlockIter iter;
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (!msg || len < 3 || msg[0] != NET_RAT_IND)
+		return;
+
+	g_isi_sb_iter_init(&iter, msg, len, 3);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			net_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case NET_RAT_INFO: {
+			guint8 info = 0;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &nd->rat, 2)
+				|| !g_isi_sb_iter_get_byte(&iter, &info, 3))
+				return;
+
+			DBG("RAT=%d, info len=%d", nd->rat, info);
+
+			if (info) {
+				(void) g_isi_sb_iter_get_byte(&iter,
+							&nd->gsm_compact,
+							4);
+			}
+
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zu bytes)",
+				net_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+}
+
+static gboolean rat_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_netreg *netreg = opaque;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	GIsiSubBlockIter iter;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return FALSE;
+	}
+
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (len < 3 || msg[0] != NET_RAT_RESP)
+		return FALSE;
+
+	if (msg[1] != NET_CAUSE_OK) {
+		DBG("Request failed: %s", net_isi_cause_name(msg[1]));
+		return TRUE;
+	}
+
+	g_isi_sb_iter_init(&iter, msg, len, 3);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			net_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case NET_RAT_INFO: {
+			guint8 info_len = 0;
+			g_isi_sb_iter_get_byte(&iter, &nd->rat, 2);
+			g_isi_sb_iter_get_byte(&iter, &info_len, 3);
+
+			if (info_len)
+				g_isi_sb_iter_get_byte(&iter, &nd->gsm_compact,
+							 4);
+
+			DBG("Current RAT %d, info len=%d", nd->rat, info_len);
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zu bytes)",
+				net_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	return TRUE;
+}
+
+static void rssi_ind_cb(GIsiClient *client, const void *restrict data,
+			size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_netreg *netreg = opaque;
+
+	if (!msg || len < 3 || msg[0] != NET_RSSI_IND)
+		return;
+
+	DBG("%s", net_message_id_name(msg[0]));
+	ofono_netreg_strength_notify(netreg, msg[1]);
+}
+
+static void cs_state_ind_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_netreg *netreg = opaque;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	gboolean new_state = FALSE;
+	DBG("");
+
+	if (!msg || len < 3 || msg[0] != NET_CS_STATE_IND)
+		return;
+
+	if (msg[1] == 0x01) /* active */
+		new_state = TRUE;
+
+	nd->cs_active = new_state;
+	DBG("CS active %d", nd->cs_active);
+}
+
+static gboolean cs_state_resp_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_netreg *netreg = opaque;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	gboolean new_state = FALSE;
+	DBG("");
+
+	if (!msg || len < 3 || msg[0] != NET_CS_STATE_RESP)
+		return FALSE;
+
+	if (msg[2] == 0x01)
+		new_state = TRUE;
+
+	nd->cs_active = new_state;
+	DBG("CS active %d", nd->cs_active);
+	return TRUE;
+}
+
+static gboolean rssi_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_netreg_strength_cb_t cb = cbd->cb;
+	GIsiSubBlockIter iter;
+	int strength = -1;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s", net_message_id_name(msg[0]));
+
+	if (len < 3 || msg[0] != NET_RSSI_GET_RESP)
+		return FALSE;
+
+	if (msg[1] != NET_CAUSE_OK) {
+		DBG("Request failed: 0x%02X", msg[1]);
+		goto error;
+	}
+
+	g_isi_sb_iter_init(&iter, msg, len, 3);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			net_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case NET_RSSI_CURRENT: {
+			guint8 rssi = 0;
+
+			if (!g_isi_sb_iter_get_byte(&iter, &rssi, 2))
+				goto error;
+
+			strength = rssi != 0 ? rssi : -1;
+			break;
+		}
+		default:
+			DBG("Skipping sub-block: %s (%zd bytes)",
+				net_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, strength, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_strength(struct ofono_netreg *netreg,
+				ofono_netreg_strength_cb_t cb,
+				void *data)
+{
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	struct isi_cb_data *cbd = isi_cb_data_new(netreg, cb, data);
+	const unsigned char msg[] = {
+		NET_RSSI_GET_REQ,
+		NET_CS_GSM,
+		NET_CURRENT_CELL_RSSI,
+		0, 0, 0, 0 /* Week 18 specs requires these */
+	};
+
+	if (!cbd || !nd)
+		goto error;
+
+	if (g_isi_request_make(nd->client, msg, sizeof(msg),
+				NETWORK_TIMEOUT,
+				rssi_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, data);
+	g_free(cbd);
+}
+
+static gboolean isi_netreg_register(gpointer user)
+{
+	struct ofono_netreg *netreg = user;
+	struct netreg_data *nd = ofono_netreg_get_data(netreg);
+	const unsigned char rat[] = {
+		NET_RAT_REQ,
+		NET_CURRENT_RAT
+	};
+	const unsigned char cs_state[] = {
+		NET_CS_STATE_REQ
+	};
+	DBG("");
+
+	if (!nd)
+		return FALSE;
+
+	g_isi_subscribe(nd->client, NET_RSSI_IND, rssi_ind_cb, netreg);
+	g_isi_subscribe(nd->client, NET_MODEM_REG_STATUS_IND, reg_status_ind_cb,
+			netreg);
+	g_isi_subscribe(nd->client, NET_RAT_IND, rat_ind_cb, netreg);
+	g_isi_subscribe(nd->client,
+			NET_NITZ_NAME_IND, nitz_name_ind_cb, netreg);
+	g_isi_subscribe(nd->client, NET_CS_STATE_IND, cs_state_ind_cb, netreg);
+	/* Bootstrap current RAT setting */
+	DBG("NET_RAT_REQ,NET_CURRENT_RAT");
+
+	if (!g_isi_request_make(nd->client, rat, sizeof(rat),
+				NETWORK_TIMEOUT,
+				rat_resp_cb, netreg)) {
+		DBG("Failed to bootstrap RAT");
+	}
+
+	DBG("NET_CS_STATE_REQ");
+
+	if (!g_isi_request_make(nd->client, cs_state, sizeof(cs_state),
+				NETWORK_TIMEOUT,
+				cs_state_resp_cb, netreg)) {
+		DBG("Failed to query CS state");
+	}
+
+	ofono_netreg_register(netreg);
+	return FALSE;
+}
+
+static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
+			 void *opaque)
+{
+	struct ofono_netreg *netreg = opaque;
+
+	if (!alive) {
+		DBG("Unable to bootsrap netreg driver");
+		return;
+	}
+
+	DBG("Resource %s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_idle_add(isi_netreg_register, netreg);
+}
+
+static int isi_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
+				void *user)
+{
+	GIsiModem *idx = user;
+	struct netreg_data *nd = g_try_new0(struct netreg_data, 1);
+
+	if (!nd)
+		return -ENOMEM;
+
+	nd->client = g_isi_client_create(idx, PN_MODEM_NETWORK);
+
+	if (!nd->client) {
+		g_free(nd);
+		return -ENOMEM;
+	}
+
+	ofono_netreg_set_data(netreg, nd);
+	g_isi_verify(nd->client, reachable_cb, netreg);
+	nd->cs_active = FALSE; /* Assume CS is inactive (updated later) */
+	return 0;
+}
+
+static void isi_netreg_remove(struct ofono_netreg *net)
+{
+	struct netreg_data *data = ofono_netreg_get_data(net);
+
+	if (data) {
+		g_isi_client_destroy(data->client);
+		g_free(data);
+	}
+}
+
+static struct ofono_netreg_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_netreg_probe,
+	.remove			= isi_netreg_remove,
+	.registration_status	= isi_registration_status,
+	.current_operator	= isi_current_operator,
+	.list_operators		= isi_list_operators,
+	.register_auto		= isi_register_auto,
+	.register_manual	= isi_register_manual,
+	.deregister		= isi_deregister,
+	.strength		= isi_strength,
+};
+
+void isi_netreg_init()
+{
+	ofono_netreg_driver_register(&driver);
+}
+
+void isi_netreg_exit()
+{
+	ofono_netreg_driver_unregister(&driver);
+}
diff --git a/drivers/isimodem2.5/network.h b/drivers/isimodem2.5/network.h
new file mode 100644
index 0000000..2fbd586
--- /dev/null
+++ b/drivers/isimodem2.5/network.h
@@ -0,0 +1,257 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_NETWORK_H
+#define __ISIMODEM25_NETWORK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PN_MODEM_NETWORK				0xC8
+#define NETWORK_TIMEOUT					5
+#define NETWORK_SCAN_TIMEOUT				180
+#define NETWORK_SET_TIMEOUT				240
+
+enum net_message_id {
+	NET_MODEM_REG_STATUS_GET_REQ =			0x00,
+	NET_MODEM_REG_STATUS_GET_RESP =			0x01,
+	NET_MODEM_REG_STATUS_IND =			0x02,
+	NET_MODEM_AVAILABLE_GET_REQ =			0x03,
+	NET_MODEM_AVAILABLE_GET_RESP =			0x04,
+	NET_AVAILABLE_CANCEL_REQ =			0x05,
+	NET_AVAILABLE_CANCEL_RESP =			0x06,
+	NET_SET_REQ =					0x07,
+	NET_SET_RESP =					0x08,
+	NET_SET_CANCEL_REQ =				0x09,
+	NET_SET_CANCEL_RESP =				0x0A,
+	NET_RSSI_GET_REQ =				0x0B,
+	NET_RSSI_GET_RESP =				0x0C,
+	NET_CS_CONTROL_REQ =				0x0D,
+	NET_CS_CONTROL_RESP =				0x0E,
+	NET_CS_WAKEUP_REQ =				0x0F,
+	NET_CS_WAKEUP_RESP =				0x10,
+	NET_TEST_CARRIER_REQ =				0x11,
+	NET_TEST_CARRIER_RESP =				0x12,
+	NET_CS_STATE_IND =				0x19,
+	NET_NEIGHBOUR_CELLS_REQ =			0x1A,
+	NET_NEIGHBOUR_CELLS_RESP =			0x1B,
+	NET_NETWORK_SELECT_MODE_SET_REQ =		0x1C,
+	NET_NETWORK_SELECT_MODE_SET_RESP =		0x1D,
+	NET_RSSI_IND =					0x1E,
+	NET_CIPHERING_IND =				0x20,
+	NET_TIME_IND =					0x27,
+	NET_CHANNEL_INFO_IND =				0x2C,
+	NET_CHANNEL_INFO_REQ =				0x2D,
+	NET_CHANNEL_INFO_RESP =				0x2E,
+	NET_RAT_IND =					0x35,
+	NET_RAT_REQ =					0x36,
+	NET_RAT_RESP =					0x37,
+	NET_CS_STATE_REQ =				0x3A,
+	NET_CS_STATE_RESP =				0x3B,
+	NET_UMA_INFO_IND =				0x3C,
+	NET_RADIO_INFO_IND =				0x3F,
+	NET_CELL_INFO_GET_REQ =				0x40,
+	NET_CELL_INFO_GET_RESP =			0x41,
+	NET_CELL_INFO_IND =				0x42,
+	NET_NITZ_NAME_IND =				0x43,
+	NET_SOR_REQ =					0x44,
+	NET_SOR_RESP =					0x45,
+	NET_RSSI_CONF_REQ =				0x46,
+	NET_RSSI_CONF_RESP =				0x47
+};
+
+enum net_subblock {
+	NET_MODEM_REG_INFO_COMMON =			0x00,
+	NET_MODEM_AVAIL_NETWORK_INFO_COMMON =		0x01,
+	NET_OPERATOR_INFO_COMMON =			0x02,
+	NET_RSSI_CURRENT =				0x04,
+	NET_TEST_CARRIER_PARAM =			0x05,
+	NET_TEST_WCDMA_PARAMS =				0x2D,
+	NET_CIPHERING_INFO =				0x29,
+	NET_MODEM_GSM_REG_INFO =			0x09,
+	NET_MODEM_CURRENT_CELL_INFO =			0x39,
+	NET_TIME_INFO =					0x10,
+	NET_MODEM_DETAILED_NETWORK_INFO =		0x0B,
+	NET_MODEM_GSM_OPERATOR_INFO =			0x0C,
+	NET_GSM_HOME_CELLS_INFO =			0x0D,
+	NET_GSM_SIM_NMR_INFO =				0x0E,
+	NET_MODEM_CAUSE_EXTENSION =			0x0F,
+	NET_MODEM_GSM_BAND_INFO =			0x11,
+	NET_UTRAN_SIM_NMR_INFO =			0x3D,
+	NET_ECID_GERAN_INFO =				0x3E,
+	NET_ECID_UTRAN_FDD_INFO =			0x3F,
+	NET_RAT_INFO =					0x2C,
+	NET_MODEM_UMA_SERVICE_ZONE_INFO =		0x37,
+	NET_UMA_FAILURE_INFO =				0x38,
+	NET_UTRAN_RADIO_INFO =				0x3C,
+	NET_UARFCN_INFO =				0x28,
+	NET_GSM_CELL_INFO =				0x46,
+	NET_WCDMA_CELL_INFO =				0x47,
+	NET_EPS_CELL_INFO =				0x50,
+	NET_FULL_NITZ_NAME =				0x48,
+	NET_SHORT_NITZ_NAME =				0x49,
+	NET_RSSI_CONF_INFO =				0x54
+};
+enum net_modem_gprs_network_mode {
+	NET_GPRS_MODE_NONE =				0x00
+};
+
+enum net_service_status {
+	NET_SERVICE =					0x00
+};
+enum net_reg_status {
+	NET_REG_STATUS_HOME =				0x00,
+	NET_REG_STATUS_ROAM =				0x01,
+	NET_REG_STATUS_ROAM_BLINK =			0x02,
+	NET_REG_STATUS_NOSERV =				0x03,
+	NET_REG_STATUS_NOSERV_SEARCHING =		0x04,
+	NET_REG_STATUS_NOSERV_NOTSEARCHING =		0x05,
+	NET_REG_STATUS_NOSERV_NOSIM =			0x06,
+	NET_REG_STATUS_POWER_OFF =			0x08,
+	NET_REG_STATUS_NSPS =				0x09,
+	NET_REG_STATUS_NSPS_NO_COVERAGE =		0x0A,
+	NET_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW =	0x0B
+};
+
+enum net_network_status {
+	NET_OPER_STATUS_UNKNOWN =			0x00,
+	NET_OPER_STATUS_AVAILABLE =			0x01,
+	NET_OPER_STATUS_CURRENT =			0x02,
+	NET_OPER_STATUS_FORBIDDEN =			0x03
+};
+
+enum net_network_pref {
+	NET_GSM_HOME_PLMN =				0x00,
+	NET_GSM_PREFERRED_PLMN =			0x01,
+	NET_GSM_FORBIDDEN_PLMN =			0x02,
+	NET_GSM_OTHER_PLMN =				0x03,
+	NET_GSM_NO_PLMN_AVAIL =				0x04
+};
+
+enum net_umts_available {
+	NET_UMTS_NOT_AVAILABLE =			0x00,
+	NET_UMTS_AVAILABLE =				0x01
+};
+
+enum net_band_info {
+	NET_GSM_BAND_900_1800 =				0x00,
+	NET_GSM_BAND_850_1900 =				0x01,
+	NET_GSM_BAND_INFO_NOT_AVAIL =			0x02,
+	NET_GSM_BAND_ALL_SUPPORTED_BANDS =		0x03
+};
+
+enum net_gsm_cause {
+	NET_GSM_IMSI_UNKNOWN_IN_HLR =			0x02,
+	NET_GSM_ILLEGAL_MS =				0x03,
+	NET_GSM_IMSI_UNKNOWN_IN_VLR =			0x04,
+	NET_GSM_IMEI_NOT_ACCEPTED =			0x05,
+	NET_GSM_ILLEGAL_ME =				0x06,
+	NET_GSM_GPRS_SERVICES_NOT_ALLOWED =		0x07,
+	NET_GSM_GPRS_AND_NON_GPRS_NA =			0x08,
+	NET_GSM_MS_ID_CANNOT_BE_DERIVED =		0x09,
+	NET_GSM_IMPLICITLY_DETACHED =			0x0A,
+	NET_GSM_PLMN_NOT_ALLOWED =			0x0B,
+	NET_GSM_LA_NOT_ALLOWED =			0x0C,
+	NET_GSM_ROAMING_NOT_IN_THIS_LA =		0x0D,
+	NET_GSM_GPRS_SERV_NA_IN_THIS_PLMN =		0x0E,
+	NET_GSM_NO_SUITABLE_CELLS_IN_LA =		0x0F,
+	NET_GSM_MSC_TEMP_NOT_REACHABLE =		0x10,
+	NET_GSM_NETWORK_FAILURE =			0x11,
+	NET_GSM_MAC_FAILURE =				0x14,
+	NET_GSM_SYNCH_FAILURE =				0x15,
+	NET_GSM_CONGESTION =				0x16,
+	NET_GSM_AUTH_UNACCEPTABLE =			0x17,
+	NET_GSM_SERV_OPT_NOT_SUPPORTED =		0x20,
+	NET_GSM_SERV_OPT_NOT_SUBSCRIBED =		0x21,
+	NET_GSM_SERV_TEMP_OUT_OF_ORDER =		0x22,
+	NET_GSM_RETRY_ENTRY_NEW_CELL_LOW =		0x30,
+	NET_GSM_RETRY_ENTRY_NEW_CELL_HIGH =		0x3F,
+	NET_GSM_SEMANTICALLY_INCORRECT =		0x5F,
+	NET_GSM_INVALID_MANDATORY_INFO =		0x60,
+	NET_GSM_MSG_TYPE_NONEXISTENT =			0x61,
+	NET_GSM_CONDITIONAL_IE_ERROR =			0x64,
+	NET_GSM_MSG_TYPE_WRONG_STATE =			0x65,
+	NET_GSM_PROTOCOL_ERROR_UNSPECIFIED =		0x6F
+};
+
+enum net_cs_type {
+	NET_CS_GSM =					0x00
+};
+
+enum net_rat_name {
+	NET_GSM_RAT =					0x01,
+	NET_UMTS_RAT =					0x02
+};
+
+enum net_rat_type {
+	NET_CURRENT_RAT =				0x00,
+	NET_SUPPORTED_RATS =				0x01
+};
+
+enum net_measurement_type {
+	NET_CURRENT_CELL_RSSI =				0x02
+};
+
+enum net_search_mode {
+	NET_MANUAL_SEARCH =				0x00
+};
+
+enum net_select_mode {
+	NET_SELECT_MODE_UNKNOWN =			0x00,
+	NET_SELECT_MODE_MANUAL =			0x01,
+	NET_SELECT_MODE_AUTOMATIC =			0x02,
+	NET_SELECT_MODE_USER_RESELECTION =		0x03,
+	NET_SELECT_MODE_NO_SELECTION =			0x04
+};
+
+enum net_isi_cause {
+	NET_CAUSE_OK =					0x00,
+	NET_CAUSE_COMMUNICATION_ERROR =			0x01,
+	NET_CAUSE_INVALID_PARAMETER =			0x02,
+	NET_CAUSE_NO_SIM =				0x03,
+	NET_CAUSE_SIM_NOT_YET_READY =			0x04,
+	NET_CAUSE_NET_NOT_FOUND =			0x05,
+	NET_CAUSE_REQUEST_NOT_ALLOWED =			0x06,
+	NET_CAUSE_CALL_ACTIVE =				0x07,
+	NET_CAUSE_SERVER_BUSY =				0x08,
+	NET_CAUSE_SECURITY_CODE_REQUIRED =		0x09,
+	NET_CAUSE_NOTHING_TO_CANCEL =			0x0A,
+	NET_CAUSE_UNABLE_TO_CANCEL =			0x0B,
+	NET_CAUSE_NETWORK_FORBIDDEN =			0x0C,
+	NET_CAUSE_REQUEST_REJECTED =			0x0D,
+	NET_CAUSE_CS_NOT_SUPPORTED =			0x0E,
+	NET_CAUSE_PAR_INFO_NOT_AVAILABLE =		0x0F,
+	NET_CAUSE_NOT_DONE =				0x10,
+	NET_CAUSE_NO_SELECTED_NETWORK =			0x11,
+	NET_CAUSE_REQUEST_INTERRUPTED =			0x12,
+	NET_CAUSE_TOO_BIG_INDEX =			0x14,
+	NET_CAUSE_MEMORY_FULL =				0x15,
+	NET_CAUSE_SERVICE_NOT_ALLOWED =			0x16,
+	NET_CAUSE_NOT_SUPPORTED_IN_TECH =		0x17
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* !__ISIMODEM25_NETWORK_H */
diff --git a/drivers/isimodem2.5/phonebook.c b/drivers/isimodem2.5/phonebook.c
new file mode 100644
index 0000000..397b4e5
--- /dev/null
+++ b/drivers/isimodem2.5/phonebook.c
@@ -0,0 +1,1320 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/phonebook.h>
+#include "util.h"
+
+#include <glib.h>
+
+#include "debug.h"
+#include "sim.h"
+#include "simutil.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "timeout.h"
+#include "uicc.h"
+#include "uicc_interface.h"
+
+/* File info parameters */
+#define FCP_TEMPLATE			0x62
+#define FCP_FILE_SIZE			0x80
+#define FCP_FILE_DESC			0x82
+#define FCP_FILE_ID			0x83
+#define FCP_FILE_LIFECYCLE		0x8A
+#define FCP_FILE_SECURITY_ARR		0x8B
+#define FCP_FILE_SECURITY_COMPACT	0x8C
+#define FCP_FILE_SECURITY_EXPANDED	0xAB
+
+#define UNUSED				0xff
+
+#define EXT1_CP_SUBADDRESS		1
+#define EXT1_ADDITIONAL_DATA		2
+
+#define NAME_SIZE			64
+#define NUMBER_SIZE			256
+#define EMAIL_SIZE			128
+#define EXT_NUMBER_SIZE			24
+#define SNE_SIZE			64
+
+/* 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_IAD = 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 {
+	int file_id;
+	uint8_t file_type;
+	uint8_t structure;
+	int file_length;
+	int record_length;
+	int record;
+	gboolean handled;
+};
+
+struct file_info {
+	int fileid;
+	int length;
+	int structure;
+	int record_length;
+	unsigned char access[3];
+};
+
+struct phonebook_entry {
+	int entry;
+	char *name;
+	char *number;
+	char *email;
+	char *anr;
+	char *sne;
+};
+
+struct pb_data {
+	GIsiClient *client;
+	struct ofono_sim_driver *sim_func;
+	gint pb_entry;
+	struct pb_file_info pb_reference_file_info;
+	struct pb_file_info *extension_file_info;
+	uint8_t ext1_to_type;
+	uint8_t ext1_to_entry;
+};
+
+static GSList *pb_files;
+static GSList *pb_next;
+
+static GSList *phonebook_entry_start;
+static GSList *phonebook_entry_current;
+
+static void pb_reference_info_cb(const struct ofono_error *error,
+					int filelength,
+					enum ofono_sim_file_structure structure,
+					int recordlength,
+					const unsigned char access[3],
+					unsigned char file_status, void *data);
+
+static void pb_content_data_read(struct pb_data *pbd,
+					struct pb_file_info *file_info,
+					struct isi_cb_data *cbd);
+
+static struct pb_file_info *decode_read_response(struct pb_file_info *file_info,
+						 const unsigned char *msg,
+						 size_t len,
+						 struct ofono_phonebook *pb)
+{
+
+	char *name = NULL;
+	char *number = NULL;
+	char *ext_number = NULL;
+	char *email = NULL;
+	char *sne = NULL;
+	char *anr = NULL;
+
+	static const char digit_to_utf8[] = "0123456789*#pwe\0";
+
+	struct pb_file_info *next_file = NULL;
+	int type = file_info->file_type;
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+
+	switch (type) {
+	case TYPE_ADN:{
+			const uint8_t name_length = len - 14;
+			const uint8_t number_start = name_length;
+			uint8_t number_length = 0;
+			uint8_t extension_record = UNUSED;
+			uint8_t i, prefix;
+			name = sim_string_to_utf8(msg, name_length);
+			/* Length contains also TON&NPI */
+			number_length = msg[number_start];
+
+			if ((number_length != UNUSED) && (number_length != 0)) {
+				number = g_try_malloc0(NUMBER_SIZE);
+				number_length--;
+
+				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) &
+									0x0f];
+					}
+
+					extension_record = msg[len - 1];
+				}
+			}
+
+			DBG("ADN name %s, number %s number \
+				length %d extension_record %d",
+				name, number, number_length, extension_record);
+
+			if (extension_record != UNUSED) {
+				next_file = g_try_new0(struct pb_file_info, 1);
+
+				if (next_file) {
+					if (pbd->extension_file_info) {
+						memmove(next_file,
+							pbd->
+							extension_file_info,
+							sizeof(struct
+								pb_file_info));
+					} else {
+						next_file->file_type =
+							TYPE_EXT1;
+						next_file->file_id =
+							SIM_EFEXT1_SIM_FILEID;
+					}
+
+					next_file->record = extension_record;
+					pbd->ext1_to_type = TYPE_ADN;
+					pbd->ext1_to_entry = pbd->pb_entry;
+				}
+			}
+
+			if (name || number) {
+				struct phonebook_entry *new_entry =
+					g_try_new0(struct phonebook_entry, 1);
+
+				if (new_entry) {
+					new_entry->name = name;
+					new_entry->number = number;
+
+					DBG("Creating PB entry %d with \
+						name %s and number %s",
+						pbd->pb_entry,
+						new_entry->name,
+						new_entry->number);
+
+					phonebook_entry_current =
+						g_slist_insert
+						(phonebook_entry_start,
+							new_entry,
+							pbd->pb_entry);
+
+					if (!phonebook_entry_start)
+						phonebook_entry_start =
+						phonebook_entry_current;
+
+					pbd->pb_entry++;
+				}
+			}
+
+			break;
+		}
+	case TYPE_SNE:{
+			uint8_t sne_end = 0;
+			const uint8_t sne_length = len - 2;
+			uint8_t i = 0;
+			uint8_t phonebook_entry_nbr = msg[len - 1];
+
+			DBG("SNE");
+			for (i = 0; (msg[i] != UNUSED) && (i < sne_length); i++)
+				;
+
+			sne_end = i;
+			sne = sim_string_to_utf8(msg, sne_length);
+
+			if (sne) {
+				/* GSlist nth counts from 0,
+					PB entries from 1 */
+				GSList *list_entry =
+					g_slist_nth(phonebook_entry_start,
+							phonebook_entry_nbr - 1);
+
+				DBG("SNE \'%s\' to PB entry %d", sne,
+					phonebook_entry_nbr);
+
+				if (list_entry) {
+					struct phonebook_entry *entry =
+						list_entry->data;
+
+					if (entry) {
+						/* If one already exists,
+								delete it */
+						if (entry->sne)
+							g_free(entry->sne);
+
+						DBG("Adding SNE to entry %d,\
+							name %s",
+							phonebook_entry_nbr,
+							entry->name);
+
+						entry->sne = sne;
+					} else {
+						g_free(sne);
+					}
+				}
+			}
+
+			break;
+		}
+	case TYPE_ANR:{
+			uint8_t number_length = 0;
+			uint8_t extension_record = UNUSED;
+			uint8_t aas_record = UNUSED;
+			uint8_t i, prefix;
+			uint8_t phonebook_entry_nbr = msg[len - 1];
+			GSList *list_entry;
+
+			DBG("ANR");
+			if (msg[0] == UNUSED)
+				break;
+
+			aas_record = msg[0];
+			/* Length contains also TON&NPI */
+			number_length = msg[1];
+
+			if (number_length) {
+				number_length--;
+				anr = g_try_malloc0(NUMBER_SIZE);
+
+				if (anr) {
+					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) & 0x0f];
+					}
+
+					extension_record = msg[len - 3];
+				}
+			}
+
+			DBG("ANR to entry %d number %s number length %d\
+						extension_record %d aas %d",
+				phonebook_entry_nbr, anr, number_length,
+						extension_record, aas_record);
+
+			if (extension_record != UNUSED) {
+				next_file = g_try_new0(struct pb_file_info, 1);
+
+				if (next_file) {
+					if (pbd->extension_file_info) {
+						memmove(next_file,
+							pbd->
+							extension_file_info,
+							sizeof(struct
+								pb_file_info));
+					} else {
+						next_file->file_type =
+							TYPE_EXT1;
+						next_file->file_id =
+							SIM_EFEXT1_SIM_FILEID;
+					}
+
+					next_file->record = extension_record;
+					pbd->ext1_to_type = TYPE_ANR;
+					pbd->ext1_to_entry =
+						phonebook_entry_nbr;
+				}
+			}
+
+			/* GSlist nth counts from 0, PB entries from 1 */
+			list_entry =
+				g_slist_nth(phonebook_entry_start,
+					phonebook_entry_nbr - 1);
+
+			if (list_entry) {
+				struct phonebook_entry *entry =
+					list_entry->data;
+
+				if (entry) {
+					/* if one already exists, delete it */
+					if (entry->anr)
+						g_free(entry->anr);
+
+					DBG("Adding ANR to entry %d, name %s",
+							phonebook_entry_nbr,
+								entry->name);
+					entry->anr = anr;
+				}
+			} else {
+				g_free(anr);
+			}
+
+			break;
+		}
+	case TYPE_AAS:{
+			DBG("AAS");
+			break;
+		}
+	case TYPE_EMAIL:{
+			uint8_t phonebook_entry_nbr = msg[len - 1];
+			email = sim_string_to_utf8(msg, len - 2);
+
+			/* GSlist nth counts from 0, PB entries from 1 */
+			if (email) {
+				GSList *list_entry =
+					g_slist_nth(phonebook_entry_start,
+						phonebook_entry_nbr - 1);
+
+				DBG("Email \'%s\' to PB entry %d", email,
+					phonebook_entry_nbr);
+				if (list_entry) {
+					struct phonebook_entry *entry =
+						list_entry->data;
+
+					/* if one already exists, delete it */
+					if (entry) {
+						if (entry->email)
+							g_free(entry->email);
+
+						DBG("Adding email to entry %d,\
+								 name %s",
+							phonebook_entry_nbr,
+								entry->name);
+
+						entry->email = email;
+					}
+				} else {
+					g_free(email);
+				}
+			}
+
+			break;
+		}
+	case TYPE_EXT1:{
+			uint8_t number_length, i, next_extension_record;
+
+			DBG("EXT1 to type=%02X, entry=%d", pbd->ext1_to_type,
+				pbd->ext1_to_entry);
+			if (msg[0] == EXT1_ADDITIONAL_DATA) {
+				ext_number = g_try_malloc0(EXT_NUMBER_SIZE);
+
+				if (ext_number) {
+					number_length = msg[1];
+
+					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) & 0x0f];
+					}
+
+					next_extension_record =
+						msg[number_length + 2];
+
+					DBG("Number extension %s\
+						number length %d\
+						extension_record %d",
+						ext_number,
+						number_length,
+						next_extension_record);
+
+					/* pb_entry is already incremented
+						& g_slist_nth counts from 0 */
+					if (pbd->ext1_to_type == TYPE_ADN) {
+						GSList *list_entry =
+							g_slist_nth
+							(phonebook_entry_start,
+							pbd->ext1_to_entry - 1);
+						DBG("Looking for ADN entry %d",
+							pbd->ext1_to_entry);
+
+						if (list_entry) {
+							struct phonebook_entry
+								*entry =
+								list_entry->data;
+
+							if (entry) {
+								strcat(entry->
+									number,
+									ext_number);
+							}
+						}
+					} else if (pbd->ext1_to_type ==
+							TYPE_ANR) {
+						GSList *list_entry =
+							g_slist_nth
+							(phonebook_entry_start,
+							pbd->ext1_to_entry - 1);
+						DBG("Looking for ANR entry %d",
+							pbd->ext1_to_entry);
+
+						if (list_entry) {
+							struct phonebook_entry
+								*entry =
+								list_entry->data;
+
+							if (entry) {
+								strcat(entry->anr,
+								       ext_number);
+							}
+						}
+					}
+
+					g_free(ext_number);
+
+					/* Check if there is
+					more extension data */
+					if (next_extension_record != UNUSED) {
+						next_file =
+							g_try_new0(struct
+								pb_file_info, 1);
+
+						if (next_file) {
+							if (pbd->extension_file_info) {
+								memmove
+								(next_file,
+								pbd->
+								extension_file_info,
+								sizeof
+								(struct
+								pb_file_info));
+							} else {
+								next_file->
+									file_type =
+									TYPE_EXT1;
+								next_file->
+									file_id =
+									SIM_EFEXT1_SIM_FILEID;
+							}
+
+							next_file->record =
+								next_extension_record;
+						}
+					}
+				}
+			}
+
+			break;
+		}
+	default:{
+			DBG("Skipping type %02X", type);
+			break;
+		}
+	}
+
+	return next_file;
+}
+
+struct pb_file_info *extension_file_info;
+
+static void pb_adn_sim_data_cb(const struct ofono_error *error,
+				const unsigned char *sdata,
+				int length, void *data)
+{
+	struct isi_cb_data *cbd_outer = data;
+	struct isi_cb_data *cbd = NULL;
+	struct pb_file_info *file_info;
+	struct ofono_phonebook *pb;
+	ofono_phonebook_cb_t cb;
+	struct pb_data *pbd;
+
+	DBG("");
+	if (!cbd_outer)
+		goto out;
+
+	file_info = cbd_outer->user;
+	cbd = cbd_outer->data;
+
+	if (!cbd)
+		goto out;
+
+	pb = cbd->user;
+	cb = cbd->cb;
+	pbd = ofono_phonebook_get_data(pb);
+
+	if (extension_file_info)
+		file_info =
+			decode_read_response(extension_file_info, sdata, length,
+						pb);
+	else
+		file_info = decode_read_response(file_info, sdata, length, pb);
+
+	if (file_info) {
+		DBG("Reading extension file %04X, record %d",
+			file_info->file_id, file_info->record);
+		pbd->sim_func->read_file_linear(get_sim(), file_info->file_id,
+						file_info->record,
+						file_info->record_length,
+						pb_adn_sim_data_cb, cbd_outer);
+
+		/* Delete if there is a previous one */
+		g_free(extension_file_info);
+		extension_file_info = file_info;
+		return;
+	} else {
+		g_free(extension_file_info);
+		extension_file_info = NULL;
+		file_info = cbd_outer->user;
+
+		if (file_info->record <
+			(file_info->file_length / file_info->record_length)) {
+
+			file_info->record++;
+			DBG("Same file, next record %d", file_info->record);
+			pbd->sim_func->read_file_linear(get_sim(),
+							file_info->file_id,
+							file_info->record,
+							file_info->
+							record_length,
+							pb_adn_sim_data_cb,
+							cbd_outer);
+		} else {
+			GSList *list_entry =
+				g_slist_nth(phonebook_entry_start, 0);
+			DBG("All data requested, start vCard creation");
+			g_free(file_info);
+
+			while (list_entry) {
+				struct phonebook_entry *entry =
+					list_entry->data;
+
+				if (entry) {
+					DBG("vCard:\nname=%s\nnumber=%s\n\
+						email=%s\nanr=%s\nsne=%s",
+						entry->name, entry->number,
+						entry->email, entry->anr,
+								entry->sne);
+
+					ofono_phonebook_entry(pb, -1,
+								entry->number, -1,
+								entry->name, -1,
+								NULL,
+								entry->anr, -1,
+								entry->sne,
+								entry->email,
+								NULL, NULL);
+					g_free(entry->number);
+					g_free(entry->name);
+					g_free(entry->anr);
+					g_free(entry->sne);
+					g_free(entry->email);
+					g_free(entry);
+				}
+
+				list_entry = g_slist_next(list_entry);
+			}
+
+			g_slist_free(phonebook_entry_start);
+			g_slist_free(pb_files);
+			g_free(cbd_outer);
+			DBG("Finally all PB data read");
+			CALLBACK_WITH_SUCCESS(cb, cbd->data);
+			goto out;
+		}
+	}
+
+	return;
+out:
+	g_free(cbd);
+	DBG("Exiting");
+}
+
+static void pb_adn_sim_info_cb(const struct ofono_error *error,
+				int filelength,
+				enum ofono_sim_file_structure structure,
+				int recordlength,
+				const unsigned char access[3],
+				unsigned char file_status, void *data)
+{
+	struct isi_cb_data *cbd = data;
+	struct ofono_phonebook *pb = cbd->user;
+	ofono_phonebook_cb_t cb = cbd->cb;
+	struct pb_data *pbd = ofono_phonebook_get_data(pb);
+	struct pb_file_info *file_info = NULL;
+	struct isi_cb_data *cbd_outer;
+	int records = 0;
+
+	DBG("");
+	if (!cbd)
+		goto error;
+
+	pb = cbd->user;
+	cb = cbd->cb;
+	pbd = ofono_phonebook_get_data(pb);
+	file_info = NULL;
+
+	if (!pbd)
+		goto error;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+		goto error;
+
+	if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED)
+		goto error;
+
+	if (!pbd->sim_func->read_file_linear)
+		goto error;
+
+	records = filelength / recordlength;
+
+	if (!records)
+		goto error;
+
+	file_info = g_try_new0(struct pb_file_info, 1);
+
+	if (!file_info)
+		goto error;
+
+	file_info->file_id = SIM_EFADN_SIM_FILEID;
+	file_info->file_type = TYPE_ADN;
+	file_info->structure = structure;
+	file_info->file_length = filelength;
+	file_info->record_length = recordlength;
+	file_info->record = 1;
+	/* Regenerate cbd (include file_info) */
+	cbd_outer = isi_cb_data_new(file_info, cb, cbd);
+	pbd->sim_func->read_file_linear(get_sim(),
+					file_info->file_id,
+					file_info->record,
+					file_info->record_length,
+					pb_adn_sim_data_cb, cbd_outer);
+	return;
+error:
+
+	if (cb && cbd)
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+	g_free(cbd);
+}
+
+static gboolean is_reading_required(uint8_t file_type)
+{
+	switch (file_type) {
+	case TYPE_ADN:
+	case TYPE_EMAIL:
+	case TYPE_SNE:
+	case TYPE_ANR:
+		return TRUE;
+	default:
+		return FALSE;
+	}
+}
+
+static void pb_content_data_cb(const struct ofono_error *error,
+				const unsigned char *sdata,
+				int length, void *data)
+{
+	struct isi_cb_data *cbd = data;
+	struct ofono_phonebook *pb;
+	ofono_phonebook_cb_t cb;
+	struct pb_data *pbd;
+	struct pb_file_info *file_info = NULL;
+
+	if (!cbd)
+		goto out;
+
+	pb = cbd->user;
+	cb = cbd->cb;
+	pbd = ofono_phonebook_get_data(pb);
+
+	if (extension_file_info)
+		file_info = decode_read_response(extension_file_info, sdata,
+						 length, pb);
+	else
+		file_info =
+			decode_read_response(pb_next->data, sdata, length, pb);
+
+	if (file_info) {
+		DBG("Reading extension file %04X, record %d, structure %d",
+			file_info->file_id, file_info->record,
+			file_info->structure);
+		pb_content_data_read(pbd, file_info, cbd);
+		/* Delete if there is a previous one */
+		g_free(extension_file_info);
+		extension_file_info = file_info;
+		return;
+	} else {
+		g_free(extension_file_info);
+		extension_file_info = NULL;
+		file_info = pb_next->data;
+
+		if (((file_info->structure ==
+		      OFONO_SIM_FILE_STRUCTURE_FIXED) ||
+			(file_info->structure ==
+			 OFONO_SIM_FILE_STRUCTURE_CYCLIC))
+			&& (file_info->record <
+			(file_info->file_length / file_info->record_length))) {
+
+			file_info->record++;
+			DBG("Same file, next record %d", file_info->record);
+		} else {
+			g_free(file_info);
+			pb_next = g_slist_next(pb_next);
+			DBG("Next file in list");
+
+			if (pb_next) {
+				file_info = pb_next->data;
+
+				while (pb_next
+						&&
+						(!is_reading_required
+						(file_info->file_type))) {
+					DBG("Skipping file type %02X",
+						file_info->file_type);
+					g_free(file_info);
+					pb_next = g_slist_next(pb_next);
+
+					if (pb_next)
+						file_info = pb_next->data;
+				}
+			}
+
+			if (pb_next == NULL) {
+				GSList *list_entry =
+					g_slist_nth(phonebook_entry_start, 0);
+
+				DBG("All data requested, start vCard creation");
+				while (list_entry) {
+					struct phonebook_entry *entry =
+					    list_entry->data;
+
+					if (entry) {
+						DBG("vCard:\nname=%s\n \
+							number=%s\nemail=%s\n \
+							anr=%s\nsne=%s",
+							entry->name,
+							entry->number,
+							entry->email,
+							entry->anr,
+							entry->sne);
+
+						ofono_phonebook_entry(pb, -1,
+								entry->number,
+								-1,
+								entry->name,
+								-1,
+								NULL,
+								entry->anr,
+								-1,
+								entry->sne,
+								entry->email,
+								NULL,
+								NULL);
+
+						g_free(entry->number);
+						g_free(entry->name);
+						g_free(entry->anr);
+						g_free(entry->sne);
+						g_free(entry->email);
+						g_free(entry);
+					}
+
+					list_entry = g_slist_next(list_entry);
+				}
+
+				g_slist_free(phonebook_entry_start);
+				g_slist_free(pb_files);
+				DBG("Finally all PB data read");
+				CALLBACK_WITH_SUCCESS(cb, cbd->data);
+				goto out;
+			}
+
+			file_info = pb_next->data;
+		}
+	}
+
+	pb_content_data_read(pbd, file_info, cbd);
+	return;
+out:
+	g_free(cbd);
+}
+
+static void pb_content_data_read(struct pb_data *pbd,
+					struct pb_file_info *file_info,
+					struct isi_cb_data *cbd)
+{
+	ofono_phonebook_cb_t cb;
+
+	if (!pbd || !file_info || !cbd)
+		goto out;
+
+	cb = cbd->cb;
+	DBG("Reading content of file type=%02X, file ID=%04X, structure=%d",
+		file_info->file_type, file_info->file_id, file_info->structure);
+
+	switch (file_info->structure) {
+	case OFONO_SIM_FILE_STRUCTURE_FIXED:
+
+		if (!pbd->sim_func->read_file_linear)
+			goto error;
+
+		pbd->sim_func->read_file_linear(get_sim(), file_info->file_id,
+						file_info->record,
+						file_info->record_length,
+						pb_content_data_cb, cbd);
+		break;
+	case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
+
+		if (!pbd->sim_func->read_file_cyclic)
+			goto error;
+
+		pbd->sim_func->read_file_cyclic(get_sim(), file_info->file_id,
+						file_info->record,
+						file_info->record_length,
+						pb_content_data_cb, cbd);
+		break;
+	case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
+
+		if (!pbd->sim_func->read_file_transparent)
+			goto error;
+
+		pbd->sim_func->read_file_transparent(get_sim(),
+							file_info->file_id, 0,
+							file_info->file_length,
+							pb_content_data_cb,
+							cbd);
+		break;
+	}
+
+	return;
+error:
+
+	if (cb && cbd)
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+out:
+	DBG("Exiting");
+}
+
+static void pb_content_info_cb(const struct ofono_error *error,
+				int filelength,
+				enum ofono_sim_file_structure structure,
+				int recordlength,
+				const unsigned char access[3],
+				unsigned char file_status, void *data)
+{
+	struct isi_cb_data *cbd = data;
+	struct ofono_phonebook *pb;
+	ofono_phonebook_cb_t cb;
+	struct pb_data *pbd;
+	struct pb_file_info *file_info = NULL;
+
+	if (!cbd)
+		goto error;
+
+	pb = cbd->user;
+	cb = cbd->cb;
+	pbd = ofono_phonebook_get_data(pb);
+
+	if (!pbd)
+		goto error;
+
+	file_info = pb_next->data;
+
+	if (!file_info)
+		goto error;
+
+	file_info->structure = structure;
+	file_info->file_length = filelength;
+	file_info->record_length = recordlength;
+	file_info->record = 1;
+
+	DBG("File type=%02X, File ID=%04X, Struct=%d, File len=%d, Rec len=%d",
+		file_info->file_type, file_info->file_id, file_info->structure,
+		file_info->file_length, file_info->record_length);
+
+	if (file_info->file_type == TYPE_EXT1)
+		/* Save for quick access */
+		pbd->extension_file_info = file_info;
+
+	pb_next = g_slist_next(pb_next);
+
+	if (pb_next == NULL) {
+		DBG("All info requested, start content reading");
+
+		/* Re-start from beginning */
+		pb_next = g_slist_nth(pb_files, 0);
+		file_info = pb_next->data;
+
+		DBG("Calling pb_content_data_read pb=%p, list=%p, type=%02X",
+			cbd->user, pb_next, file_info->file_type);
+
+		pb_content_data_read(pbd, file_info, cbd);
+		return;
+	}
+
+	file_info = pb_next->data;
+
+	DBG("Reading next content info %04X", file_info->file_id);
+	pbd->sim_func->read_file_info(get_sim(), file_info->file_id,
+					pb_content_info_cb, cbd);
+	return;
+error:
+
+	if (cb && cbd) {
+		DBG("Error cbd=%p, pbd=%p, file_info=%p", cbd, pbd, file_info);
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+	}
+
+	g_free(cbd);
+}
+
+static void pb_reference_data_cb(const struct ofono_error *error,
+					const unsigned char *sdata,
+					int length, void *data)
+{
+	struct isi_cb_data *cbd = data;
+	struct ofono_phonebook *pb;
+	ofono_phonebook_cb_t cb;
+	struct pb_data *pbd;
+	const unsigned char *ptr = sdata;
+	int typelen = 0;
+	int i = 0;
+	int file_id = 0;
+	gboolean finished = FALSE;
+
+	if (!cbd)
+		goto error;
+
+	pb = cbd->user;
+	cb = cbd->cb;
+
+	if (!cb || !pb)
+		goto out;
+
+	pbd = ofono_phonebook_get_data(pb);
+
+	if (!pbd)
+		goto error;
+
+	while ((ptr < sdata + length) && (finished == FALSE)) {
+		switch (*ptr) {
+		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);
+				file_id = (ptr[i + 2] << 8) + ptr[i + 3];
+
+				DBG("creating file info for File type=%02X,\
+								File ID=%04X",
+								ptr[i],
+								file_id);
+
+				if (!file_info)
+					goto error;
+
+				file_info->file_type = ptr[i];
+				file_info->file_id = file_id;
+				pb_files =
+					g_slist_append(pb_files,
+							(void *)file_info);
+				i += ptr[i + 1] + 2;
+			}
+
+			ptr += typelen;
+			break;
+		default:
+			DBG("All handled %02x", *ptr);
+			finished = TRUE;
+			break;
+		}
+	}
+
+	if (pbd->pb_reference_file_info.record <
+			(pbd->pb_reference_file_info.file_length /
+			pbd->pb_reference_file_info.record_length)) {
+		pbd->pb_reference_file_info.record++;
+		DBG("Next EFpbr record %d", pbd->pb_reference_file_info.record);
+		pbd->sim_func->read_file_linear(get_sim(),
+						pbd->pb_reference_file_info.
+						file_id,
+						pbd->pb_reference_file_info.
+						record,
+						pbd->pb_reference_file_info.
+						record_length,
+						pb_reference_data_cb, cbd);
+	} else {
+		struct pb_file_info *file_info;
+		DBG("All EFpbr records read");
+		pb_next = g_slist_nth(pb_files, 0);
+
+		if (!pb_next)
+			goto error;
+
+		file_info = pb_next->data;
+
+		if (!file_info || !pbd->sim_func)
+			goto error;
+
+		pbd->sim_func->read_file_info(get_sim(), file_info->file_id,
+						pb_content_info_cb, cbd);
+	}
+
+	return;
+error:
+
+	if (cb && cbd)
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+out:
+	g_free(cbd);
+}
+
+static void pb_reference_info_cb(const struct ofono_error *error,
+					int filelength,
+					enum ofono_sim_file_structure structure,
+					int recordlength,
+					const unsigned char access[3],
+					unsigned char file_status,
+					void *data)
+{
+
+	struct isi_cb_data *cbd = data;
+	struct ofono_phonebook *pb;
+	ofono_phonebook_cb_t cb;
+	struct pb_data *pbd;
+	int records = 0;
+
+	DBG("");
+	if (!cbd)
+		goto error;
+
+	pb = cbd->user;
+	cb = cbd->cb;
+	pbd = ofono_phonebook_get_data(pb);
+
+	if (!pbd)
+		goto error;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+		goto error;
+
+	if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED)
+		goto error;
+
+	if (!pbd->sim_func->read_file_linear)
+		goto error;
+
+	records = filelength / recordlength;
+
+	if (!records)
+		goto error;
+
+	DBG("EFpbr size %d, record length %d, records %d",
+		filelength, recordlength, records);
+	pbd->pb_reference_file_info.file_id = SIM_EFPBR_FILEID;
+	pbd->pb_reference_file_info.file_length = filelength;
+	pbd->pb_reference_file_info.record_length = recordlength;
+	pbd->pb_reference_file_info.record = 1;	/* Current record, not amount */
+	pbd->pb_reference_file_info.structure = OFONO_SIM_FILE_STRUCTURE_FIXED;
+	pbd->sim_func->read_file_linear(get_sim(), SIM_EFPBR_FILEID,
+					1, recordlength,
+					pb_reference_data_cb, cbd);
+	return;
+error:
+
+	if (cb && cbd)
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+	g_free(cbd);
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(pb, cb, data);
+
+	DBG("Storage %s", storage);
+	if (strcmp(storage, "SM"))	/* Only for SIM memory */
+		goto error;
+
+	if (!pbd->sim_func->read_file_info)
+		goto error;
+
+	if (!cbd)
+		goto error;
+
+	pbd->pb_entry = 1;
+	pb_files = NULL;
+	pb_next = NULL;
+	phonebook_entry_current = NULL;
+	phonebook_entry_start = NULL;
+
+	switch (get_app_type()) {
+	case UICC_APPL_TYPE_ICC_SIM:
+		DBG("SIM application");
+		pbd->sim_func->read_file_info(get_sim(), SIM_EFADN_SIM_FILEID,
+						pb_adn_sim_info_cb, cbd);
+		break;
+	case UICC_APPL_TYPE_UICC_USIM:
+		DBG("USIM application");
+		pbd->sim_func->read_file_info(get_sim(), SIM_EFPBR_FILEID,
+						pb_reference_info_cb, cbd);
+		break;
+	default:
+		DBG("UICC application type not unknown or supported");
+		goto error;
+		break;
+	}
+
+	return;
+error:
+
+	if (cb && cbd)
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+	g_free(cbd);
+}
+
+static gboolean isi_phonebook_register(gpointer user)
+{
+	struct ofono_phonebook *pb = user;
+	DBG("");
+	ofono_phonebook_register(pb);
+	return FALSE;
+}
+
+static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
+			 void *opaque)
+{
+	struct ofono_phonebook *pb = opaque;
+
+	if (!alive) {
+		DBG("Unable to bootstrap phonebook driver");
+		return;
+	}
+
+	DBG("%s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client), g_isi_version_minor(client));
+	g_idle_add(isi_phonebook_register, pb);
+}
+
+static int isi_phonebook_probe(struct ofono_phonebook *pb, unsigned int vendor,
+				void *user)
+{
+	GIsiModem *idx = user;
+	struct pb_data *data = g_try_new0(struct pb_data, 1);
+	DBG("");
+
+	if (!data)
+		return -ENOMEM;
+
+	data->client = get_pn_uicc_client(idx, PN_UICC);
+
+	if (!data->client) {
+		g_free(data);
+		return -ENOMEM;
+	}
+
+	data->sim_func = get_sim_driver_func();
+	ofono_phonebook_set_data(pb, data);
+
+	if (!g_isi_verify(data->client, reachable_cb, pb))
+		DBG("Unable to verify reachability");
+
+	return 0;
+}
+
+static void isi_phonebook_remove(struct ofono_phonebook *pb)
+{
+	struct pb_data *data = ofono_phonebook_get_data(pb);
+	DBG("");
+	pb_files = NULL;
+	pb_next = NULL;
+	phonebook_entry_start = NULL;
+	phonebook_entry_current = NULL;
+
+	if (data) {
+		pn_uicc_client_destroy(data->client);
+		g_free(data);
+	}
+}
+
+static struct ofono_phonebook_driver driver = {
+	.name = "isimodem25",
+	.probe = isi_phonebook_probe,
+	.remove = isi_phonebook_remove,
+	.export_entries = isi_export_entries
+};
+
+void isi_phonebook_init()
+{
+	DBG("");
+	ofono_phonebook_driver_register(&driver);
+}
+
+void isi_phonebook_exit()
+{
+	DBG("");
+	ofono_phonebook_driver_unregister(&driver);
+}
diff --git a/drivers/isimodem2.5/radio-settings.c b/drivers/isimodem2.5/radio-settings.c
new file mode 100644
index 0000000..237fd72
--- /dev/null
+++ b/drivers/isimodem2.5/radio-settings.c
@@ -0,0 +1,313 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/radio-settings.h>
+
+#include <glib.h>
+
+#include "debug.h"
+#include "gss.h"
+#include "network.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "timeout.h"
+
+struct radio_data {
+	GIsiClient *client;
+};
+
+static enum ofono_radio_access_mode isi_mode_to_ofono_mode(guint8 mode)
+{
+	switch (mode) {
+	case GSS_DUAL_RAT:
+		return OFONO_RADIO_ACCESS_MODE_ANY;
+	case GSS_GSM_RAT:
+		return OFONO_RADIO_ACCESS_MODE_GSM;
+	case GSS_UMTS_RAT:
+		return OFONO_RADIO_ACCESS_MODE_UMTS;
+	default:
+		return -1;
+	}
+}
+
+static int ofono_mode_to_isi_mode(enum ofono_radio_access_mode mode)
+{
+	switch (mode) {
+	case OFONO_RADIO_ACCESS_MODE_ANY:
+		return GSS_DUAL_RAT;
+	case OFONO_RADIO_ACCESS_MODE_GSM:
+		return GSS_GSM_RAT;
+	case OFONO_RADIO_ACCESS_MODE_UMTS:
+		return GSS_UMTS_RAT;
+	default:
+		return -1;
+	}
+}
+
+static gboolean rat_mode_read_resp_cb(GIsiClient *client,
+						const void *restrict data,
+						size_t len,
+						uint16_t object,
+						void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
+	int mode = -1;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s", gss_message_id_name(msg[0]));
+
+	if (len < 3) {
+		DBG("truncated message");
+		return FALSE;
+	}
+
+	if (msg[0] == GSS_CS_SERVICE_FAIL_RESP)
+		goto error;
+
+	if (msg[0] == GSS_CS_SERVICE_RESP) {
+		GIsiSubBlockIter iter;
+
+		for (g_isi_sb_iter_init(&iter, msg, len, 3);
+				g_isi_sb_iter_is_valid(&iter);
+				g_isi_sb_iter_next(&iter)) {
+			switch (g_isi_sb_iter_get_id(&iter)) {
+			case GSS_RAT_INFO: {
+				guint8 isi_mode;
+
+				if (!g_isi_sb_iter_get_byte(&iter,
+								&isi_mode, 2))
+					goto error;
+
+				mode = isi_mode_to_ofono_mode(isi_mode);
+				DBG("ISI mode=%d, oFono mode=%d",
+					isi_mode, mode);
+				break;
+			}
+			default:
+				DBG("Skipping sub-block: %s (%zu bytes)",
+					gss_subblock_name(
+						g_isi_sb_iter_get_id(&iter)),
+					g_isi_sb_iter_get_len(&iter));
+				break;
+			}
+		}
+
+		CALLBACK_WITH_SUCCESS(cb, mode, cbd->data);
+		goto out;
+	}
+
+	return FALSE;
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(rd, cb, data);
+	const unsigned char msg[] = {
+		GSS_CS_SERVICE_REQ,
+		GSS_SELECTED_RAT_READ,
+		0x00 /* subblock count */
+	};
+	DBG("");
+
+	if (!cbd)
+		goto error;
+
+	if (g_isi_request_make(rd->client, msg, sizeof(msg), GSS_TIMEOUT,
+				rat_mode_read_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, data);
+	g_free(cbd);
+}
+
+static gboolean mode_write_resp_cb(GIsiClient *client,
+					const void *restrict data, size_t len,
+					uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s", gss_message_id_name(msg[0]));
+
+	if (len < 3) {
+		DBG("truncated message");
+		return FALSE;
+	}
+
+	if (msg[0] == GSS_CS_SERVICE_FAIL_RESP)
+		goto error;
+
+	if (msg[0] == GSS_CS_SERVICE_RESP) {
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		goto out;
+	}
+
+	return FALSE;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(rd, cb, data);
+	int isi_mode = ofono_mode_to_isi_mode(mode);
+	const unsigned char msg[] = {
+		GSS_CS_SERVICE_REQ,
+		GSS_SELECTED_RAT_WRITE,
+		0x01, /* subblock count */
+		GSS_RAT_INFO,
+		0x04, /* subblock length */
+		isi_mode,
+		0x00 /* filler */
+	};
+	DBG("oFono RAT mode=%d, ISI mode=%d", mode, isi_mode);
+
+	if (!cbd)
+		goto error;
+
+	if (isi_mode == -1)
+		goto error;
+
+	if (g_isi_request_make(rd->client, msg, sizeof(msg), GSS_TIMEOUT,
+				mode_write_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static gboolean isi_radio_settings_register(gpointer user)
+{
+	struct ofono_radio_settings *rs = user;
+	ofono_radio_settings_register(rs);
+	return FALSE;
+}
+
+static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
+				void *opaque)
+{
+	struct ofono_radio_settings *rs = opaque;
+
+	if (!alive) {
+		DBG("Radio settings driver bootstrap failed");
+		return;
+	}
+
+	DBG("%s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_idle_add(isi_radio_settings_register, rs);
+}
+
+static int isi_radio_settings_probe(struct ofono_radio_settings *rs,
+					unsigned int vendor,
+					void *user)
+{
+	GIsiModem *idx = user;
+	struct radio_data *rd = g_try_new0(struct radio_data, 1);
+
+	if (!rd)
+		return -ENOMEM;
+
+	rd->client = g_isi_client_create(idx, PN_GSS);
+
+	if (!rd->client) {
+		g_free(rd);
+		return -ENOMEM;
+	}
+
+	ofono_radio_settings_set_data(rs, rd);
+	g_isi_verify(rd->client, reachable_cb, rs);
+	return 0;
+}
+
+static void isi_radio_settings_remove(struct ofono_radio_settings *rs)
+{
+	struct radio_data *rd = ofono_radio_settings_get_data(rs);
+
+	if (rd->client)
+		g_isi_client_destroy(rd->client);
+
+	g_free(rd);
+}
+
+static struct ofono_radio_settings_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_radio_settings_probe,
+	.remove			= isi_radio_settings_remove,
+	.query_rat_mode		= isi_query_rat_mode,
+	.set_rat_mode		= isi_set_rat_mode
+};
+
+void isi_radio_settings_init()
+{
+	ofono_radio_settings_driver_register(&driver);
+}
+
+void isi_radio_settings_exit()
+{
+	ofono_radio_settings_driver_unregister(&driver);
+}
diff --git a/drivers/isimodem2.5/simu_resps.h b/drivers/isimodem2.5/simu_resps.h
new file mode 100644
index 0000000..043cec6
--- /dev/null
+++ b/drivers/isimodem2.5/simu_resps.h
@@ -0,0 +1,6800 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <stdint.h>
+#include <drivers/isimodem2.5/mce.h>
+#include <drivers/isimodem2.5/gpds.h>
+#include <drivers/isimodem2.5/sms.h>
+#include <drivers/isimodem2.5/network.h>
+#include <drivers/isimodem2.5/call.h>
+#include <drivers/isimodem2.5/uicc.h>
+#include <drivers/isimodem2.5/info.h>
+#include <drivers/isimodem2.5/ss.h>
+#include <drivers/isimodem2.5/gss.h>
+#include <gisi/pipe_wg25.h>
+#include <src/simutil.h>
+
+/*struct ofono_modem *fake_modem;*/
+struct isimodem25_simu {
+	GIsiClient *client;
+	uint8_t request;
+	GIsiResponseFunc first_cb;
+	struct isi_cb_data *cbd;
+	unsigned char *nextmsg;
+	unsigned char *longreq;
+};
+
+struct isimodem25_response {
+	uint8_t resource;
+	uint8_t request;
+	const unsigned char *response;
+	uint8_t len;
+	const unsigned char *next;
+	const uint16_t *longreq;
+	const uint8_t reqlen;
+};
+
+/* UICC type defintions */
+#define         UICC_TYPE 2
+
+/* NET_MODEM Simulation messages */
+const uint16_t reg_auto[] = {
+	NET_SET_REQ,
+	-1,			/* Registered in another protocol? */
+	0x01,			/* Sub-block count */
+	NET_OPERATOR_INFO_COMMON,
+	0x04,			/* Sub-block length */
+	NET_SELECT_MODE_USER_RESELECTION,
+	0x00			/* Index not used */
+};
+
+const unsigned char set_auto_resp_cb_msg[] = {
+	NET_SET_RESP,
+	NET_CAUSE_OK,
+	2,			/* Number of sub-blocks */
+	NET_MODEM_REG_INFO_COMMON,
+	4,
+	NET_REG_STATUS_HOME,
+	NET_SELECT_MODE_AUTOMATIC,
+	/* Extra Sub-block (check code coverage) */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_GSM_RAT,
+	0,
+};
+
+const uint16_t reg_manual[] = {
+	NET_SET_REQ,
+	-1,			/* Registered in another protocol? */
+	-1,			/* Sub-block count */
+	NET_OPERATOR_INFO_COMMON,
+	0x04,			/* Sub-block length */
+	NET_SELECT_MODE_MANUAL,
+	0x00			/* Index not used */
+};
+
+const unsigned char set_manual_resp_cb_msg[] = {
+	NET_SET_RESP,
+	NET_CAUSE_OK,
+	2,			/* Number of sub-blocks */
+	NET_MODEM_REG_INFO_COMMON,
+	4,
+	NET_REG_STATUS_HOME,
+	NET_SELECT_MODE_MANUAL,
+	/* Extra Sub-block (check code coverage) */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_GSM_RAT,
+	0,
+};
+
+const unsigned char reg_status_resp_cb_auto_msg[] = {
+	NET_MODEM_REG_STATUS_GET_RESP,
+	NET_CAUSE_OK,
+	3,			/* Number of sub-blocks */
+	/* Subblock 1 */
+	NET_MODEM_REG_INFO_COMMON,
+	4,			/*len */
+	NET_REG_STATUS_HOME, /*=0*/
+	NET_SELECT_MODE_AUTOMATIC, /*=2*/
+	/* Subblock 2 */
+	NET_MODEM_GSM_REG_INFO,
+	24,			/*len */
+	2, 1, /*LAC*/ 0, 0, 0, 15,	/*cell id */
+	0x42, 0xF4, 0x50,	/*BCD operator code (MCC & MNC) */
+	NET_GSM_BAND_900_1800,
+	NET_GSM_HOME_PLMN,
+	0,			/*GPRS support true/false */
+	NET_GPRS_MODE_NONE,
+	1,			/*CS services */
+	0,			/*GPRS serv */
+	0,			/*EGPRS support */
+	0,			/*DTM support */
+	0, /*RAC*/ 0, /*HSDPA*/ 0, /*HSUPA*/ 1,	/*camped in HPLMN */
+	NET_GSM_RAT,		/* RAT name */
+	/* Extra Sub-block (check code coverage) */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_GSM_RAT,
+	0,
+};
+
+const unsigned char rssi_resp_cb_msg[] = {
+	NET_RSSI_GET_RESP,
+	NET_CAUSE_OK,
+	2,
+	/* Sub-block 1 */
+	NET_RSSI_CURRENT,
+	4,
+	75,			/*signal bars % */
+	80,			/*dBm */
+	/* Extra Sub-block (check code coverage) */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_GSM_RAT,
+	0,
+};
+
+const unsigned char rssi_ind_cb_msg[] = {
+	NET_RSSI_IND,
+	50,			/*signal bars % */
+	100			/*dBm */
+};
+
+const unsigned char reg_status_ind_cb_msg[] = {
+	NET_MODEM_REG_STATUS_IND,
+	0,			/*filler */
+	2,			/*number of sub-blocks */
+	/* Sub-block 1 */
+	NET_MODEM_REG_INFO_COMMON,
+	4,			/*len */
+	NET_REG_STATUS_HOME, /*=1*/
+	NET_SELECT_MODE_AUTOMATIC, /*=2*(*/
+	/* Extra Sub-block (check code coverage) */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_GSM_RAT,
+	0,
+};
+
+const unsigned char rat_ind_cb_msg[] = {
+	NET_RAT_IND,		/* (= 0x35) */
+	0,			/*Filler */
+	2,			/*number of sub-blocks */
+	/* Sub-block 1 */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	8,
+	NET_GSM_RAT,
+	1,
+	0,
+	0, 0, 0,
+	/* Sub-block 1 */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_UMTS_RAT,
+	0,
+};
+
+const unsigned char rat_resp[] = {
+	NET_RAT_RESP,
+	NET_CAUSE_OK,
+	2,			/*number of sub-blocks */
+	/* Sub-block 1 */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	8,
+	NET_GSM_RAT,
+	1,
+	0,
+	0, 0, 0,
+	/* Sub-block 1 */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_UMTS_RAT,
+	0,
+};
+
+const unsigned char available_resp_cb_msg[] = {
+	NET_MODEM_AVAILABLE_GET_RESP,
+	NET_CAUSE_OK,
+	7,			/*number of sub-blocks */
+	/* Sub-block 1 */
+	NET_MODEM_AVAIL_NETWORK_INFO_COMMON,
+	4,
+	NET_OPER_STATUS_CURRENT,
+	15,			/*index of CS arrays */
+	/* Sub-block 2 */
+	NET_MODEM_DETAILED_NETWORK_INFO,
+	12,
+	0x42, 0xF4, 0x50,	/*BCD operator code */
+	NET_GSM_BAND_900_1800,
+	NET_GSM_PREFERRED_PLMN,
+	NET_UMTS_NOT_AVAILABLE,
+	0x05, 0x00,		/* LAC */
+	0,			/*Filler */
+	0,			/*Filler */
+	/* Sub-block 3 */
+	NET_MODEM_AVAIL_NETWORK_INFO_COMMON,
+	4,
+	NET_OPER_STATUS_FORBIDDEN,
+	254,			/*index of CS arrays */
+	/* Sub-block 4 */
+	NET_MODEM_DETAILED_NETWORK_INFO,
+	12,
+	0x42, 0xF4, 0x19,	/*BCD operator code (MCC & MNC) */
+	NET_GSM_BAND_900_1800,
+	NET_GSM_PREFERRED_PLMN,
+	NET_UMTS_NOT_AVAILABLE,
+	0x00, 0x04,		/* LAC */
+	0,			/*Filler */
+	0,			/*Filler */
+	/* Sub-block 5 */
+	NET_MODEM_AVAIL_NETWORK_INFO_COMMON,
+	4,
+	NET_OPER_STATUS_AVAILABLE,
+	4,			/*index of CS arrays */
+	/* Sub-block 6 */
+	NET_MODEM_DETAILED_NETWORK_INFO,
+	12,
+	0x42, 0xF0, 0x07,	/*BCD operator code (MCC & MNC) */
+	NET_GSM_BAND_900_1800,
+	NET_GSM_PREFERRED_PLMN,
+	NET_UMTS_AVAILABLE,
+	0x00, 0x04,		/* LAC */
+	0,			/*Filler */
+	0,			/*Filler */
+	/* Extra Sub-block (check code coverage) */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_GSM_RAT,
+	0,
+};
+
+const unsigned char cell_info_resp_cb_msg[] = {
+	NET_CELL_INFO_GET_RESP,
+	NET_CAUSE_OK,
+	3,			/*number of sub-blocks */
+	/* Sub-block 1 */
+	NET_WCDMA_CELL_INFO,
+	20,			/*len */
+	01, 02, /*LAC*/ 0, 0, 0, 63,	/*Cell Id */
+	0, 0, 0, 0,		/*Bands info */
+	0x42, 0xF4, 0x50,	/*BCD operator code */
+	NET_SERVICE,
+	NET_GSM_HOME_PLMN,
+	0, 0, 0,		/* filler */
+	/* Sub-block 2 */
+	NET_GSM_CELL_INFO,
+	20,			/*len */
+	01, 02, /*LAC*/ 0, 0, 0, 63,	/*Cell Id */
+	0, 0, 0, 0,		/*Bands info */
+	0x42, 0xF4, 0x50,	/*BCD operator code */
+	NET_SERVICE,
+	NET_GSM_HOME_PLMN,
+	0, 0, 0,		/* filler */
+	/* Extra Sub-block (check code coverage) */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_GSM_RAT,
+	0,
+};
+
+const unsigned char nitz_name_ind_msg[] = {
+	NET_NITZ_NAME_IND,
+	0x42, 0xF4, 0x50,	/*BCD operator code (MCC & MNC) */
+	0, 0,			/*Filler */
+	1,			/*number of sub-blocks */
+	/* Sub-block 1 */
+	NET_SHORT_NITZ_NAME,
+	12,			/*SB Len */
+	3,			/*Data len */
+	0,			/*Filler */
+	/*Network IE, see TS24.008 */
+	0,			/*Network Name IEI (ETSI spec. not found) */
+	1,			/*Len */
+	0x80,			/*Coding scheme etc */
+	0, 'A',			/*Name */
+	0, 0, 0,		/*Filler */
+	/* Extra Sub-block (check code coverage) */
+	NET_RAT_INFO,		/* (= 0x2C) */
+	4,
+	NET_GSM_RAT,
+	0,
+};
+
+const unsigned char net_cs_state_resp[] = {
+	NET_CS_STATE_RESP,
+	0x00,
+	0x01,
+	0x00,
+};
+
+const unsigned char net_cs_state_ind_msg[] = {
+	NET_CS_STATE_IND,
+	0x01,
+	0x00,
+	0x00,
+	0x00, 0x00, 0x00,	/* Fillers */
+};
+
+const unsigned char net_cs_control_resp[] = {
+	NET_CS_CONTROL_RESP,
+	0x00,
+	0x00,
+	0x03,
+};
+
+/* GSS NET_MODEM Simulation messages */
+const uint16_t rat_query_req[] = {
+	GSS_CS_SERVICE_REQ,
+	GSS_SELECTED_RAT_READ
+};
+
+const unsigned char rat_query_resp_msg[] = {
+	GSS_CS_SERVICE_RESP,
+	GSS_SELECTED_RAT_READ,
+	4,			/*Number of sub-block */
+	/* Sub-block 1 */
+	GSS_RAT_INFO,
+	4,
+	GSS_DUAL_RAT,
+	0,
+	/* Sub-block 2 */
+	GSS_RAT_INFO,
+	4,
+	GSS_GSM_RAT,
+	0,
+	/* Sub-block 3 */
+	GSS_RAT_INFO,
+	4,
+	GSS_UMTS_RAT,
+	0,
+	/* Extra Sub-block */
+	0xfe,
+	2,
+};
+
+const uint16_t rat_set_any_req[] = {
+	GSS_CS_SERVICE_REQ,
+	GSS_SELECTED_RAT_WRITE,
+	-1, -1, -1,
+	GSS_DUAL_RAT
+};
+
+const unsigned char rat_set_any_resp_msg[] = {
+	GSS_CS_SERVICE_RESP,
+	GSS_SELECTED_RAT_WRITE,
+	1,			/* Number of sub-block */
+	/* Sub-block 1 */
+	GSS_RAT_INFO,
+	4,
+	GSS_DUAL_RAT,
+	0,
+};
+
+const uint16_t rat_set_umts_req[] = {
+	GSS_CS_SERVICE_REQ,
+	GSS_SELECTED_RAT_WRITE,
+	-1, -1, -1,
+	GSS_UMTS_RAT
+};
+
+const unsigned char rat_set_umts_resp_msg[] = {
+	GSS_CS_SERVICE_RESP,
+	GSS_SELECTED_RAT_WRITE,
+	1,			/*Number of sub-block */
+	/* Sub-block 1 */
+	GSS_RAT_INFO,
+	4,
+	GSS_UMTS_RAT,
+	0,
+};
+
+const uint16_t rat_set_gsm_req[] = {
+	GSS_CS_SERVICE_REQ,
+	GSS_SELECTED_RAT_WRITE,
+	-1, -1, -1,
+	GSS_GSM_RAT
+};
+
+const unsigned char rat_set_gsm_resp_msg[] = {
+	GSS_CS_SERVICE_RESP,
+	GSS_SELECTED_RAT_WRITE,
+	1,			/*Number of sub-block */
+	/* Sub-block 1 */
+	GSS_RAT_INFO,
+	4,
+	GSS_GSM_RAT,
+	0,
+};
+
+/* MCE Simulation messages set 1 */
+const unsigned char rf_on_resp_ok[] = {
+	MCE_RF_STATE_RESP,
+	MCE_OK, 0x00		/* Filler */
+};
+
+const unsigned char rf_state_query_resp[] = {
+	MCE_RF_STATE_QUERY_RESP,
+	MCE_RF_ON,		/*Current */
+	MCE_RF_ON		/*Target */
+};
+
+unsigned char modem_state_normal_ind[] = {
+	MCE_MODEM_STATE_IND,
+	MCE_OK, 0x00		/* Filler */
+};
+
+const unsigned char modem_state_query_resp_ok[] = {
+	MCE_MODEM_STATE_QUERY_RESP,
+	MCE_NORMAL, MCE_NORMAL
+};
+
+/* GPRS Simulation messages */
+const unsigned char gpds_attach_resp_msg[] = {
+	GPDS_ATTACH_RESP, GPDS_OK,
+	GPDS_CAUSE_UNKNOWN,
+	GPDS_ATTACH_TYPE_GPRS
+};
+
+const unsigned char gpds_status_resp_attached_msg[] = {
+	GPDS_STATUS_RESP, GPDS_ATTACHED, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	GPDS_TRANSFER_AVAIL, GPDS_TRANSFER_CAUSE_ATTACHED
+};
+
+const unsigned char gpds_transfer_status_ind_not_avail_detach_msg[] = {
+	GPDS_TRANSFER_STATUS_IND,
+	GPDS_TRANSFER_NOT_AVAIL, GPDS_TRANSFER_CAUSE_DETACHED
+};
+
+const unsigned char gpds_detach_resp_msg[] = {
+	GPDS_DETACH_RESP, GPDS_OK, GPDS_DETACH_TYPE_GPRS_MO
+};
+
+const unsigned char gpds_detach_ind_msg1[] = {
+	GPDS_DETACH_IND,
+	GPDS_CAUSE_DETACHED,
+	GPDS_DETACH_TYPE_GPRS_MO
+};
+
+const unsigned char gpds_configure_resp_msg[] = {
+	GPDS_CONFIGURE_RESP, GPDS_OK
+};
+
+const unsigned char gpds_context_id_create_resp_msg1[] = {
+	GPDS_CONTEXT_ID_CREATE_RESP, 0x01, GPDS_OK
+};
+
+const unsigned char gpds_ll_configure_resp_msg1[] = {
+	GPDS_LL_CONFIGURE_RESP, 0x01, GPDS_OK
+};
+
+const unsigned char gpds_context_configure_resp_msg1[] = {
+	GPDS_CONTEXT_CONFIGURE_RESP, 0x01, GPDS_OK
+};
+
+const unsigned char gpds_context_auth_resp_msg1[] = {
+	GPDS_CONTEXT_AUTH_RESP, 0x01, GPDS_OK
+};
+
+const unsigned char gpds_context_activate_resp_msg1[] = {
+	GPDS_CONTEXT_ACTIVATE_RESP, 0x01,
+	GPDS_OK, GPDS_CAUSE_UNKNOWN,
+	0x00, 0x00, 0x00
+};
+
+const unsigned char gpds_context_activate_ind_msg1[] = {
+	GPDS_CONTEXT_ACTIVATE_IND, 0x01, 0x04,
+	GPDS_PDP_ADDRESS_INFO, 0x08, 0x00, 0x04,
+	0x7F, 0x00, 0x00, 0x00,
+	GPDS_PDNS_ADDRESS_INFO, 0x08, 0x00, 0x04,
+	0x0A, 0x00, 0x00, 0x02,
+	GPDS_SDNS_ADDRESS_INFO, 0x08, 0x00, 0x04,
+	0x0A, 0x00, 0x00, 0x02,
+	GPDS_APN_INFO, 0x0C, 0X08,
+	0x69, 0x6E, 0x74, 0x65, 0x72, 0x69, 0x65, 0x74, 0x00
+};
+
+const unsigned char gpds_context_deactivate_resp_msg1[] = {
+	GPDS_CONTEXT_DEACTIVATE_RESP, 0x01, GPDS_OK
+};
+
+const unsigned char gpds_context_deactivate_ind_msg1[] = {
+	GPDS_CONTEXT_DEACTIVATE_IND, 0x01,
+	GPDS_CAUSE_DEACT_REGULAR, 0x00, 0x00, 0x00, 0x00
+};
+
+const unsigned char gpds_context_id_delete_ind_msg1[] = {
+	GPDS_CONTEXT_ID_DELETE_IND, 0x01
+};
+
+/* PIPE Simulation messages */
+const unsigned char pns_pep_connect_resp_msg1[] = {
+	PNS_PEP_CONNECT_RESP,
+	0x01,
+	PN_PIPE_NO_ERROR,
+	0x00, 0x00, 0x00, 0x00
+};
+
+const unsigned char pns_pep_disconnect_resp_msg1[] = {
+	PNS_PEP_DISCONNECT_RESP, 0x01, PN_PIPE_NO_ERROR
+};
+
+const unsigned char pns_pep_enable_resp_msg1[] = {
+	PNS_PEP_ENABLE_RESP, 0x01, PN_PIPE_NO_ERROR
+};
+
+/* UICC Simulation messages */
+const unsigned char uicc_card_ind_card_ready[] = {
+	UICC_CARD_IND,
+	UICC_CARD_READY,
+	UICC_CARD_TYPE_UICC
+};
+
+const unsigned char uicc_pin1_ind_pin_required[] = {
+	UICC_PIN_IND,
+	UICC_PIN_VERIFY_NEEDED,
+	/*PIN ID, PIN1=1...8, PIN2=0x81...0x88,
+	 * 0x11=PHNET_PIN what ever it means
+	 */
+	0x01,
+	1,			/*application id */
+	0,			/*filler */
+	0,			/*filler */
+	0			/*filler */
+};
+
+const unsigned char uicc_pin2_ind_pin_required[] = {
+	UICC_PIN_IND,
+	UICC_PIN_VERIFY_NEEDED,
+	0x81,
+	1,			/*application id */
+	0,			/*filler */
+	0,			/*filler */
+	0			/*filler */
+};
+
+const unsigned char uicc_pin1_ind_pin_verified[] = {
+	UICC_PIN_IND,
+	UICC_PIN_VERIFIED,
+	/*PIN ID, PIN1=1...8, PIN2=0x81...0x88,
+	 * 0x11=PHNET_PIN what ever it means
+	 */
+	0x01,
+	1,			/*application id */
+	0,			/*filler */
+	0,			/*filler */
+	0			/*filler */
+};
+
+const unsigned char uicc_pin2_ind_pin_verified[] = {
+	UICC_PIN_IND,
+	UICC_PIN_VERIFIED,
+	0x81,			/*PIN ID, PIN1=1...8, PIN2=0x81...0x88,
+				 * 0x11=PHNET_PIN what ever it means
+				 */
+	1,			/*application id */
+	0,			/*filler */
+	0,			/*filler */
+	0			/*filler */
+};
+
+const unsigned char uicc_pin_phnet_ind_pin_verified[] = {
+	UICC_PIN_IND,
+	UICC_PIN_VERIFIED,
+	/*PIN ID, PIN1=1...8, PIN2=0x81...0x88,
+	 * 0x11=PHNET_PIN what ever it means
+	 */
+	0x11,
+	1,			/*application id */
+	0,			/*filler */
+	0,			/*filler */
+	0			/*filler */
+};
+
+const unsigned char uicc_pin1_ind_puk_required[] = {
+	UICC_PIN_IND,
+	UICC_PIN_UNBLOCK_NEEDED,	/* UICC_PIN_UNBLOCK_NEEDED, */
+	/*PIN ID, PIN1=1...8, PIN2=0x81...0x88,
+	 * 0x11=PHNET_PIN what ever it means
+	 */
+	0x01,
+	1,			/*application id */
+	0,			/*filler */
+	0,			/*filler */
+	0			/*filler */
+};
+
+const unsigned char uicc_pin2_ind_puk_required[] = {
+	UICC_PIN_IND,
+	UICC_PIN_UNBLOCK_NEEDED,	/* UICC_PIN_UNBLOCK_NEEDED, */
+	0x81,			/*PIN ID, PIN1=1...8, PIN2=0x81...0x88,
+				 *0x11=PHNET_PIN what ever it means
+				 */
+	1,			/*application id */
+	0,			/*filler */
+	0,			/*filler */
+	0			/*filler */
+};
+
+const unsigned char uicc_pin_phnet_ind_puk_required[] = {
+	UICC_PIN_IND,
+	UICC_PIN_UNBLOCK_NEEDED,	/* UICC_PIN_UNBLOCK_NEEDED, */
+	/*PIN ID, PIN1=1...8, PIN2=0x81...0x88,
+	 *0x11=PHNET_PIN what ever it means
+	 */
+	0x11,
+	1,			/*application id */
+	0,			/*filler */
+	0,			/*filler */
+	0			/*filler */
+};
+
+const unsigned char uicc_ind_startup_complete[] = {
+	UICC_IND,
+	UICC_START_UP_COMPLETE
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFECC_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	SIM_EFECC_FILEID >> 8,	/* UICC elementary file ID */
+	SIM_EFECC_FILEID & 0xff,
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFECC_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 (actual of 6FB7) */
+	/*UICC_SB_FCI, FCI len = 0x1D=29 */
+	0x00, 0x1C, 0x00, 0x28, 0x00, 0x1D, 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len =0x1B=27 */
+	/*M Descriptor desc=0x41, coding=0x21(always 0x21),
+	 *0x41: Shareable, working EF, transparent
+	 */
+	0x82, 0x02, 0x41, 0x21,
+	/*M file id */
+	0x83, 0x02, SIM_EFECC_FILEID >> 8, SIM_EFECC_FILEID & 0xff,
+	0xA5, 0x03, 0xDA, 0x01, 0x01,	/*O proprietary */
+	0x8A, 0x01, 0x05,	/*O life cycle, state=activated */
+	/*M EFarr file id=6f06, EFarr record number */
+	0x8B, 0x03, 0x6F, 0x06, 0x06,
+	0x80, 0x02, 0x00, 0x0F,	/*M EF File size=0x0f=15 */
+	0x88, 0x00, /*SFI*/ 0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFIMSI_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	SIM_EFIMSI_FILEID >> 8,	/* UICC elementary file ID */
+	SIM_EFIMSI_FILEID & 0xff
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFIMSI_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	/*UICC_SB_FCI, FCI */
+	0x00, 0x1C, 0x00, 20, 0x00, (20 - 8 - 2), 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len */
+	/*M Descriptor desc=0x41 (transparent),
+	 * coding=0x21(always 0x21)*/
+	0x82, 0x02, 0x41, 0x21,
+	0x80, 0x02, 0x00, 0x08,	/*M EF File size */
+	0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFPNN_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	SIM_EFPNN_FILEID >> 8,	/* UICC elementary file ID */
+	SIM_EFPNN_FILEID & 0xff
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFPNN_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	/*UICC_SB_FCI, FCI */
+	0x00, 0x1C, 0x00, 20, 0x00, (20 - 8 - 2), 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len */
+	/*M Descriptor desc=0x42 (linear fixed),
+	 * coding=0x21(always 0x21)*/
+	0x82, 0x05, 0x42, 0x21, 0x00, 0x08, 0x01,
+	0x80, 0x02, 0x00, 0x08,	/*M EF File size */
+	0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFMSISDN_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	SIM_EFMSISDN_FILEID >> 8,	/* UICC elementary file ID */
+	SIM_EFMSISDN_FILEID & 0xff
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFMSISDN_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	/*UICC_SB_FCI, FCI */
+	0x00, 0x1C, 0x00, 20, 0x00, (20 - 8 - 2), 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len */
+	/*M Descriptor desc=0x42 (linear fixed),
+	 * coding=0x21(always 0x21)*/
+	0x82, 0x05, 0x42, 0x21, 0x00, 0x18, 0x05,
+	0x80, 0x02, 0x00, 0x78,	/*M EF File size */
+	0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFPNN_SIM_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	0,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	SIM_EFPNN_FILEID >> 8,	/* UICC elementary file ID */
+	SIM_EFPNN_FILEID & 0xff
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFPNN_SIM_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_ICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	0x00, 0x1C, 0x00, 0x18, 0x00, 0x0F,
+	0x01, 0x55,
+	0x00, 0x00, /*RFU*/ 0x00, 0x08,	/*File size */
+	0x6F, 0xC5,		/*File Id */
+	0x04,			/*File type */
+	0x01,
+	0x11, 0xF0, 0x22,	/*Access conditions */
+	0x01,			/*Status */
+	0x02,			/*Len of following */
+	0x01,			/*Structure */
+	0x08,			/*Record length */
+	0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFICI_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	0x6f80 >> 8,		/* UICC elementary file ID */
+	0x6f80 & 0xff
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFICI_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	/*UICC_SB_FCI, FCI */
+	0x00, 0x1C, 0x00, 20, 0x00, (20 - 8 - 2), 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len */
+	/*M Descriptor desc=0x46 (cyclic),
+	 *coding=0x21(always 0x21)*/
+	0x82, 0x05, 0x46, 0x21, 0x00, 0x04, 0x02,
+	0x80, 0x02, 0x00, 0x08,	/*M EF File size */
+	0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFLI_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	SIM_EFLI_FILEID >> 8,		/* UICC elementary file ID */
+	SIM_EFLI_FILEID & 0xff
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFLI_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	/*UICC_SB_FCI, FCI */
+	0x00, 0x1C, 0x00, 20, 0x00, (20 - 8 - 2), 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len */
+	/*M Descriptor desc=0x41 (transparent),
+	 *coding=0x21(always 0x21)*/
+	0x82, 0x03, 0x41, 0x21, 0x00,
+	0x80, 0x02, 0x00, 0x02,	/*M EF File size */
+	0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFPL_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	SIM_EFPL_FILEID >> 8,		/* UICC elementary file ID */
+	SIM_EFPL_FILEID & 0xff
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFPL_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	/*UICC_SB_FCI, FCI */
+	0x00, 0x1C, 0x00, 20, 0x00, (20 - 8 - 2), 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len */
+	/*M Descriptor desc=0x41 (transparent),
+	 *coding=0x21(always 0x21)*/
+	0x82, 0x03, 0x41, 0x21, 0x00,
+	0x80, 0x02, 0x00, 0x0a,	/*M EF File size */
+	0x55, 0x55
+};
+
+
+/* Phonebook Simulation messages set */
+const uint16_t uicc_appl_cmd_file_info_EFADN_SIM_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	1,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	0x6F3A >> 8,		/* UICC elementary file ID */
+	0x6F3A & 0xff,
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFADN_SIM_resp[] = {
+	0x0D, 0x25, 0x00, 0x00, 0x55, 0x01, 0x01,
+	0x00, 0x1C, 0x00, 0x18, 0x00, 0x0F,
+	0x01, 0x55,
+	0x00, 0x00, /*RFU*/ 0x02, 0x58,	/*File size */
+	0x6F, 0x3A,		/*File Id */
+	0x04,			/*File type */
+	0x01,
+	0x11, 0xF0, 0x22,	/*Access conditions */
+	0x01,			/*Status */
+	0x02,			/*Len of following */
+	0x01,			/*Structure */
+	0x1E,			/*Record length */
+	0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFPBR_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	SIM_EFPBR_FILEID >> 8,	/* UICC elementary file ID */
+	SIM_EFPBR_FILEID & 0xff,
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFPBR_resp[] = {
+	0x0D, 0x25, 0x00, 0x00, 0x55, 0x02, 0x01,	/* 1 SB */
+	/*UICC_SB_FCI, FCI */
+	0x00, 0x1C, 0x00, 20, 0x00, (20 - 8 - 2), 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len */
+	/*M Descriptor desc=0x42 (linear fixed),
+	 *coding=0x21(always 0x21)
+	 */
+	0x82, 0x05, 0x42, 0x21, 0x00, 0x64, 0x02,
+	0x80, 0x02, 0x00, 0xC8,	/*M EF File size */
+	0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFADN_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	0x4F3A >> 8,		/* UICC elementary file ID */
+	0x4F3A & 0xff,
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFADN_resp[] = {
+	0x0D, 0x25, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x1C, 0x00, 0x2C, 0x00, 0x21, 0x02, 0x55,
+	0x62, 0x1F,
+	0x82, 0x05, 0x42, 0x21, 0x00, 0x26, 0x14,
+	0x83, 0x02, 0x4F, 0x3A, 0xA5, 0x03, 0xDA, 0x01, 0x01,
+	0x8A, 0x01, 0x05,
+	0x8B, 0x03, 0x6F, 0x06, 0x02,
+	0x80, 0x02, 0x02, 0xF8,	/* 20 records * 38 record_length */
+	0x88, 0x01, 0xD0, 0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFEXT1_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	0x4F4A >> 8,		/* UICC elementary file ID */
+	0x4F4A & 0xff,
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFEXT1_resp[] = {
+	0x0D, 0x25, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x1C, 0x00, 0x2C, 0x00, 0x21, 0x02, 0x55,
+	0x62, 0x1F,
+	0x82, 0x05, 0x42, 0x21, 0x00, 0x0D, 0x14,
+	0x83, 0x02, 0x4F, 0x4A, 0xA5, 0x03, 0xDA, 0x01, 0x01,
+	0x8A, 0x01, 0x05,
+	0x8B, 0x03, 0x6F, 0x06, 0x02,
+	0x80, 0x02, 0x01, 0x04,
+	0x88, 0x01, 0x50, 0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFEMAIL_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	0x4F50 >> 8,		/* UICC elementary file ID */
+	0x4F50 & 0xff,
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFEMAIL_resp[] = {
+	0x0D, 0x25, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x1C, 0x00, 0x2C, 0x00, 0x21, 0x02, 0x55,
+	0x62, 0x1F,
+	0x82, 0x05, 0x42, 0x21, 0x00, 0x32, 0x32,
+	0x83, 0x02, 0x4F, 0x50, 0xA5, 0x03, 0xDA, 0x01, 0x01,
+	0x8A, 0x01, 0x05,
+	0x8B, 0x03, 0x6F, 0x06, 0x02,
+	0x80, 0x02, 0x00, 0x64,
+	0x88, 0x01, 0x80, 0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFSNE_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	0x4F19 >> 8,		/* UICC elementary file ID */
+	0x4F19 & 0xff,
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFSNE_resp[] = {
+	0x0D, 0x25, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x1C, 0x00, 0x2C, 0x00, 0x21, 0x02, 0x55,
+	0x62, 0x1F,
+	0x82, 0x05, 0x42, 0x21, 0x00, 0x32, 0x01,
+	0x83, 0x02, 0x4F, 0x19, 0xA5, 0x03, 0xDA, 0x01, 0x01,
+	0x8A, 0x01, 0x05,
+	0x8B, 0x03, 0x6F, 0x06, 0x02,
+	0x80, 0x02, 0x00, 0x32,
+	0x88, 0x01, 0x80, 0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_EFANR_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2,
+	-1,			/*Session ID */
+	-1,			/*Filler */
+	-1,			/*Filler */
+	-1,			/*number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/*Sub block length */
+	0x4F19 >> 8,		/* UICC elementary file ID */
+	0x4F11 & 0xff,
+};
+
+const unsigned char uicc_appl_cmd_file_info_EFANR_resp[] = {
+	0x0D, 0x25, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x1C, 0x00, 0x2C, 0x00, 0x21, 0x02, 0x55,
+	0x62, 0x1F,
+	0x82, 0x05, 0x42, 0x21, 0x00, 0x1C, 0x01,
+	0x83, 0x02, 0x4F, 0x11, 0xA5, 0x03, 0xDA, 0x01, 0x01,
+	0x8A, 0x01, 0x05,
+	0x8B, 0x03, 0x6F, 0x06, 0x02,
+	0x80, 0x02, 0x00, 0x1C,
+	0x88, 0x01, 0x80, 0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_general_transparent_SIM_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	1
+};
+
+const unsigned char uicc_appl_cmd_file_info_general_transparent_SIM_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_ICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	0x00, 0x1C, 0x00, 0x18, 0x00, 0x0F,
+	0x01, 0x55,
+	0x00, 0x00, /*RFU*/ 0x00, 0x08,	/*File size */
+	0x6F, 0xC5,		/*File Id */
+	0x04,			/*File type */
+	0x01,
+	0x11, 0xF0, 0x22,	/*Access conditions */
+	0x01,			/*Status */
+	0x02,			/*Len of following */
+	0x01,			/*Structure */
+	0x08,			/*Record length */
+	0x55
+};
+
+const uint16_t uicc_appl_cmd_file_info_general_transparent_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_FILE_INFO,
+	2
+};
+
+const unsigned char uicc_appl_cmd_file_info_general_transparent_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_FILE_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0x55,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	/*UICC_SB_FCI, FCI */
+	0x00, 0x1C, 0x00, 20, 0x00, (20 - 8 - 2), 0x02, 0x55,
+	0x62, 0x1B,		/* FCP template, len */
+	/*M Descriptor desc=0x41, coding=0x21(always 0x21),
+	 * 0x41: Shareable, working EF, transparent
+	 */
+	0x82, 0x02, 0x41, 0x21,
+	0x80, 0x02, 0x00, 0x08,	/*M EF File size */
+	0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_EFLI_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_TRANSPARENT,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	-1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	SIM_EFLI_FILEID >> 8,
+	SIM_EFLI_FILEID & 0xFF,	/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_EFLI_response[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_READ_TRANSPARENT,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	UICC_SB_FILE_DATA >> 8,
+	UICC_SB_FILE_DATA & 0xff,
+	0,			/*subblock length */
+	(8 + 2),		/*subblock length */
+	0, 0, 0, 2,		/*Length of filedata */
+	'f',
+	'i'
+};
+
+const uint16_t uicc_appl_cmd_EFPL_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_TRANSPARENT,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	-1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	SIM_EFPL_FILEID >> 8,
+	SIM_EFPL_FILEID & 0xFF,	/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_EFPL_response[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_READ_TRANSPARENT,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	UICC_SB_FILE_DATA >> 8,
+	UICC_SB_FILE_DATA & 0xff,
+	0,			/*subblock length */
+	(8 + 10),		/*subblock length */
+	0, 0, 0, 10,		/*Length of filedata */
+	'e',
+	'n',
+	'n',
+	'l',
+	's',
+	'w',
+	'p',
+	'l',
+	'p',
+	't'
+};
+
+
+const uint16_t uicc_appl_cmd_transparent_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_TRANSPARENT
+};
+
+const unsigned char uicc_appl_cmd_transparent_response[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_READ_TRANSPARENT,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	UICC_SB_FILE_DATA >> 8,
+	UICC_SB_FILE_DATA & 0xff,
+	0,			/*subblock length */
+	(8 + 8),		/*subblock length */
+	0, 0, 0, 9,		/*Length of filedata */
+	8,			/*Filedata: len */
+	0x10,			/*Filedata: number */
+	0x23,
+	0x45,
+	0x67,
+	0x89,
+	0x01,
+	0x23,
+	0x45
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADN1_SIM_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x6F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADN1_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_ADN1_response[] = {
+	/* UCS2 */
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26,
+	0x80, 0x00, 0x41, 0x00, 0x73, 0x00, 0x69, 0x00,
+	0x61, 0x00, 0x6B, 0x00, 0x61, 0x00, 0x73, 0x00,
+	0x70, 0x00, 0x61, 0x00, 0x6C, 0x00, 0xE4, 0xFF,
+	0x07, 0x81, 0x53, 0x28, 0x00, 0x71, 0x00, 0xF0,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADN2_SIM_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	2,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x6F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADN2_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	2,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_ADN2_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26,
+	'N', 'u', 'm', 'b', 'e', 'r', ' ', 'e', 'x', 't', 'e', 'n',
+	's', 'i', 'o', 'n',
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x0B, 0x91, 0x53, 0x48, 0x10, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32,
+	0x54, 0xFF,
+	0x01, 0x55, 0x55	/* With EXT1 file, record 1 */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADN3_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	3,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_ADN3_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26,
+	'B', 'o', 'n', 'd', '/', 'h', 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x0B, 0x91, 0x64, 0x48, 0x10, 0x32, 0x54, 0x76,
+	0x98, 0x10, 0x32,
+	0x54, 0xFF,
+	0x01, 0x55, 0x55	/* With EXT1 file, record 1 */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADN4_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	4,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_ADN4_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26,
+	'B', 'o', 'n', 'd', '/', 'm', 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x0B, 0x91, 0x76, 0x48, 0x10, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32,
+	0x54, 0xFF,
+	0x01, 0x55, 0x55	/* With EXT1 file, record 1 */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADN5_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	5,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_ADN5_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26,
+	'B', 'o', 'n', 'd', '/', 'w', 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x0B, 0x91, 0x76, 0x48, 0x10, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32,
+	0x54, 0xFF,
+	0x01, 0x55, 0x55	/* With EXT1 file, record 1 */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADNx_SIM_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	-1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x6F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_ADNx_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	-1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x3A,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_ADNx_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01, 0x00, 0x0F, 0x00, 0x30,
+	0x00, 0x00, 0x00, 0x26,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EXT1_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	2,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x4A,			/* UICC elementary file ID */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EXT1_SIM_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x6F,
+	0x4A,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_EXT1_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0D,
+	0x02,			/* additional data */
+	0x0A,			/* length */
+	0x76, 0x98, 0x10, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32, 0x54,
+	0x03,			/* next additional */
+	0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EXT3_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	2,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	3,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x4A,			/* UICC elementary file ID */
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EXT3_SIM_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	3,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x6F,
+	0x4A,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_EXT3_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0D,
+	0x02,			/* additional data */
+	0x03,			/* length */
+	0x76, 0x98, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xff,			/* next additional */
+	0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EFEMAIL_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	-1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x50,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_EFEMAIL_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x32,
+	0x74, 0x65, 0x6B, 0x6E, 0x69, 0x73, 0x65, 0x74,
+	0x00, 0x76, 0x69, 0x61, 0x74, 0x2E, 0x66, 0x69, 0xff,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0x1A, 0x02, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EFSNE_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	-1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x19,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_EFSNE_resp[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x32,
+	'S', 'e', 'c', 'o', 'n', 'd', ' ', 'n',
+	'a', 'm', 'e', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0x02, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EFANR_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	-1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x11,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_EFANR_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x11,
+	0x00,			/* EFaas record */
+	0x0B, 0x81, 0x20, 0x10, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32, 0x54, 0x76,
+	0xFF,			/* Capability */
+	0x01,			/* EXT 1 */
+	0x1A,			/* ADN SFI */
+	0x01,			/* ADN */
+	0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EFPBR1_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x30,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_EFPBR1_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64,	/* UICC_SB_FILE_DATA */
+	0xA8, 0x19,		/*Type 1, len=0x19=25 */
+	0xC0, 0x03, 0x4F, 0x3A, 0x02,
+	0xC1, 0x03, 0x4F, 0x25, 0x01,
+	0xC5, 0x03, 0x4F, 0x09, 0x04,
+	0xC6, 0x03, 0x4F, 0x35, 0x05,
+	0xC9, 0x03, 0x4F, 0x99, 0x0C,
+	0xA9, 0x0F,		/*Type 2, len=0x0f=15 */
+	0xC4, 0x03, 0x4F, 0x11, 0x08,
+	0xC3, 0x03, 0x4F, 0x19, 0x09,
+	0xCA, 0x03, 0x4F, 0x50, 0x0B,
+	0xAA, 0x14,		/*Type 3, len=0x14=20 */
+	0xC2, 0x03, 0x4F, 0x4A, 0x03,
+	0xC7, 0x03, 0x4F, 0x4B, 0x06,
+	0xC8, 0x03, 0x4F, 0x4C, 0x07,
+	0xCB, 0x03, 0x4F, 0x3D, 0x0A,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EFPBR2_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	2,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x4F,
+	0x30,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_EFPBR2_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64,	/* UICC_SB_FILE_DATA */
+	0xA8, 0x05,		/*Type 1, len=5 */
+	0xC7, 0x03, 0x4F, 0x4B, 0x06,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xA9, 0x00,		/*Type 2, len=0 */
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xAA, 0x00,		/*Type 3, len=0 */
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_EFMSISDN_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED,
+	-1,
+	-1,			/* Session ID */
+	-1,			/* Filler */
+	-1,			/* Filler */
+	-1,			/* number of subblocks */
+	/* Subblock 1 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1, -1, -1,		/* Filler */
+	-1,			/* Client ID,
+				read from UICC_APPL_HOST_ACTIVATE */
+	/* Subblock 2 */
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	-1,			/* Sub block length */
+	-1,			/* Record */
+	-1,			/* Record offset (0=beginning) */
+	-1,			/* Data amount (0=all) */
+	-1,			/* Filler */
+	/* Subblock 3 */
+	-1,
+	-1,
+	-1,
+	-1,			/* Sub block length */
+	0x6f,
+	0x40,			/* UICC elementary file ID */
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_EFMSISDN_response[] = {
+	0x0D, 0x23, 0x00, 0x00, 0x55, 0x02, 0x01,
+	0x00, 0x0F, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18,
+	'A', 'b', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x0B, 0x91, 0x76, 0x48, 0x10, 0x32, 0x54, 0x76, 0x98, 0x10,
+	0x32, 0x54, 0xFF, 0xFF
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_LINEAR_FIXED
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_response[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_READ_LINEAR_FIXED,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	UICC_SB_FILE_DATA >> 8,
+	UICC_SB_FILE_DATA & 0xff,
+	0,			/*subblock length */
+	(8 + 7),		/*subblock length */
+	0, 0, 0, 7,		/*Length of filedata */
+	0,			/*Filedata: Display condition */
+	'T',			/*Filedata: Name */
+	'i',
+	'e',
+	't',
+	'o',
+	0xff
+};
+
+const uint16_t uicc_appl_cmd_cyclic_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_READ_CYCLIC
+};
+
+const unsigned char uicc_appl_cmd_cyclic_response[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_READ_CYCLIC,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,			/*Number of subblocks */
+	/*Subblock 1 */
+	UICC_SB_FILE_DATA >> 8,
+	UICC_SB_FILE_DATA & 0xff,
+	0,			/*subblock length */
+	(8 + 1 + 3),		/*subblock length */
+	0, 0, 0, 1,		/*Length of filedata */
+	0,			/*Filedata: Display condition */
+	0x55, 0x55, 0x55
+};
+
+const uint16_t uicc_appl_cmd_transparent_write_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_UPDATE_TRANSPARENT,
+};
+
+const unsigned char uicc_appl_cmd_transparent_write_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_UPDATE_TRANSPARENT,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+};
+
+const uint16_t uicc_appl_cmd_linear_fixed_write_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_UPDATE_LINEAR_FIXED,
+};
+
+const unsigned char uicc_appl_cmd_linear_fixed_write_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_UPDATE_LINEAR_FIXED,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+};
+
+const uint16_t uicc_appl_cmd_cyclic_write_req[] = {
+	UICC_APPL_CMD_REQ,
+	UICC_APPL_UPDATE_CYCLIC,
+};
+
+const unsigned char uicc_appl_cmd_cyclic_write_resp[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_UPDATE_CYCLIC,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+};
+
+const uint16_t uicc_app_activate_req[] = {
+	UICC_APPLICATION_REQ,
+	UICC_APPL_HOST_ACTIVATE,
+};
+
+const unsigned char uicc_app_activate_ok_resp[] = {
+	UICC_APPLICATION_RESP,
+	UICC_APPL_HOST_ACTIVATE,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,
+	UICC_TYPE,		/*Card type */
+	4,			/* Number of subblocks */
+
+	/* Subblock 1 */
+	UICC_SB_CLIENT >> 8,
+	UICC_SB_CLIENT & 0xff,
+	0,			/*len */
+	8,			/*len */
+	0x55, 0x55, 0x55,
+	5,			/* Client ID */
+
+	/* Subblock 2 */
+	UICC_SB_FCI >> 8,
+	UICC_SB_FCI & 0xff,
+	0,			/*len */
+	0x17,			/*len */
+	0,
+	0x0D,
+	UICC_TYPE,
+	0x55,
+	0x62, 0x0B,
+	0xC6, 0x09, 0x90, 0x01, 0xC0,
+	0x83, 0x01, 0x01, 0x83, 0x01, 0x81, 0x55, 0x55,
+
+	/* Subblock 3 */
+	UICC_SB_CHV >> 8,
+	UICC_SB_CHV & 0xff,
+	0,			/*len */
+	8,			/*len */
+	0x01, 0x01, 0x55, 0x55,
+
+	/* Subblock 4 */
+	UICC_SB_CHV >> 8,
+	UICC_SB_CHV & 0xff,
+	0,			/*len */
+	8,			/*len */
+	0x02, 0x02, 0x55, 0x55,
+};
+
+const unsigned char uicc_app_activate_fail_resp[] = {
+	UICC_APPLICATION_RESP,
+	UICC_APPL_HOST_ACTIVATE,
+	UICC_STATUS_FAIL,
+	UICC_INVALID_PARAMETERS,
+	0,
+	UICC_CARD_TYPE_ICC,
+	0,			/* Number of subblocks */
+};
+
+const uint16_t uicc_app_list_req[] = {
+	UICC_APPLICATION_REQ,
+	UICC_APPL_LIST,
+};
+
+const unsigned char uicc_app_list_resp[] = {
+	UICC_APPLICATION_RESP,
+	UICC_APPL_LIST,
+	UICC_STATUS_CARD_NOT_PRESENT,	/* UICC_STATUS_OK, */
+	UICC_NO_DETAILS,
+	0,			/*filler */
+	UICC_TYPE,		/*Card type */
+	2,			/* Number of subblocks */
+
+	/* Sub-block 1 */
+	UICC_SB_APPL_DATA_OBJECT >> 8,
+	UICC_SB_APPL_DATA_OBJECT & 0xff,
+	0,			/*len */
+	12,			/*len */
+	0,			/*filler */
+	0,			/*filler */
+	UICC_TYPE,		/*Appl type */
+	UICC_TYPE,		/*Appl ID */
+	UICC_STATUS_APPL_ACTIVE,
+	0,			/*Appl Data Object len */
+	0,			/*filler */
+	0,			/*filler */
+
+	/* Sub-block 2 */
+	UICC_SB_APPLICATION >> 8,
+	UICC_SB_APPLICATION & 0xff,
+	0,			/*len */
+	8,			/*len */
+	0,			/*fille*r */
+	0,			/*filler */
+	UICC_TYPE,		/*Apll type */
+	UICC_TYPE,		/*Appl ID */
+};
+
+const unsigned char uicc_app_list_fail_resp[] = {
+	UICC_APPLICATION_RESP,
+	UICC_APPL_LIST,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,			/*filler */
+	1,			/*Card type */
+	2,			/* Number of subblocks */
+	/* Sub-block 1 */
+	UICC_SB_APPL_DATA_OBJECT >> 8,
+	UICC_SB_APPL_DATA_OBJECT & 0xff,
+	0,			/*len */
+	12,			/*len */
+	0,			/*filler */
+	0,			/*filler */
+	1,			/*Appl type */
+	1,			/*Appl ID */
+	UICC_STATUS_APPL_ACTIVE,
+	0,			/*Appl Data Object len */
+	0,			/*filler */
+	0,			/*filler */
+	/* Sub-block 2 */
+	UICC_SB_APPLICATION >> 8,
+	UICC_SB_APPLICATION & 0xff,
+	0,			/*len */
+	8,			/*len */
+	0,			/*fille*r */
+	0,			/*filler */
+	1,			/*Apll type */
+	1,			/*Appl ID */
+};
+
+/* SECURITY Simulation messages */
+const uint16_t uicc_pin_verify_req[] = {
+	UICC_PIN_REQ,
+	UICC_PIN_VERIFY,
+};
+
+const unsigned char uicc_pin_verify_resp[] = {
+	UICC_PIN_RESP,
+	UICC_PIN_VERIFY,
+	UICC_STATUS_OK,
+	0,
+	UICC_CARD_TYPE_UICC,
+	0x01,
+	0
+};
+
+const uint16_t uicc_pin_enable_req[] = {
+	UICC_PIN_REQ,
+	UICC_PIN_ENABLE,
+};
+
+const unsigned char uicc_pin_enable_resp[] = {
+	UICC_PIN_RESP,
+	UICC_PIN_ENABLE,
+	UICC_STATUS_OK,
+	0,
+	UICC_CARD_TYPE_UICC,
+	0x01,
+	0
+};
+
+const uint16_t uicc_pin_disable_req[] = {
+	UICC_PIN_REQ,
+	UICC_PIN_DISABLE,
+};
+
+const unsigned char uicc_pin_disable_resp[] = {
+	UICC_PIN_RESP,
+	UICC_PIN_DISABLE,
+	UICC_STATUS_FAIL,
+	0,
+	UICC_CARD_TYPE_UICC,
+	0x01,
+	1,
+	/*Sub-block 1 */
+	UICC_SB_STATUS_WORD >> 8,
+	UICC_SB_STATUS_WORD & 0xff,
+	0,
+	8,
+	0x55, 0x55,		/*filler */
+	0x63, 0xC1,
+};
+
+const uint16_t uicc_pin_reset_req[] = {
+	UICC_PIN_REQ,
+	UICC_PIN_UNBLOCK,
+};
+
+const unsigned char uicc_pin_reset_resp[] = {
+	UICC_PIN_RESP,
+	UICC_PIN_UNBLOCK,
+	UICC_STATUS_OK,
+	0,
+	UICC_CARD_TYPE_UICC,
+	0x01,
+	0
+};
+
+const uint16_t uicc_pin_change_req[] = {
+	UICC_PIN_REQ,
+	UICC_PIN_CHANGE,
+};
+
+const unsigned char uicc_pin_change_resp[] = {
+	UICC_PIN_RESP,
+	UICC_PIN_CHANGE,
+	UICC_STATUS_OK,
+	0,
+	UICC_CARD_TYPE_UICC,
+	0x01,
+	0
+};
+
+const uint16_t uicc_pin_query_req[] = {
+	UICC_PIN_REQ,
+	UICC_PIN_INFO,
+};
+
+const unsigned char uicc_pin_query_resp[] = {
+	UICC_PIN_RESP,
+	UICC_PIN_INFO,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,
+	UICC_CARD_TYPE_UICC,
+	1,
+	/*SB 1 */
+	UICC_SB_PIN_INFO >> 8,
+	UICC_SB_PIN_INFO & 0xff,
+	0,
+	8,
+	UICC_STATUS_PIN_ENABLED,
+	5,			/*PIN attempts */
+	5,			/*PUK attempts */
+	0
+};
+
+const uint16_t uicc_pin_prompt_req[] = {
+	UICC_PIN_REQ,
+	UICC_PIN_PROMPT_VERIFY,
+};
+
+const unsigned char uicc_pin_prompt_resp[] = {
+	0x0A, 0x18, 0x41, 0x00, 0x55, 0x02, 0x00
+};
+
+const uint16_t uicc_simlock_query_req[] = {
+	UICC_SIMLOCK_REQ,
+	UICC_SIMLOCK_ACTIVE,
+};
+
+const unsigned char uicc_simlock_query_resp[] = {
+	UICC_SIMLOCK_RESP,
+	UICC_SIMLOCK_ACTIVE,
+	UICC_STATUS_OK,
+	0,
+	UICC_SIMLOCK_STATUS_INACTIVE
+};
+
+/* CALL PIPE Simulation messages */
+const unsigned char call_modem_status_resp_msg[] = {
+	CALL_MODEM_STATUS_RESP, 0x00, 0x03,
+	CALL_MODEM_SB_STATUS_INFO, 0x08,
+	CALL_MODEM_ID_1, CALL_MODEM_MODE_SPEECH,
+	0x01, CALL_MODEM_STATUS_WAITING, 0x00, 0x00,
+	CALL_MODEM_SB_ADDR_AND_STATUS_INFO, 0x20,
+	CALL_MODEM_ID_1, CALL_MODEM_MODE_SPEECH,
+	0x01, CALL_MODEM_STATUS_WAITING, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x36,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_SERVER, CALL_MODEM_CAUSE_NO_CALL
+};
+
+const unsigned char call_modem_create_resp_msg2[] = {
+	CALL_MODEM_CREATE_RESP, CALL_MODEM_ID_2, 0
+};
+
+const unsigned char call_modem_release_resp_msg2[] = {
+	CALL_MODEM_RELEASE_RESP, CALL_MODEM_ID_2, 1,
+	CALL_MODEM_SB_CAUSE, 4,
+	CALL_MODEM_CAUSE_TYPE_CLIENT, CALL_MODEM_CAUSE_RELEASE_BY_USER
+};
+
+const uint16_t call_modem_control_req_hold_msg[] = {
+	CALL_MODEM_CONTROL_REQ, CALL_MODEM_ID_ACTIVE, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_HOLD, 0x00
+};
+
+const unsigned char call_modem_control_resp_hold_msg[] = {
+	CALL_MODEM_CONTROL_RESP, CALL_MODEM_ID_ACTIVE, 0x02,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_HOLD, 0x00,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_CLIENT, 0x00
+};
+
+const uint16_t call_modem_control_req_retr_msg[] = {
+	CALL_MODEM_CONTROL_REQ, CALL_MODEM_ID_HOLD, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_RETRIEVE, 0x00
+};
+
+const unsigned char call_modem_control_resp_retr_msg[] = {
+	CALL_MODEM_CONTROL_RESP, CALL_MODEM_ID_HOLD, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_RETRIEVE, 0x00
+};
+
+const uint16_t call_modem_control_req_swap_msg[] = {
+	CALL_MODEM_CONTROL_REQ, CALL_MODEM_ID_ACTIVE, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_SWAP, 0x00
+};
+
+const unsigned char call_modem_control_resp_swap_msg[] = {
+	CALL_MODEM_CONTROL_RESP, CALL_MODEM_ID_ACTIVE, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_SWAP, 0x00
+};
+
+const uint16_t call_modem_control_req_transfer_msg[] = {
+	CALL_MODEM_CONTROL_REQ, CALL_MODEM_ID_HOLD, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_TRANSFER, 0x00
+};
+
+const unsigned char call_modem_control_resp_transfer_msg[] = {
+	CALL_MODEM_CONTROL_RESP, CALL_MODEM_ID_ACTIVE, 0x02,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_TRANSFER, 0x00,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_NETWORK,
+	CALL_MODEM_NW_CAUSE_FACILITY_REJECTED
+};
+
+const uint16_t call_modem_control_req_conf_build_msg[] = {
+	CALL_MODEM_CONTROL_REQ, CALL_MODEM_ID_ACTIVE, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_CONFERENCE_BUILD, 0x00
+};
+
+const unsigned char call_modem_control_resp_conf_build_msg[] = {
+	CALL_MODEM_CONTROL_RESP, CALL_MODEM_ID_ACTIVE, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_CONFERENCE_BUILD, 0x00
+};
+
+const uint16_t call_modem_control_req_pri_chat_msg[] = {
+	CALL_MODEM_CONTROL_REQ, CALL_MODEM_ID_2, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_CONFERENCE_SPLIT, 0x00
+};
+
+const unsigned char call_modem_control_resp_pri_chat_msg[] = {
+	CALL_MODEM_CONTROL_RESP, CALL_MODEM_ID_2, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_CONFERENCE_SPLIT, 0x00
+};
+
+const unsigned char call_modem_control_ind_msg[] = {
+	CALL_MODEM_CONTROL_IND, CALL_MODEM_ID_NONE, 0x01,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_UNKNOWN, 0x00
+};
+
+const unsigned char call_modem_control_ind_error_msg[] = {
+	CALL_MODEM_CONTROL_IND, CALL_MODEM_ID_NONE, 0x02,
+	CALL_MODEM_SB_OPERATION, 0x04,
+	CALL_MODEM_OP_UNKNOWN, 0x00,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_NETWORK, CALL_MODEM_NW_CAUSE_FACILITY_REJECTED
+};
+
+const unsigned char call_modem_notification_ind_test[] = {
+	CALL_MODEM_NOTIFICATION_IND, 0x01, 0x07,
+	CALL_MODEM_SB_NOTIFY, 0x04, 0x00, 0x00,
+	CALL_MODEM_SB_SS_CODE, 0x04, 0x01, 0x4D,
+	CALL_MODEM_SB_SS_STATUS, 0x04, 0x07, 0x00,
+	CALL_MODEM_SB_SS_NOTIFY, 0x04, 0x07, 0x00,
+	CALL_MODEM_SB_SS_NOTIFY_INDICATOR, 0x04, 0x07, 0x00,
+	CALL_MODEM_SB_SS_HOLD_INDICATOR, 0x04, 0x00, 0x00,
+	CALL_MODEM_SB_SS_ECT_INDICATOR, 0x04, 0x01, 0x00
+};
+
+const unsigned char call_modem_notification_ind_barring_inc[] = {
+	CALL_MODEM_NOTIFICATION_IND, 0x01, 0x02,
+	CALL_MODEM_SB_SS_CODE, 0x04, 0x01, 0x61,
+	CALL_MODEM_SB_SS_STATUS, 0x04, 0x07, 0x00
+};
+
+const unsigned char call_modem_notification_ind_barring_out[] = {
+	CALL_MODEM_NOTIFICATION_IND, 0x01, 0x02,
+	CALL_MODEM_SB_SS_CODE, 0x04, 0x01, 0x4D,
+	CALL_MODEM_SB_SS_STATUS, 0x04, 0x07, 0x00
+};
+
+const unsigned char call_modem_notification_ind_forwarding_uncond[] = {
+	CALL_MODEM_NOTIFICATION_IND, 0x01, 0x02,
+	CALL_MODEM_SB_SS_CODE, 0x04, 0x00, 0x15,
+	CALL_MODEM_SB_SS_STATUS, 0x04, 0x07, 0x00
+};
+
+const unsigned char call_modem_notification_ind_forwarding_cond[] = {
+	CALL_MODEM_NOTIFICATION_IND, 0x01, 0x02,
+	CALL_MODEM_SB_SS_CODE, 0x04, 0x00, 0x04,
+	CALL_MODEM_SB_SS_STATUS, 0x04, 0x07, 0x00
+};
+
+const unsigned char call_modem_notification_ind_call_hold[] = {
+	CALL_MODEM_NOTIFICATION_IND, 0x01, 0x02,
+	CALL_MODEM_SB_SS_CODE, 0x04, 0xFF, 0xFF,
+	CALL_MODEM_SB_SS_STATUS, 0x04, CALL_MODEM_SS_STATUS_QUIESCENT, 0x00
+};
+
+const unsigned char call_modem_notification_ind_mpty[] = {
+	CALL_MODEM_NOTIFICATION_IND, 0x01, 0x02,
+	CALL_MODEM_SB_SS_CODE, 0x04, 0xFF, 0xFE,
+	CALL_MODEM_SB_SS_STATUS, 0x04, CALL_MODEM_SS_STATUS_ACTIVE, 0x00
+};
+
+const unsigned char call_modem_notification_ind_cug_call[] = {
+	CALL_MODEM_NOTIFICATION_IND, 0x01, 0x03,
+	CALL_MODEM_SB_CUG_INFO, 0x08, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00,
+	CALL_MODEM_SB_SS_STATUS, 0x04, 0x07, 0x00,
+	CALL_MODEM_SB_REMOTE_ADDRESS, 0x19, 0x10, 0x00, 0x00,
+	0x09,
+	0x00, 0x36, 0x00, 0x36, 0x00, 0x38, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33,
+	0x00, 0x34, 0x00, 0x35, 0x00, 0x36,
+	0x00
+};
+
+const unsigned char call_modem_dtmf_send_resp_msg2[] = {
+	CALL_MODEM_DTMF_SEND_RESP, CALL_MODEM_ID_2, 1,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_CLIENT, 0x00
+};
+
+const unsigned char call_modem_answer_resp_msg3[] = {
+	CALL_MODEM_ANSWER_RESP, CALL_MODEM_ID_3, 0
+};
+
+const unsigned char call_modem_status_ind_idle_msg[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_1, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_IDLE, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_CLIENT, CALL_MODEM_CAUSE_BUSY_USER_REQUEST
+};
+
+const unsigned char call_modem_status_ind_create_msg2[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_2, 4,
+	CALL_MODEM_SB_STATUS, 4,
+	CALL_MODEM_STATUS_CREATE, 0,
+	CALL_MODEM_SB_MODE, 4,
+	CALL_MODEM_MODE_SPEECH, 0,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_proceeding_msg2[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_2, 4,
+	CALL_MODEM_SB_STATUS, 4,
+	CALL_MODEM_STATUS_PROCEEDING, 0,
+	CALL_MODEM_SB_MODE, 4,
+	CALL_MODEM_MODE_SPEECH, 0,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_mo_alert_msg2[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_2, 4,
+	CALL_MODEM_SB_STATUS, 4,
+	CALL_MODEM_STATUS_MO_ALERTING, 0,
+	CALL_MODEM_SB_MODE, 4,
+	CALL_MODEM_MODE_SPEECH, 0,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_active_msg2[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_2, 0x04,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_ACTIVE, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_hold_msg2[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_2, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_HOLD, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00
+};
+
+const unsigned char call_modem_status_ind_hold_msg2multi[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_2, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_HOLD, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00
+};
+
+const unsigned char call_modem_status_ind_mo_release_msg2[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_2, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_MO_RELEASE, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_CLIENT, CALL_MODEM_CAUSE_RELEASE_BY_USER
+};
+
+const unsigned char call_modem_status_ind_idle_msg2[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_2, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_IDLE, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_CLIENT, CALL_MODEM_CAUSE_RELEASE_BY_USER
+};
+
+const unsigned char call_modem_status_ind_coming_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 4,
+	CALL_MODEM_SB_STATUS, 4,
+	CALL_MODEM_STATUS_COMING, 0,
+	CALL_MODEM_SB_MODE, 4,
+	CALL_MODEM_MODE_SPEECH, 0,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_proceeding_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 4,
+	CALL_MODEM_SB_STATUS, 4,
+	CALL_MODEM_STATUS_PROCEEDING, 0,
+	CALL_MODEM_SB_MODE, 4,
+	CALL_MODEM_MODE_SPEECH, 0,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_mt_alerting_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 4,
+	CALL_MODEM_SB_STATUS, 4,
+	CALL_MODEM_STATUS_MT_ALERTING, 0,
+	CALL_MODEM_SB_MODE, 4,
+	CALL_MODEM_MODE_SPEECH, 0,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_answered_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 0x04,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_ANSWERED, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_active_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 0x04,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_ACTIVE, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00
+};
+
+const unsigned char call_modem_status_ind_hold_init_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_HOLD_INITIATED, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00
+};
+
+const unsigned char call_modem_status_ind_hold_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_HOLD, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00
+};
+
+const unsigned char call_modem_status_ind_mt_release_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_MT_RELEASE, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_NETWORK, CALL_MODEM_NW_CAUSE_NORMAL
+};
+
+const unsigned char call_modem_status_ind_idle_msg3[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_3, 0x03,
+	CALL_MODEM_SB_STATUS, 0x04,
+	CALL_MODEM_STATUS_IDLE, 0x00,
+	CALL_MODEM_SB_MODE, 0x04,
+	CALL_MODEM_MODE_SPEECH, 0x00,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_NETWORK, CALL_MODEM_NW_CAUSE_NORMAL
+};
+
+const unsigned char call_modem_mt_alert[] = {
+	CALL_MODEM_MT_ALERT_IND,
+	CALL_MODEM_ID_ALL,
+	0x00
+};
+
+const unsigned char call_modem_status_ind_waiting_msg[] = {
+	CALL_MODEM_STATUS_IND, CALL_MODEM_ID_1, 4,
+	CALL_MODEM_SB_STATUS, 4,
+	CALL_MODEM_STATUS_WAITING, 0,
+	CALL_MODEM_SB_MODE, 4,
+	CALL_MODEM_MODE_SPEECH, 0,
+	CALL_MODEM_SB_ORIGIN_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x36,
+	0x00, 0x00,
+	CALL_MODEM_SB_DESTINATION_ADDRESS, 0x1C,
+	0x28, 0x01, 0x00, 0x0A,
+	0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32,
+	0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37,
+	0x00, 0x00
+};
+
+const uint16_t call_modem_relese_req_waiting_msg[] = {
+	CALL_MODEM_RELEASE_REQ, CALL_MODEM_ID_1, 0x01,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_CLIENT, CALL_MODEM_CAUSE_BUSY_USER_REQUEST
+};
+
+const unsigned char call_modem_relese_resp_waiting_msg[] = {
+	CALL_MODEM_RELEASE_RESP, CALL_MODEM_ID_1, 0x01,
+	CALL_MODEM_SB_CAUSE, 0x04,
+	CALL_MODEM_CAUSE_TYPE_CLIENT, CALL_MODEM_CAUSE_BUSY_USER_REQUEST
+};
+
+/* INFO Simulation messages */
+const unsigned char version_info_query_resp_ok[] = {
+	M_INFO_VERSION_READ_RESP,
+	M_INFO_OK,
+	1,
+	M_INFO_SB_MODEMSW_VERSION,
+	9,			/* subblock lenght */
+	0x00,
+	0x05,			/* lenght of string */
+	0x55, 0x38, 0x35, 0x30, 0x30	/*U8500 */
+};
+
+/* SMS Simulation messages */
+/*Receive*/
+const unsigned char sms_received_msg_ind[] = {
+	SMS_RECEIVED_MSG_IND, 0x00, 0x02,
+	SMS_SB_ADDRESS >> 8,	/*address subblock */
+	SMS_SB_ADDRESS & 0xFF,
+	0X10 >> 8,		/*subblock lenght */
+	0X10 & 0xFF,
+	SMS_SMSC_ADDRESS,	/*type */
+	8,			/* address lenght */
+	0x07,			/*Length of the SMSC information */
+	0x91,			/*Type of address of SMSC */
+	0x13, 0x26, 0x04, 0x00, 0x00, 0xF0,	/*SMSC number */
+	0x00, 0x00,		/*filler */
+	SMS_SB_TPDU >> 8,	/*message subblock */
+	SMS_SB_TPDU & 0xFF,
+	0X26 >> 8,		/*subblock lenght */
+	0X26 & 0xFF,
+	0x1E,			/*the lenght of the message(data)
+						SMS_TPDU_MAX_LEN = 232 */
+	0x00,			/*filler */
+	0x04,			/*First octet of this SMS-DELIVER message. */
+	0x0B,			/*Length of the sender address */
+	0x91,			/*Type of address of the sender number */
+	0x13, 0x46, 0x61, 0x00, 0x89, 0xF6,	/*Sender number */
+	0x00, 0x00,		/*Protocol identifier , Data encoding scheme */
+	0x20, 0x80, 0x62, 0x91, 0x73, 0x14, 0x08,	/*Time stamp */
+	0x0C,			/*Length of User data (SMS message) */
+	0xC8, 0xF7, 0x1D, 0x14, 0x96, 0x97, 0x41,
+	0xF9, 0x77, 0xFD, 0x07,	/*User data */
+	0x00, 0x00		/*fillers */
+};
+
+/*CBS message receive*/
+
+const unsigned char sms_received_cbs_msg_ind[] = {
+	SMS_CB_ROUTING_IND,
+	0x00,
+	0x02,
+	0x00,
+	0x2D,
+	0x00,
+	0x0C,
+	0x06,
+	0x01,
+	0x02,
+	0x06,
+	0x07,
+	0x08,
+	0x09,
+	0x00,
+	0x00, 0x0E,
+	0x00, 0x60,
+	0x10, 0x50, 0x00, 0x32, 0x01, 0x11, 0xFF, 0x57,
+	0xF9, 0x7B, 0xCC, 0x0E, 0xDF, 0x1B,
+	0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x68, 0x34, 0x1A, 0x8D, 0x46,
+	0xA3, 0xD1, 0x00, 0x00, 0x00, 0x00
+};
+
+const unsigned char sms_received_incorrect_msg_ind[] = {
+	0
+};
+
+const unsigned char sms_received_msg_report_resp[] = {
+	SMS_RECEIVED_MSG_REPORT_RESP,
+	SMS_OK,
+	0x00
+};
+
+const unsigned char sms_received_msg_report_resp_fail[] = {
+	0x00,
+	0x00,
+	0x00
+};
+
+const unsigned char sms_receive_message_resp_inactive[] = {
+	SMS_RECEIVE_MESSAGE_RESP,
+	SMS_RECEPTION_INACTIVE,
+	0x01,
+	SMS_SB_CAUSE,
+	0x08,
+	SMS_CAUSE_TYPE_COMMON,	/*this could be SMS_CAUSE_TYPE_EXT
+				 *and thus needs to be checked
+				 */
+	SMS_ERR_CS_INACTIVE,
+	0x00, 0x00		/*fillers */
+};
+
+const unsigned char sms_receive_message_resp_active[] = {
+	SMS_RECEIVE_MESSAGE_RESP,
+	SMS_RECEPTION_ACTIVE,
+	0x01,
+	SMS_SB_CAUSE,
+	0x08,
+	SMS_CAUSE_TYPE_COMMON,
+	SMS_OK,
+	0x00, 0x00		/*fillers */
+};
+
+/*send*/
+const unsigned char sms_message_send_resp[] = {
+	SMS_MESSAGE_SEND_RESP,
+	SMS_CAUSE_TYPE_COMMON,
+	SMS_OK,
+	0x00,			/* this should be reference number for
+				 * identifying a sent short message
+				 */
+	0x00, 0x00,		/*fillers */
+	0x00			/* nro of sub blocks */
+};
+
+const unsigned char sms_message_send_resp_fail[] = {
+	SMS_MESSAGE_SEND_RESP,
+	SMS_CAUSE_TYPE_COMMON,
+	0x02,
+	0x00,			/* this should be reference number for
+				 * identifying a sent short message
+				 */
+	0x00, 0x00,		/*fillers */
+	0x00			/* nro of sub blocks */
+};
+
+/* SMS_SETTINGS Simulation messages */
+const unsigned char sms_settings_update_resp_ok[] = {
+	SMS_SETTINGS_UPDATE_RESP,
+	0x02,			/* Route */
+	0x00,			/* SMS_OK */
+};
+
+const unsigned char sms_settings_update_resp_false[] = {
+	SMS_SETTINGS_UPDATE_RESP,
+	0x02,			/* Route */
+	0x02,
+};
+
+const unsigned char sms_settings_read_resp_cs_only[] = {
+	SMS_SETTINGS_READ_RESP,
+	0x00,			/* SMS_OK */
+	0x01,			/* number of sub blocks */
+	0x00,
+	0x23,			/* sub block id */
+	0x00,
+	0x08,			/* len */
+	0x01,			/* cs prio */
+	0x00,			/* ps prio */
+	0x00,
+	0x00,
+};
+
+/*SMS SCA Simulation messages */
+const uint16_t sms_appl_cmd_linear_req[] = {
+	0x0C, 0x23, -1, -1, -1, -1, 0x03, 0x00,
+	0x1F, 0x00, 0x08, 0x00, 0x00, 0x00, -1, 0x00,
+	0x0D, 0x00, 0x10, 0x6F, 0x42, 0x00, 0x00, 0x04,
+	0x00, 0x3F, 0x00, 0x7F, -1, 0x00, 0x00, 0x00,
+	0x13, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00
+};
+
+const unsigned char sms_sca_query_resp_ok[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_READ_LINEAR_FIXED,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,			/*filler */
+	UICC_CARD_TYPE_UICC,
+	1,
+	UICC_SB_FILE_DATA >> 8,
+	UICC_SB_FILE_DATA & 0xFF,
+	0x34 >> 8,		/*sb length */
+	0x34 & 0xFF,
+	0,
+	0,
+	0,
+	0x2C,			/*data length */
+	0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF,
+	0xE9,			/*parameter indicator */
+	0xFF,			/*TP-destination address */
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	/*TS-Service-centre-address */
+	0x07,			/*length of sca in bytes */
+	0x91,			/*type of sca */
+	0x53, 0x48, 0x50, 0x02, 0x02, 0x00,
+	0xFF, 0xFF, 0xFF, 0xFF,
+	0x00,			/*protocol identifier */
+	0xFF,			/*data coding scheme */
+	0xAD			/*TP validity period */
+};
+
+const unsigned char sms_sca_query_resp_fail[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_READ_LINEAR_FIXED,
+	0x02,
+	UICC_NO_DETAILS
+};
+
+const uint16_t sms_appl_cmd_linear_update_req[] = {
+	0x0C, 0x24	/*, 0x01, 0x00, 0x00, 0x00, 0x04,
+			   0x00, 0x1F, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01,
+			   0x00, 0x13, 0x00, 0x08, 0x01, 0x1D, 0x03, 0x00,
+			   0x00, 0x0D, 0x00, 0x10, 0x6F, 0x42, 0x00,
+			   0x00, 0x04, 0x00, 0x3F, 0x00, 0x7F, 0x10, 0x00,
+			   0x00, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x00,
+			   0x00 */
+};
+
+const unsigned char sms_sca_set_resp_ok[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_UPDATE_LINEAR_FIXED,
+	UICC_STATUS_OK,
+	UICC_NO_DETAILS,
+	0,
+	UICC_CARD_TYPE_UICC,
+	0
+};
+
+const unsigned char sms_sca_set_resp_fail[] = {
+	UICC_APPL_CMD_RESP,
+	UICC_APPL_UPDATE_LINEAR_FIXED,
+	0x02,
+	UICC_NO_DETAILS,
+	0,
+	UICC_CARD_TYPE_UICC,
+	0
+};
+
+/* ADVANCED VOICE CALL messages */
+
+/* Call forwarding */
+const uint16_t req_query_forw[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_FORWARDINGS >> 8,
+	SS_GSM_ALL_FORWARDINGS & 0xFF,
+};
+
+const unsigned char call_forward_query_resp_forw[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_FORWARDINGS >> 8,
+	SS_GSM_ALL_FORWARDINGS & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0
+};
+
+const uint16_t req_query_forw_A0[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_UNCONDITIONAL >> 8,
+	SS_GSM_FORW_UNCONDITIONAL & 0xFF,
+};
+
+const unsigned char call_forward_query_resp_A0[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_UNCONDITIONAL >> 8,
+	SS_GSM_FORW_UNCONDITIONAL & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	0x04, 0x24, 0x00, 0x01,
+	0x05, 0x20, 0x0B, 0x07, 0x11, 0x00, 0x04, 0x0B,
+	0x00, 0x00, 0x00, 0x34, 0x00, 0x38, 0x00, 0x36,
+	0x00, 0x30, 0x00, 0x32, 0x00, 0x39, 0x00, 0x35,
+	0x00, 0x33, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30
+};
+
+const uint16_t req_query_forw_B0[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_BUSY >> 8, SS_GSM_FORW_BUSY & 0xFF,
+};
+
+const unsigned char call_forward_query_resp_B0[] = {
+	0x01, 0x05, 0x0B, 0x00, 0x43, 0x00, 0x02,
+	0x04, 0x10, 0x00, 0x01,	/* SS_GSM_FORWARDING_INFO */
+	0x05, 0x0C, 0x0B, 0x04, 0x00, 0x00, 0x04, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x2F, 0x0C, 0x08, 0x0E, 0xA3, 0x05, 0x30, 0x03,
+	0x84, 0x01, 0x04, 0x00
+};
+
+const uint16_t req_query_forw_C0[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_NO_REPLY >> 8, SS_GSM_FORW_NO_REPLY & 0xFF,
+};
+
+const unsigned char call_forward_query_resp_C0[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_NO_REPLY >> 8,
+	SS_GSM_FORW_NO_REPLY & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	(SS_GSM_PROVISIONED | SS_GSM_ACTIVE | SS_GSM_REGISTERED),
+	0
+};
+
+const uint16_t req_query_forw_D0[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_NO_REACH >> 8, SS_GSM_FORW_NO_REACH & 0xFF,
+};
+
+const unsigned char call_forward_query_resp_D0[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_NO_REACH >> 8, SS_GSM_FORW_NO_REACH & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	SS_GSM_FORWARDING_INFO,
+	0x10,			/* length */
+	0x00,			/* filler */
+	0x01,			/* # of SB */
+	SS_GSM_FORWARDING_FEATURE,
+	0x0C,
+	SS_GSM_TELEPHONY,
+	SS_GSM_PROVISIONED,
+	0x00, 0x00, 0x08,
+	0x00,			/*len */
+	0x00,			/*subaddres len */
+	0x00, 0x00, 0x00	/*fillers */
+};
+
+const uint16_t req_query_forw_erase[] = {
+	SS_SERVICE_REQ,
+	SS_ERASURE,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_NO_REPLY >> 8, SS_GSM_FORW_NO_REPLY & 0xFF,
+};
+
+const unsigned char call_forward_query_resp_erase[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_ERASURE,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_NO_REPLY >> 8,
+	SS_GSM_FORW_NO_REPLY & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	0x04, 0x10, 0x00, 0x01,
+	0x05, 0x0C, 0x0B, 0x04, 0x00, 0x00, 0x08, 0x00,
+	0x00, 0x00, 0x00, 0x00
+};
+
+const uint16_t req_query_forw_erase_A0[] = {
+	SS_SERVICE_REQ,
+	SS_ERASURE,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_COND_FORWARDINGS >> 8,
+	SS_GSM_ALL_COND_FORWARDINGS & 0xFF,
+};
+
+const unsigned char call_forward_query_resp_erase_A0[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_ERASURE,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_COND_FORWARDINGS >> 8,
+	SS_GSM_ALL_COND_FORWARDINGS & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0
+};
+
+const uint16_t req_query_forw_erase_B0[] = {
+	SS_SERVICE_REQ,
+	SS_ERASURE,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_FORWARDINGS >> 8,
+	SS_GSM_ALL_FORWARDINGS & 0xFF,
+};
+
+const unsigned char call_forward_query_resp_erase_B0[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_ERASURE,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_FORWARDINGS >> 8, SS_GSM_ALL_FORWARDINGS & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0
+};
+
+const uint16_t forw_no_reply_set_req[] = {
+	SS_SERVICE_REQ,
+	SS_REGISTRATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_NO_REPLY >> 8,
+	SS_GSM_FORW_NO_REPLY & 0xFF,
+};
+
+const unsigned char forw_no_reply_set_resp[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_REGISTRATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_NO_REPLY >> 8, SS_GSM_FORW_NO_REPLY & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	0x04, 0x1C, 0x00, 0x01,
+	0x05, 0x18, 0x0B, 0x07, 0x11, 0x14, 0x08, 0x06, 0x00, 0x00,
+	0x00, 0x31, 0x00, 0x33, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34,
+	0x00, 0x34, 0x00, 0x00
+};
+
+const uint16_t forw_uncond_set_req[] = {
+	SS_SERVICE_REQ,
+	SS_REGISTRATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_UNCONDITIONAL >> 8,
+	SS_GSM_FORW_UNCONDITIONAL & 0xFF,
+};
+
+const unsigned char forw_uncond_set_resp[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_REGISTRATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_FORW_UNCONDITIONAL >> 8,
+	SS_GSM_FORW_UNCONDITIONAL & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	0x04, 0x1C, 0x00, 0x01,
+	0x05, 0x18, 0x0B, 0x07, 0x11, 0x00, 0x0C, 0x06, 0x00, 0x00,
+	0x00, 0x31, 0x00, 0x33, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34,
+	0x00, 0x34, 0x00, 0x00
+};
+
+/* CALL BARRING Simulation messages */
+#define BARRING_TYPE    SS_GSM_BARR_ALL_IN
+#define VOICE_OUT_STATUS        SS_GSM_TELEPHONY
+#define VOICE_IN_STATUS SS_GSM_SMS
+#define BARR_ENABLED    SS_GSM_TELEPHONY
+#define BARR_DISABLED   SS_GSM_SMS
+
+const uint16_t req_query_AO[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_BARR_ALL_OUT >> 8, SS_GSM_BARR_ALL_OUT & 0xFF,
+};
+
+const unsigned char call_barring_query_resp_AO[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_BARR_ALL_OUT >> 8,
+	SS_GSM_BARR_ALL_OUT & 0XFF,
+	0,			/* Filler */
+	2,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+	/* Sub block 2 */
+	SS_GSM_BARRING_INFO,
+	12,
+	0x55,
+	2,
+	/* sub sub block 1 */
+	SS_GSM_BARRING_FEATURE,
+	4,
+	SS_GSM_TELEPHONY,
+	SS_GSM_PROVISIONED,
+	/* sub sub block 2 */
+	SS_GSM_BARRING_FEATURE,
+	4,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC,
+	SS_GSM_PROVISIONED,
+};
+
+const uint16_t req_query_OI[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_BARR_OUT_INTER >> 8, SS_GSM_BARR_OUT_INTER & 0xFF,
+};
+
+const unsigned char call_barring_query_resp_OI[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_BARR_OUT_INTER >> 8,
+	SS_GSM_BARR_OUT_INTER & 0XFF,
+	0,			/*Filler */
+	2,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_ACTIVE,
+	0,
+	/* Sub block 2 */
+	SS_GSM_BARRING_INFO,
+	12,
+	0x55,
+	2,
+	/* sub sub block 1 */
+	SS_GSM_BARRING_FEATURE,
+	4,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ACTIVE,
+	/* sub sub block 2 */
+	SS_GSM_BARRING_FEATURE,
+	4,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC,
+	0,			/*SS_GSM_ACTIVE, */
+};
+
+const uint16_t req_query_OX[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_BARR_OUT_INTER_EXC_HOME >> 8,
+	SS_GSM_BARR_OUT_INTER_EXC_HOME & 0xFF,
+};
+
+const unsigned char call_barring_query_resp_OX[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_BARR_OUT_INTER_EXC_HOME >> 8,
+	SS_GSM_BARR_OUT_INTER_EXC_HOME & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0
+};
+
+const uint16_t req_query_AI[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_BARR_ALL_IN >> 8,
+	SS_GSM_BARR_ALL_IN & 0xFF,
+};
+
+const unsigned char call_barring_query_resp_AI[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_BARR_ALL_IN >> 8,
+	SS_GSM_BARR_ALL_IN & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0
+};
+
+const uint16_t req_query_IR[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_BARR_ALL_IN_ROAM >> 8,
+	SS_GSM_BARR_ALL_IN_ROAM & 0xFF,
+};
+
+const unsigned char call_barring_query_resp_IR[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_BARR_ALL_IN_ROAM >> 8,
+	SS_GSM_BARR_ALL_IN_ROAM & 0XFF,
+	0,			/* Filler */
+	3,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+	/* Sub block 2 */
+	SS_GSM_BSC_INFO,
+	16,
+	9,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_DATA_TELE,
+	SS_GSM_FACSIMILE, SS_GSM_SMS,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC,
+	SS_GSM_ALL_DATA_CIRCUIT_ASYNC,
+	SS_GSM_ALL_DATA_PACKET_SYNC,
+	SS_GSM_ALL_PAD_ACCESS,
+	0xff,
+	0,
+	0,
+	0,
+	0,
+	/* Sub block 3 */
+	0x2F, 0x10, 0x0C, 0x0E, 0xA2, 0x09, 0x83, 0x01,
+	0x10, 0x83, 0x01, 0x20, 0x82, 0x01, 0x10, 0x00
+};
+
+const uint16_t req_disable_all_in[] = {
+	SS_SERVICE_REQ,
+	SS_DEACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_INCOMING_BARR_SERV >> 8,
+	SS_GSM_INCOMING_BARR_SERV & 0xFF,
+};
+
+const unsigned char call_barring_disable_all_in_msg[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_DEACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_INCOMING_BARR_SERV >> 8,
+	SS_GSM_INCOMING_BARR_SERV & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0
+};
+
+const uint16_t req_disable_all_out[] = {
+	SS_SERVICE_REQ,
+	SS_DEACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_OUTGOING_BARR_SERV >> 8,
+	SS_GSM_OUTGOING_BARR_SERV & 0xFF,
+};
+
+const unsigned char call_barring_disable_all_out_msg[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_DEACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_OUTGOING_BARR_SERV >> 8,
+	SS_GSM_OUTGOING_BARR_SERV & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0
+};
+
+const uint16_t req_enable_all_in[] = {
+	SS_SERVICE_REQ,
+	SS_ACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_BARR_ALL_IN >> 8, SS_GSM_BARR_ALL_IN & 0xFF
+};
+
+const unsigned char call_barring_enable_all_in_msg[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_ACTIVATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_BARR_ALL_IN >> 8,
+	SS_GSM_BARR_ALL_IN & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	(SS_GSM_PROVISIONED | SS_GSM_ACTIVE),
+	0
+};
+
+const uint16_t req_enable_all_out[] = {
+	SS_SERVICE_REQ,
+	SS_ACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_BARR_ALL_OUT >> 8, SS_GSM_BARR_ALL_OUT & 0xFF
+};
+
+const unsigned char call_barring_enable_all_out_msg[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_ACTIVATION,
+	SS_GSM_TELEPHONY,
+	SS_GSM_BARR_ALL_OUT >> 8, SS_GSM_BARR_ALL_OUT & 0XFF,
+	0,			/* Filler */
+	1,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	(SS_GSM_PROVISIONED | SS_GSM_ACTIVE),
+	0
+};
+
+const uint16_t req_change_cb_password[] = {
+	SS_SERVICE_REQ,
+	SS_GSM_PASSWORD_REGISTRATION
+};
+
+const unsigned char req_change_cb_password_msg[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_GSM_PASSWORD_REGISTRATION,
+	SS_ALL_TELE_AND_BEARER
+};
+
+/* CALL WAITING Simulation messages */
+const uint16_t req_query_cw[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CALL_WAITING >> 8, SS_GSM_CALL_WAITING & 0xFF,
+};
+
+const unsigned char call_waiting_query_resp[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CALL_WAITING >> 8,
+	SS_GSM_CALL_WAITING & 0xFF,
+	0,			/* Filler */
+	3,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+	/* Sub block 2 */
+	SS_GSM_BSC_INFO,
+	16,
+	9,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_DATA_TELE,
+	SS_GSM_FACSIMILE,
+	SS_GSM_SMS,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC,
+	SS_GSM_ALL_DATA_CIRCUIT_ASYNC,
+	SS_GSM_ALL_DATA_PACKET_SYNC,
+	SS_GSM_ALL_PAD_ACCESS,
+	0xff,
+	0,
+	0,
+	0,
+	0,
+	/* Sub block 3 */
+	SS_GSM_DATA,
+	8,
+	SS_GSM_ACTIVE,
+	SS_GSM_CLI_PERMANENT,
+	0, 0, 0,		/*Filler */
+	0,			/* Number of sub-sub-blocks */
+};
+
+const uint16_t req_query_cw_A0[] = {
+	SS_SERVICE_REQ,
+	SS_DEACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CALL_WAITING >> 8, SS_GSM_CALL_WAITING & 0xFF
+};
+
+const unsigned char call_waiting_query_resp_A0[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_DEACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CALL_WAITING >> 8,
+	SS_GSM_CALL_WAITING & 0xFF,
+	0,			/*Filler */
+	2,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+	/* Sub block 2 */
+	SS_GSM_DATA,
+	8,
+	SS_GSM_PROVISIONED,
+	SS_GSM_CLI_PERMANENT,
+	0, 0, 0,		/* Filler */
+	0,			/* Number of sub-sub-blocks */
+};
+
+const uint16_t req_query_cw_B0[] = {
+	SS_SERVICE_REQ,
+	SS_ACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CALL_WAITING >> 8,
+	SS_GSM_CALL_WAITING & 0xFF
+};
+
+const unsigned char call_waiting_query_resp_B0[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_ACTIVATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CALL_WAITING >> 8,
+	SS_GSM_CALL_WAITING & 0xFF,
+	0,			/* Filler */
+	2,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+	/* Sub block 2 */
+	SS_GSM_DATA,
+	8,
+	SS_GSM_ACTIVE,
+	SS_GSM_CLI_PERMANENT,
+	0, 0, 0,		/*Filler */
+	0,			/* Number of sub-sub-blocks */
+};
+
+/* CLIP Simulation messages */
+const uint16_t req_query_clip[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CLIP >> 8, SS_GSM_CLIP & 0xFF
+};
+
+const unsigned char clip_query_resp[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CLIP >> 8,
+	SS_GSM_CLIP & 0xFF,
+	0,			/* Filler */
+	2,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+	/* Sub block 2 */
+	SS_GSM_BSC_INFO,
+	16,
+	9,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_DATA_TELE,
+	SS_GSM_FACSIMILE,
+	SS_GSM_SMS,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC,
+	SS_GSM_ALL_DATA_CIRCUIT_ASYNC,
+	SS_GSM_ALL_DATA_PACKET_SYNC,
+	SS_GSM_ALL_PAD_ACCESS,
+	0xff,
+	0,
+	0,
+	0,
+	0,
+};
+
+/* CLIR Simulation messages */
+const uint16_t req_query_clir[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CLIR >> 8,
+	SS_GSM_CLIR & 0xFF
+};
+
+const unsigned char clir_query_resp[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_CLIR >> 8,
+	SS_GSM_CLIR & 0xFF,
+	0,			/*Filler */
+	3,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_GSM_GENERIC_SERVICE_INFO,
+	8,
+	SS_GSM_PROVISIONED,
+	1,
+	/* Sub-sub block */
+	SS_GSM_CLIR_INFO,
+	4,
+	SS_GSM_CLI_PERMANENT,
+	0,			/*Filler */
+	/* Sub block 2 */
+	SS_GSM_BSC_INFO,
+	16,
+	9,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_DATA_TELE,
+	SS_GSM_FACSIMILE,
+	SS_GSM_SMS,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC,
+	SS_GSM_ALL_DATA_CIRCUIT_ASYNC,
+	SS_GSM_ALL_DATA_PACKET_SYNC,
+	SS_GSM_ALL_PAD_ACCESS,
+	0xff,
+	0,
+	0,
+	0,
+	0,
+	/* Sub block 3 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+};
+
+/* COLP Simulation messages */
+const uint16_t req_query_colp[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_COLP >> 8, SS_GSM_COLP & 0xFF
+};
+
+const unsigned char colp_query_resp[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_COLP >> 8, SS_GSM_COLP & 0xFF,
+	0,			/*Filler */
+	2,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+	/* Sub block 2 */
+	SS_GSM_BSC_INFO,
+	16,
+	9,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_DATA_TELE,
+	SS_GSM_FACSIMILE,
+	SS_GSM_SMS,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC,
+	SS_GSM_ALL_DATA_CIRCUIT_ASYNC,
+	SS_GSM_ALL_DATA_PACKET_SYNC,
+	SS_GSM_ALL_PAD_ACCESS,
+	0xff,
+	0,
+	0,
+	0,
+	0,
+};
+
+/* COLR Simulation messages */
+const uint16_t req_query_colr[] = {
+	SS_SERVICE_REQ,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_COLR >> 8,
+	SS_GSM_COLR & 0xFF
+};
+
+const unsigned char colr_query_resp[] = {
+	SS_SERVICE_COMPLETED_RESP,
+	SS_INTERROGATION,
+	SS_ALL_TELE_AND_BEARER,
+	SS_GSM_COLR >> 8, SS_GSM_COLR & 0xFF,
+	0,			/*Filler */
+	2,			/* Number of sub blocks */
+	/* Sub block 1 */
+	SS_STATUS_RESULT,
+	4,
+	SS_GSM_PROVISIONED,
+	0,
+	/* Sub block 2 */
+	SS_GSM_BSC_INFO,
+	16,
+	9,
+	SS_GSM_TELEPHONY,
+	SS_GSM_ALL_DATA_TELE,
+	SS_GSM_FACSIMILE,
+	SS_GSM_SMS,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC,
+	SS_GSM_ALL_DATA_CIRCUIT_ASYNC,
+	SS_GSM_ALL_DATA_PACKET_SYNC,
+	SS_GSM_ALL_PAD_ACCESS,
+	0xff,
+	0,
+	0,
+	0,
+	0,
+};
+
+
+/* USSD Simulation messages */
+const uint16_t req_ussd_init[] = {
+	SS_GSM_USSD_SEND_REQ,
+	SS_GSM_USSD_COMMAND,
+};
+
+const unsigned char req_ussd_init_resp[] = {
+	0x05, 0x0F, 0x05, 0x79, 0xCC, 0x74, 0x9A, 0x4E,
+	0xCF, 0xB7, 0xF7, 0xF3, 0x34, 0x68, 0x1E, 0x66,
+	0x93, 0xDF, 0xA0, 0xB7, 0x1B, 0x64, 0x73, 0xC1,
+	0x60, 0xA0, 0x62, 0x55, 0xCA, 0x02, 0xC1, 0xC3,
+	0x6C, 0x7B, 0x99, 0x5D, 0x9F, 0x87, 0xD9, 0xE4,
+	0x37, 0x08, 0x05, 0xAF, 0xA3, 0xCB, 0xEC, 0x3A,
+	0xFD, 0x45, 0x4F, 0x97, 0xC9, 0x6F, 0xF7, 0x3C,
+	0x9D, 0x96, 0xD3, 0xDF, 0xA0, 0x22, 0x3B, 0x3D,
+	0x0F, 0x83, 0xDA, 0x6F, 0x71, 0x3A, 0xCD, 0x4E,
+	0xDB, 0xCB, 0xF2, 0xF5, 0x7B, 0x3E, 0x0F, 0xA7,
+	0x40, 0x6F, 0x37, 0x08, 0xE6, 0x82, 0xC1, 0x40,
+	0xC5, 0xAA, 0x14, 0xA4, 0x0E, 0x83, 0xEC, 0xEF,
+	0x74, 0x3B, 0x3C, 0x9F, 0x87, 0xDF, 0xEC, 0x77,
+	0x38, 0xBD, 0x0E, 0x83, 0xE0, 0xFB, 0x3D, 0x9D,
+	0x9E, 0xCF, 0x83, 0x66, 0x30, 0x57, 0x0C, 0xE6,
+	0x92, 0xC1, 0x62, 0x30, 0x17, 0x00, 0x00
+};
+
+const unsigned char req_ussd_init_ind[] = {
+	/*test */
+	0x06, 0xfF, 0x02, 0x00
+};
+
+const uint16_t req_ussd_cancel[] = {
+	SS_GSM_USSD_SEND_REQ,
+	SS_GSM_USSD_END,
+	0x00			/* subblock count */
+};
+
+const unsigned char req_ussd_cancel_resp[] = {
+	SS_GSM_USSD_SEND_RESP,
+	0x0f,			/*Coding */
+	SS_GSM_USSD_END,
+	0,			/*Length of USSD string */
+};
+
+/* CBS Simulation messages */
+const unsigned char req_cbs_routing_resp[] = {
+	SMS_CB_ROUTING_RESP,
+	SMS_OK,			/*Sms cause */
+	0,
+};
+
+struct isimodem25_response fakeresps[] = {
+	/*
+	 * How to add new simulation msgs:
+	 * 1) Phonet resource
+	 * 2) Request for which you want a response OR
+			 Indication you want to subscribe for
+	 * 3) Response or indication message
+	 * 4) Size of the response message
+	 * 5) Next message
+	 * 6) Long request (in case a more detailed match is required)
+	 * 7) Size of long request
+	 */
+	/*Changeable responses. Do not change the order */
+	{
+	 PN_UICC, UICC_APPLICATION_REQ,
+	 uicc_app_list_resp,
+	 sizeof(uicc_app_list_resp),
+	 NULL,
+	 uicc_app_list_req,
+	 sizeof(uicc_app_list_req) / 2}
+	,
+
+	/*Not changeable responses */
+	{
+	 PN_UICC, UICC_APPLICATION_REQ,
+	 uicc_app_activate_ok_resp,
+	 sizeof(uicc_app_activate_ok_resp),
+	 NULL,
+	 uicc_app_activate_req,
+	 sizeof(uicc_app_activate_req) / 2}
+	,
+	/*PN_MODEM_MCE messages */
+	{
+	 PN_MODEM_MCE, MCE_MODEM_STATE_IND,
+	 modem_state_normal_ind,
+	 sizeof(modem_state_normal_ind),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_MODEM_MCE, MCE_RF_STATE_REQ,
+	 rf_on_resp_ok,
+	 sizeof(rf_on_resp_ok),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_MODEM_MCE, MCE_RF_STATE_QUERY_REQ,
+	 rf_state_query_resp,
+	 sizeof(rf_state_query_resp),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_MODEM_MCE, MCE_MODEM_STATE_QUERY_REQ,
+	 modem_state_query_resp_ok,
+	 sizeof(modem_state_query_resp_ok),
+	 NULL,
+	 NULL,
+	 0}
+	,
+
+	/* Network registration messages */
+	{
+	 PN_MODEM_NETWORK, NET_SET_REQ,
+	 set_auto_resp_cb_msg,
+	 sizeof(set_auto_resp_cb_msg),
+	 NULL, reg_auto,
+	 sizeof(reg_auto) / 2}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_SET_REQ,
+	 set_manual_resp_cb_msg,
+	 sizeof(set_manual_resp_cb_msg),
+	 NULL,
+	 reg_manual,
+	 sizeof(reg_manual) / 2}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_MODEM_REG_STATUS_GET_REQ,
+	 reg_status_resp_cb_auto_msg,
+	 sizeof(reg_status_resp_cb_auto_msg),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_RSSI_GET_REQ,
+	 rssi_resp_cb_msg,
+	 sizeof(rssi_resp_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_MODEM_AVAILABLE_GET_REQ,
+	 available_resp_cb_msg,
+	 sizeof(available_resp_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_RSSI_IND,
+	 rssi_ind_cb_msg,
+	 sizeof(rssi_ind_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_MODEM_REG_STATUS_IND,
+	 reg_status_ind_cb_msg,
+	 sizeof(reg_status_ind_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_RAT_IND,
+	 rat_ind_cb_msg,
+	 sizeof(rat_ind_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_RAT_REQ,
+	 rat_resp,
+	 sizeof(rat_resp),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_CELL_INFO_GET_REQ,
+	 cell_info_resp_cb_msg,
+	 sizeof(cell_info_resp_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_NITZ_NAME_IND,
+	 nitz_name_ind_msg,
+	 sizeof(nitz_name_ind_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_CS_STATE_IND,
+	 net_cs_state_ind_msg,
+	 sizeof(net_cs_state_ind_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_CS_STATE_REQ,
+	 net_cs_state_resp,
+	 sizeof(net_cs_state_resp),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_CS_CONTROL_REQ,
+	 net_cs_control_resp,
+	 sizeof(net_cs_control_resp),
+	 NULL}
+	,
+
+	/* GSS messages */
+	{
+	 PN_GSS, GSS_CS_SERVICE_REQ,
+	 rat_query_resp_msg,
+	 sizeof(rat_query_resp_msg),
+	 NULL, rat_query_req,
+	 sizeof(rat_query_req) / 2}
+	,
+	{
+	 PN_GSS, GSS_CS_SERVICE_REQ,
+	 rat_set_any_resp_msg,
+	 sizeof(rat_set_any_resp_msg),
+	 NULL, rat_set_any_req,
+	 sizeof(rat_set_any_req) / 2}
+	,
+	{
+	 PN_GSS, GSS_CS_SERVICE_REQ,
+	 rat_set_umts_resp_msg,
+	 sizeof(rat_set_umts_resp_msg),
+	 NULL, rat_set_umts_req,
+	 sizeof(rat_set_umts_req) / 2}
+	,
+	{
+	 PN_GSS, GSS_CS_SERVICE_REQ,
+	 rat_set_gsm_resp_msg,
+	 sizeof(rat_set_gsm_resp_msg),
+	 NULL, rat_set_gsm_req,
+	 sizeof(rat_set_gsm_req) / 2}
+	,
+
+	/* GPDS/GPRS messages */
+	{
+	 PN_GPDS, GPDS_ATTACH_REQ,
+	 gpds_attach_resp_msg,
+	 sizeof(gpds_attach_resp_msg),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_STATUS_REQ,
+	 gpds_status_resp_attached_msg,
+	 sizeof(gpds_status_resp_attached_msg),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_DETACH_REQ,
+	 gpds_detach_resp_msg,
+	 sizeof(gpds_detach_resp_msg),
+	 gpds_detach_ind_msg1}
+	,
+	{
+	 PN_GPDS, GPDS_CONFIGURE_REQ,
+	 gpds_configure_resp_msg,
+	 sizeof(gpds_configure_resp_msg),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_ID_CREATE_REQ,
+	 gpds_context_id_create_resp_msg1,
+	 sizeof(gpds_context_id_create_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_LL_CONFIGURE_REQ,
+	 gpds_ll_configure_resp_msg1,
+	 sizeof(gpds_ll_configure_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_CONFIGURE_REQ,
+	 gpds_context_configure_resp_msg1,
+	 sizeof(gpds_context_configure_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_AUTH_REQ,
+	 gpds_context_auth_resp_msg1,
+	 sizeof(gpds_context_auth_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_ACTIVATE_REQ,
+	 gpds_context_activate_resp_msg1,
+	 sizeof(gpds_context_activate_resp_msg1),
+	 gpds_context_activate_ind_msg1}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_DEACTIVATE_REQ,
+	 gpds_context_deactivate_resp_msg1,
+	 sizeof(gpds_context_deactivate_resp_msg1),
+	 gpds_context_deactivate_ind_msg1}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_context_activate_ind_msg1,
+	 sizeof(gpds_context_activate_ind_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_context_deactivate_ind_msg1,
+	 sizeof(gpds_context_deactivate_ind_msg1),
+	 gpds_context_id_delete_ind_msg1}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_context_id_delete_ind_msg1,
+	 sizeof(gpds_context_id_delete_ind_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_detach_ind_msg1,
+	 sizeof(gpds_detach_ind_msg1),
+	 gpds_transfer_status_ind_not_avail_detach_msg}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_transfer_status_ind_not_avail_detach_msg,
+	 sizeof(gpds_transfer_status_ind_not_avail_detach_msg),
+	 NULL}
+	,
+
+	/* PIPE/PEP messages */
+	{
+	 PN_PIPE, PNS_PEP_CONNECT_REQ,
+	 pns_pep_connect_resp_msg1,
+	 sizeof(pns_pep_connect_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_PIPE, PNS_PEP_DISCONNECT_REQ,
+	 pns_pep_disconnect_resp_msg1,
+	 sizeof(pns_pep_disconnect_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_PIPE, PNS_PEP_ENABLE_REQ,
+	 pns_pep_enable_resp_msg1,
+	 sizeof(pns_pep_enable_resp_msg1),
+	 NULL}
+	,
+
+	/*UICC messages */
+	/*SMS SCA query is here */
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 sms_sca_query_resp_ok,
+	 sizeof(sms_sca_query_resp_ok),
+	 NULL,
+	 sms_appl_cmd_linear_req,
+	 sizeof(sms_appl_cmd_linear_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 sms_sca_set_resp_ok,
+	 sizeof(sms_sca_set_resp_ok),
+	 NULL,
+	 sms_appl_cmd_linear_update_req,
+	 sizeof(sms_appl_cmd_linear_update_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_CARD_IND,
+	 uicc_card_ind_card_ready,
+	 sizeof(uicc_card_ind_card_ready),
+	 NULL}
+	,
+	{
+	 PN_UICC, UICC_PIN_IND,
+	 uicc_pin1_ind_pin_required,
+	 sizeof(uicc_pin1_ind_pin_required),
+	 uicc_pin2_ind_pin_verified}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin2_ind_pin_required,
+	 sizeof(uicc_pin1_ind_pin_required),
+	 uicc_pin2_ind_pin_verified}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin2_ind_pin_verified,
+	 sizeof(uicc_pin2_ind_pin_verified),
+	 uicc_pin_phnet_ind_pin_verified}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin_phnet_ind_pin_verified,
+	 sizeof(uicc_pin_phnet_ind_pin_verified),
+	 uicc_ind_startup_complete}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin1_ind_puk_required,
+	 sizeof(uicc_pin1_ind_puk_required),
+	 uicc_pin2_ind_puk_required}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin2_ind_puk_required,
+	 sizeof(uicc_pin2_ind_puk_required),
+	 uicc_pin_phnet_ind_puk_required}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin_phnet_ind_puk_required,
+	 sizeof(uicc_pin_phnet_ind_puk_required),
+	 uicc_ind_startup_complete}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_ind_startup_complete,
+	 sizeof(uicc_ind_startup_complete),
+	 NULL}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFIMSI_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFIMSI_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFIMSI_req,
+	 sizeof(uicc_appl_cmd_file_info_EFIMSI_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFPNN_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFPNN_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFPNN_req,
+	 sizeof(uicc_appl_cmd_file_info_EFPNN_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFMSISDN_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFMSISDN_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFMSISDN_req,
+	 sizeof(uicc_appl_cmd_file_info_EFMSISDN_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFPNN_SIM_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFPNN_SIM_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFPNN_SIM_req,
+	 sizeof(uicc_appl_cmd_file_info_EFPNN_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFECC_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFECC_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFECC_req,
+	 sizeof(uicc_appl_cmd_file_info_EFECC_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFICI_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFICI_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFICI_req,
+	 sizeof(uicc_appl_cmd_file_info_EFICI_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFLI_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFLI_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFLI_req,
+	 sizeof(uicc_appl_cmd_file_info_EFLI_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFPL_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFPL_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFPL_req,
+	 sizeof(uicc_appl_cmd_file_info_EFPL_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFADN_SIM_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFADN_SIM_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFADN_SIM_req,
+	 sizeof(uicc_appl_cmd_file_info_EFADN_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFPBR_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFPBR_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFPBR_req,
+	 sizeof(uicc_appl_cmd_file_info_EFPBR_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFADN_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFADN_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFADN_req,
+	 sizeof(uicc_appl_cmd_file_info_EFADN_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFEXT1_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFEXT1_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFEXT1_req,
+	 sizeof(uicc_appl_cmd_file_info_EFEXT1_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFEMAIL_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFEMAIL_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFEMAIL_req,
+	 sizeof(uicc_appl_cmd_file_info_EFEMAIL_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFSNE_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFSNE_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFSNE_req,
+	 sizeof(uicc_appl_cmd_file_info_EFSNE_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFANR_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFANR_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFANR_req,
+	 sizeof(uicc_appl_cmd_file_info_EFANR_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_general_transparent_SIM_resp,
+	 sizeof(uicc_appl_cmd_file_info_general_transparent_SIM_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_general_transparent_SIM_req,
+	 sizeof(uicc_appl_cmd_file_info_general_transparent_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_general_transparent_resp,
+	 sizeof(uicc_appl_cmd_file_info_general_transparent_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_general_transparent_req,
+	 sizeof(uicc_appl_cmd_file_info_general_transparent_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_EFLI_response,
+	 sizeof(uicc_appl_cmd_EFLI_response),
+	 NULL,
+	 uicc_appl_cmd_EFLI_req,
+	 sizeof(uicc_appl_cmd_EFLI_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_EFPL_response,
+	 sizeof(uicc_appl_cmd_EFPL_response),
+	 NULL,
+	 uicc_appl_cmd_EFPL_req,
+	 sizeof(uicc_appl_cmd_EFPL_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_transparent_response,
+	 sizeof(uicc_appl_cmd_transparent_response),
+	 NULL,
+	 uicc_appl_cmd_transparent_req,
+	 sizeof(uicc_appl_cmd_transparent_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFPBR1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFPBR1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFPBR1_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFPBR1_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFPBR2_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFPBR2_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFPBR2_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFPBR2_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN1_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN1_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN2_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN2_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN2_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN2_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN3_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN3_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN3_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN3_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN4_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN4_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN4_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN4_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN5_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN5_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN5_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN5_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADNx_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADNx_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADNx_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADNx_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN1_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN1_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN2_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN2_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN2_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN2_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADNx_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADNx_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADNx_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADNx_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFMSISDN_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFMSISDN_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFMSISDN_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFMSISDN_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EXT1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EXT1_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT1_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EXT1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EXT1_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT1_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EXT3_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT3_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EXT3_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT3_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EXT3_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT3_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EXT3_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT3_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFEMAIL_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFEMAIL_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFEMAIL_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFEMAIL_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFSNE_resp,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFSNE_resp),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFSNE_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFSNE_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFANR_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFANR_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFANR_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFANR_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_cyclic_response,
+	 sizeof(uicc_appl_cmd_cyclic_response),
+	 NULL,
+	 uicc_appl_cmd_cyclic_req,
+	 sizeof(uicc_appl_cmd_cyclic_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_transparent_write_resp,
+	 sizeof(uicc_appl_cmd_transparent_write_resp),
+	 NULL,
+	 uicc_appl_cmd_transparent_write_req,
+	 sizeof(uicc_appl_cmd_transparent_write_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_write_resp,
+	 sizeof(uicc_appl_cmd_linear_fixed_write_resp),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_write_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_write_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_cyclic_write_resp,
+	 sizeof(uicc_appl_cmd_cyclic_write_resp),
+	 NULL,
+	 uicc_appl_cmd_cyclic_write_req,
+	 sizeof(uicc_appl_cmd_cyclic_write_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_verify_resp,
+	 sizeof(uicc_pin_verify_resp),
+	 uicc_ind_startup_complete,
+	 uicc_pin_verify_req,
+	 sizeof(uicc_pin_verify_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_enable_resp,
+	 sizeof(uicc_pin_enable_resp),
+	 NULL,
+	 uicc_pin_enable_req,
+	 sizeof(uicc_pin_enable_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_disable_resp,
+	 sizeof(uicc_pin_disable_resp),
+	 NULL,
+	 uicc_pin_disable_req,
+	 sizeof(uicc_pin_disable_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_reset_resp,
+	 sizeof(uicc_pin_reset_resp),
+	 uicc_pin1_ind_pin_required,
+	 uicc_pin_reset_req,
+	 sizeof(uicc_pin_reset_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_change_resp,
+	 sizeof(uicc_pin_change_resp),
+	 NULL,
+	 uicc_pin_change_req,
+	 sizeof(uicc_pin_change_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_query_resp,
+	 sizeof(uicc_pin_query_resp),
+	 NULL,
+	 uicc_pin_query_req,
+	 sizeof(uicc_pin_query_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_prompt_resp,
+	 sizeof(uicc_pin_prompt_resp),
+	 NULL,
+	 uicc_pin_prompt_req,
+	 sizeof(uicc_pin_prompt_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_SIMLOCK_REQ,
+	 uicc_simlock_query_resp,
+	 sizeof(uicc_simlock_query_resp),
+	 NULL,
+	 uicc_simlock_query_req,
+	 sizeof(uicc_simlock_query_req) / 2}
+	,
+
+	/*CALL messages */
+	{
+	 PN_MODEM_CALL, CALL_MODEM_STATUS_REQ,
+	 call_modem_status_resp_msg,
+	 sizeof(call_modem_status_resp_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CREATE_REQ,
+	 call_modem_create_resp_msg2,
+	 sizeof(call_modem_create_resp_msg2),
+	 call_modem_status_ind_idle_msg}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_idle_msg,
+	 sizeof(call_modem_status_ind_idle_msg),
+	 call_modem_status_ind_create_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_create_msg2,
+	 sizeof(call_modem_status_ind_create_msg2),
+	 call_modem_status_ind_proceeding_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_proceeding_msg2,
+	 sizeof(call_modem_status_ind_proceeding_msg2),
+	 call_modem_status_ind_mo_alert_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_mo_alert_msg2,
+	 sizeof(call_modem_status_ind_mo_alert_msg2),
+	 call_modem_status_ind_active_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_active_msg2,
+	 sizeof(call_modem_status_ind_active_msg2),
+	 call_modem_control_ind_msg}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_RELEASE_REQ,
+	 call_modem_relese_resp_waiting_msg,
+	 sizeof(call_modem_relese_resp_waiting_msg),
+	 call_modem_status_ind_idle_msg,
+	 call_modem_relese_req_waiting_msg,
+	 sizeof(call_modem_relese_req_waiting_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_RELEASE_REQ,
+	 call_modem_release_resp_msg2,
+	 sizeof(call_modem_release_resp_msg2),
+	 call_modem_status_ind_mo_release_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_mo_release_msg2,
+	 sizeof(call_modem_status_ind_mo_release_msg2),
+	 call_modem_status_ind_idle_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_idle_msg2,
+	 sizeof(call_modem_status_ind_idle_msg2),
+	 call_modem_status_ind_mt_release_msg3}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_hold_msg,
+	 sizeof(call_modem_control_resp_hold_msg),
+	 call_modem_status_ind_hold_init_msg3,
+	 call_modem_control_req_hold_msg,
+	 sizeof(call_modem_control_req_hold_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_retr_msg,
+	 sizeof(call_modem_control_resp_retr_msg),
+	 call_modem_status_ind_active_msg3,
+	 call_modem_control_req_retr_msg,
+	 sizeof(call_modem_control_req_retr_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_swap_msg,
+	 sizeof(call_modem_control_resp_swap_msg),
+	 call_modem_status_ind_hold_msg2,
+	 call_modem_control_req_swap_msg,
+	 sizeof(call_modem_control_req_swap_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_transfer_msg,
+	 sizeof(call_modem_control_resp_transfer_msg),
+	 call_modem_control_ind_error_msg,
+	 call_modem_control_req_transfer_msg,
+	 sizeof(call_modem_control_req_transfer_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_conf_build_msg,
+	 sizeof(call_modem_control_resp_conf_build_msg),
+	 call_modem_status_ind_active_msg2,
+	 call_modem_control_req_conf_build_msg,
+	 sizeof(call_modem_control_req_conf_build_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_pri_chat_msg,
+	 sizeof(call_modem_control_resp_pri_chat_msg),
+	 call_modem_status_ind_hold_msg3,
+	 call_modem_control_req_pri_chat_msg,
+	 sizeof(call_modem_control_req_pri_chat_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_hold_init_msg3,
+	 sizeof(call_modem_status_ind_hold_init_msg3),
+	 call_modem_status_ind_hold_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_hold_msg3,
+	 sizeof(call_modem_status_ind_hold_msg3),
+	 call_modem_control_ind_msg}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_hold_msg2,
+	 sizeof(call_modem_status_ind_hold_msg2),
+	 call_modem_status_ind_active_msg3}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_STATUS_IND,
+	 call_modem_status_ind_coming_msg3,
+	 sizeof(call_modem_status_ind_coming_msg3),
+	 call_modem_status_ind_proceeding_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_proceeding_msg3,
+	 sizeof(call_modem_status_ind_proceeding_msg3),
+	 call_modem_status_ind_mt_alerting_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_mt_alerting_msg3,
+	 sizeof(call_modem_status_ind_mt_alerting_msg3),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_ANSWER_REQ,
+	 call_modem_answer_resp_msg3,
+	 sizeof(call_modem_answer_resp_msg3),
+	 call_modem_status_ind_answered_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_answered_msg3,
+	 sizeof(call_modem_status_ind_answered_msg3),
+	 call_modem_status_ind_active_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_active_msg3,
+	 sizeof(call_modem_status_ind_active_msg3),
+	 call_modem_control_ind_msg}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_mt_release_msg3,
+	 sizeof(call_modem_status_ind_mt_release_msg3),
+	 call_modem_status_ind_idle_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_idle_msg3,
+	 sizeof(call_modem_status_ind_idle_msg3),
+	 call_modem_mt_alert}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_mt_alert,
+	 sizeof(call_modem_mt_alert),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_DTMF_SEND_REQ,
+	 call_modem_dtmf_send_resp_msg2,
+	 sizeof(call_modem_dtmf_send_resp_msg2),
+	 call_modem_status_ind_hold_msg2multi}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_hold_msg2multi,
+	 sizeof(call_modem_status_ind_hold_msg2multi),
+	 call_modem_status_ind_hold_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_control_ind_msg,
+	 sizeof(call_modem_control_ind_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_control_ind_error_msg,
+	 sizeof(call_modem_control_ind_error_msg),
+	 call_modem_status_ind_waiting_msg}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_NOTIFICATION_IND,
+	 call_modem_notification_ind_test,
+	 sizeof(call_modem_notification_ind_test),
+	 call_modem_notification_ind_barring_inc}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_barring_inc,
+	 sizeof(call_modem_notification_ind_barring_inc),
+	 call_modem_notification_ind_barring_out}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_barring_out,
+	 sizeof(call_modem_notification_ind_barring_out),
+	 call_modem_notification_ind_forwarding_uncond}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_forwarding_uncond,
+	 sizeof(call_modem_notification_ind_forwarding_uncond),
+	 call_modem_notification_ind_forwarding_cond}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_forwarding_cond,
+	 sizeof(call_modem_notification_ind_forwarding_cond),
+	 call_modem_notification_ind_call_hold}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_call_hold,
+	 sizeof(call_modem_notification_ind_call_hold),
+	 call_modem_notification_ind_mpty}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_mpty,
+	 sizeof(call_modem_notification_ind_mpty),
+	 call_modem_notification_ind_cug_call}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_cug_call,
+	 sizeof(call_modem_notification_ind_cug_call),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_waiting_msg,
+	 sizeof(call_modem_status_ind_waiting_msg),
+	 NULL}
+	,
+
+	/* INFO messages */
+	{
+	 PN_MODEM_INFO, M_INFO_VERSION_READ_REQ,
+	 version_info_query_resp_ok,
+	 sizeof(version_info_query_resp_ok),
+	 NULL}
+	,
+
+	/*SMS messages */
+	/* Receive */
+	{
+	 PN_SMS, SMS_RECEIVED_MSG_IND,
+	 sms_received_incorrect_msg_ind,
+	 sizeof(sms_received_incorrect_msg_ind),
+	 sms_received_msg_ind}
+	,
+	{
+	 PN_SMS, -1,
+	 sms_received_msg_ind,
+	 sizeof(sms_received_msg_ind)
+	 }
+	,
+	/*
+	 * {PN_SMS, SMS_RECEIVE_MESSAGE_REQ,
+	 * sms_receive_message_resp_inactive,
+	 * sizeof(sms_receive_message_resp_inactive)},
+	 */
+	{
+	 PN_SMS, SMS_RECEIVE_MESSAGE_REQ,
+	 sms_receive_message_resp_active,
+	 sizeof(sms_receive_message_resp_active)
+	 }
+	,
+	{
+	 PN_SMS, SMS_RECEIVED_MSG_REPORT_REQ,
+	 sms_received_msg_report_resp,
+	 sizeof(sms_received_msg_report_resp)
+	 }
+	,
+	/* Send */
+	{
+	 PN_SMS, SMS_MESSAGE_SEND_REQ,
+	 sms_message_send_resp,
+	 sizeof(sms_message_send_resp)
+	 }
+	,
+	/* SETTINGS_UPDATE */
+	{
+	 PN_SMS, SMS_SETTINGS_UPDATE_REQ,
+	 sms_settings_update_resp_ok,
+	 sizeof(sms_settings_update_resp_ok)
+	 }
+	,
+	/* Route settings query */
+	{
+	 PN_SMS, SMS_SETTINGS_READ_REQ,
+	 sms_settings_read_resp_cs_only,
+	 sizeof(sms_settings_read_resp_cs_only)
+	 }
+	,
+
+	 /*CBS*/ {
+		  PN_SMS, SMS_CB_ROUTING_REQ,
+		  req_cbs_routing_resp,
+		  sizeof(req_cbs_routing_resp),
+		  sms_received_cbs_msg_ind,
+		  }
+	,
+	/*Receive cbs */
+	{
+	 PN_SMS, -1,
+	 sms_received_cbs_msg_ind,
+	 sizeof(sms_received_cbs_msg_ind),
+	 NULL}
+	,
+	/*Advanced voice calls */
+	/*Call forwarding */
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_forw,
+	 sizeof(call_forward_query_resp_forw),
+	 NULL,
+	 req_query_forw,
+	 sizeof(req_query_forw) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_A0,
+	 sizeof(call_forward_query_resp_A0),
+	 NULL,
+	 req_query_forw_A0,
+	 sizeof(req_query_forw_A0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_B0,
+	 sizeof(call_forward_query_resp_B0),
+	 NULL,
+	 req_query_forw_B0,
+	 sizeof(req_query_forw_B0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_C0,
+	 sizeof(call_forward_query_resp_C0),
+	 NULL,
+	 req_query_forw_C0,
+	 sizeof(req_query_forw_C0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_D0,
+	 sizeof(call_forward_query_resp_D0),
+	 NULL,
+	 req_query_forw_D0,
+	 sizeof(req_query_forw_D0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_erase,
+	 sizeof(call_forward_query_resp_erase),
+	 NULL,
+	 req_query_forw_erase,
+	 sizeof(req_query_forw_erase) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_erase_A0,
+	 sizeof(call_forward_query_resp_erase_A0),
+	 NULL,
+	 req_query_forw_erase_A0,
+	 sizeof(req_query_forw_erase_A0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_erase_B0,
+	 sizeof(call_forward_query_resp_erase_B0),
+	 NULL,
+	 req_query_forw_erase_B0,
+	 sizeof(req_query_forw_erase_B0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 forw_no_reply_set_resp,
+	 sizeof(forw_no_reply_set_resp),
+	 NULL,
+	 forw_no_reply_set_req,
+	 sizeof(forw_no_reply_set_req) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 forw_uncond_set_resp,
+	 sizeof(forw_uncond_set_resp),
+	 NULL,
+	 forw_uncond_set_req,
+	 sizeof(forw_uncond_set_req) / 2}
+	,
+	{
+	 PN_SS, SS_GSM_USSD_SEND_REQ,
+	 req_ussd_init_resp,
+	 sizeof(req_ussd_init_resp),
+	 req_ussd_init_ind,
+	 req_ussd_init,
+	 sizeof(req_ussd_init) / 2}
+	,
+	{
+	 PN_SS, -1,
+	 req_ussd_init_ind,
+	 sizeof(req_ussd_init_ind),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_SS, SS_GSM_USSD_SEND_REQ,
+	 req_ussd_cancel_resp,
+	 sizeof(req_ussd_cancel_resp),
+	 NULL,
+	 req_ussd_cancel,
+	 sizeof(req_ussd_cancel) / 2}
+	,
+
+	/*Call Barring */
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_AO,
+	 sizeof(call_barring_query_resp_AO),
+	 NULL,
+	 req_query_AO,
+	 sizeof(req_query_AO) / 2}
+	,
+	/* ISIMODEM2.5 messages */
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_AO,
+	 sizeof(call_barring_query_resp_AO),
+	 NULL,
+	 req_query_AO,
+	 sizeof(req_query_AO) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_OI,
+	 sizeof(call_barring_query_resp_OI),
+	 NULL, req_query_OI,
+	 sizeof(req_query_OI) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_OX,
+	 sizeof(call_barring_query_resp_OX),
+	 NULL,
+	 req_query_OX,
+	 sizeof(req_query_OX) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_AI,
+	 sizeof(call_barring_query_resp_AI),
+	 NULL,
+	 req_query_AI,
+	 sizeof(req_query_AI) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_IR,
+	 sizeof(call_barring_query_resp_IR),
+	 NULL,
+	 req_query_IR,
+	 sizeof(req_query_IR) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_disable_all_in_msg,
+	 sizeof(call_barring_disable_all_in_msg),
+	 NULL,
+	 req_disable_all_in,
+	 sizeof(req_disable_all_in) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_disable_all_out_msg,
+	 sizeof(call_barring_disable_all_out_msg),
+	 NULL,
+	 req_disable_all_out,
+	 sizeof(req_disable_all_out) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_enable_all_in_msg,
+	 sizeof(call_barring_enable_all_in_msg),
+	 NULL,
+	 req_enable_all_in,
+	 sizeof(req_enable_all_in) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_enable_all_out_msg,
+	 sizeof(call_barring_enable_all_out_msg),
+	 NULL,
+	 req_enable_all_out,
+	 sizeof(req_enable_all_out) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 req_change_cb_password_msg,
+	 sizeof(req_change_cb_password_msg),
+	 NULL,
+	 req_change_cb_password,
+	 sizeof(req_change_cb_password) / 2}
+	,
+	/*Call waiting */
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_waiting_query_resp,
+	 sizeof(call_waiting_query_resp),
+	 NULL, req_query_cw,
+	 sizeof(req_query_cw) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_waiting_query_resp_A0,
+	 sizeof(call_waiting_query_resp_A0),
+	 NULL,
+	 req_query_cw_A0,
+	 sizeof(req_query_cw_A0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_waiting_query_resp_B0,
+	 sizeof(call_waiting_query_resp_B0),
+	 NULL,
+	 req_query_cw_B0,
+	 sizeof(req_query_cw_B0) / 2}
+	,
+	 /*CLIP*/ {
+		   PN_SS, SS_SERVICE_REQ,
+		   clip_query_resp,
+		   sizeof(clip_query_resp),
+		   NULL,
+		   req_query_clip,
+		   sizeof(req_query_clip) / 2}
+	,
+	 /*CLIR*/ {
+		   PN_SS, SS_SERVICE_REQ,
+		   clir_query_resp,
+		   sizeof(clir_query_resp),
+		   NULL,
+		   req_query_clir,
+		   sizeof(req_query_clir) / 2}
+	,
+	 /*COLP*/ {
+		   PN_SS, SS_SERVICE_REQ,
+		   colp_query_resp,
+		   sizeof(colp_query_resp),
+		   NULL,
+		   req_query_colp,
+		   sizeof(req_query_colp) / 2}
+	,
+	 /*COLR*/ {
+		   PN_SS, SS_SERVICE_REQ,
+		   colr_query_resp,
+		   sizeof(colr_query_resp),
+		   NULL,
+		   req_query_colr,
+		   sizeof(req_query_colr) / 2}
+	,
+};
+
+struct isimodem25_response fakeresps_sms_fail[] = {
+	/*
+	 * How to add new simulation msgs:
+	 * 1) Phonet resource
+	 * 2) Request for which you want a response OR Indication you
+	 *       want to subscribe for
+	 * 3) Response or indication message
+	 * 4) Size of the response message
+	 * 5) Next message
+	 * 6) Long request (in case a more detailed match is required)
+	 * 7) Size of long request
+	 */
+	/*Changeable responses. Do not change the order */
+	{
+	 PN_UICC, UICC_APPLICATION_REQ,
+	 uicc_app_list_resp,
+	 sizeof(uicc_app_list_resp),
+	 NULL,
+	 uicc_app_list_req,
+	 sizeof(uicc_app_list_req) / 2}
+	,
+
+	/*Not changeable responses */
+	{
+	 PN_UICC, UICC_APPLICATION_REQ,
+	 uicc_app_activate_ok_resp,
+	 sizeof(uicc_app_activate_ok_resp),
+	 NULL,
+	 uicc_app_activate_req,
+	 sizeof(uicc_app_activate_req) / 2}
+	,
+	/*PN_MODEM_MCE messages */
+	{
+	 PN_MODEM_MCE, MCE_MODEM_STATE_IND,
+	 modem_state_normal_ind,
+	 sizeof(modem_state_normal_ind),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_MODEM_MCE, MCE_RF_STATE_REQ,
+	 rf_on_resp_ok,
+	 sizeof(rf_on_resp_ok),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_MODEM_MCE, MCE_RF_STATE_QUERY_REQ,
+	 rf_state_query_resp,
+	 sizeof(rf_state_query_resp),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_MODEM_MCE, MCE_MODEM_STATE_QUERY_REQ,
+	 modem_state_query_resp_ok,
+	 sizeof(modem_state_query_resp_ok),
+	 NULL,
+	 NULL,
+	 0}
+	,
+
+	/* Network registration messages */
+	{
+	 PN_MODEM_NETWORK, NET_SET_REQ,
+	 set_auto_resp_cb_msg,
+	 sizeof(set_auto_resp_cb_msg),
+	 NULL, reg_auto,
+	 sizeof(reg_auto) / 2}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_SET_REQ,
+	 set_manual_resp_cb_msg,
+	 sizeof(set_manual_resp_cb_msg),
+	 NULL,
+	 reg_manual,
+	 sizeof(reg_manual) / 2}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_MODEM_REG_STATUS_GET_REQ,
+	 reg_status_resp_cb_auto_msg,
+	 sizeof(reg_status_resp_cb_auto_msg),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_RSSI_GET_REQ,
+	 rssi_resp_cb_msg,
+	 sizeof(rssi_resp_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_MODEM_AVAILABLE_GET_REQ,
+	 available_resp_cb_msg,
+	 sizeof(available_resp_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_RSSI_IND,
+	 rssi_ind_cb_msg,
+	 sizeof(rssi_ind_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_MODEM_REG_STATUS_IND,
+	 reg_status_ind_cb_msg,
+	 sizeof(reg_status_ind_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_RAT_IND,
+	 rat_ind_cb_msg,
+	 sizeof(rat_ind_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_RAT_REQ,
+	 rat_resp,
+	 sizeof(rat_resp),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_CELL_INFO_GET_REQ,
+	 cell_info_resp_cb_msg,
+	 sizeof(cell_info_resp_cb_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_NITZ_NAME_IND,
+	 nitz_name_ind_msg,
+	 sizeof(nitz_name_ind_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_CS_STATE_IND,
+	 net_cs_state_ind_msg,
+	 sizeof(net_cs_state_ind_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_CS_STATE_REQ,
+	 net_cs_state_resp,
+	 sizeof(net_cs_state_resp),
+	 NULL}
+	,
+	{
+	 PN_MODEM_NETWORK, NET_CS_CONTROL_REQ,
+	 net_cs_control_resp,
+	 sizeof(net_cs_control_resp),
+	 NULL}
+	,
+
+	/* GSS messages */
+	{
+	 PN_GSS, GSS_CS_SERVICE_REQ,
+	 rat_query_resp_msg,
+	 sizeof(rat_query_resp_msg),
+	 NULL, rat_query_req,
+	 sizeof(rat_query_req) / 2}
+	,
+	{
+	 PN_GSS, GSS_CS_SERVICE_REQ,
+	 rat_set_any_resp_msg,
+	 sizeof(rat_set_any_resp_msg),
+	 NULL, rat_set_any_req,
+	 sizeof(rat_set_any_req) / 2}
+	,
+	{
+	 PN_GSS, GSS_CS_SERVICE_REQ,
+	 rat_set_umts_resp_msg,
+	 sizeof(rat_set_umts_resp_msg),
+	 NULL, rat_set_umts_req,
+	 sizeof(rat_set_umts_req) / 2}
+	,
+	{
+	 PN_GSS, GSS_CS_SERVICE_REQ,
+	 rat_set_gsm_resp_msg,
+	 sizeof(rat_set_gsm_resp_msg),
+	 NULL, rat_set_gsm_req,
+	 sizeof(rat_set_gsm_req) / 2}
+	,
+
+	/* GPDS/GPRS messages */
+	{
+	 PN_GPDS, GPDS_ATTACH_REQ,
+	 gpds_attach_resp_msg,
+	 sizeof(gpds_attach_resp_msg),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_STATUS_REQ,
+	 gpds_status_resp_attached_msg,
+	 sizeof(gpds_status_resp_attached_msg),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_DETACH_REQ,
+	 gpds_detach_resp_msg,
+	 sizeof(gpds_detach_resp_msg),
+	 gpds_detach_ind_msg1}
+	,
+	{
+	 PN_GPDS, GPDS_CONFIGURE_REQ,
+	 gpds_configure_resp_msg,
+	 sizeof(gpds_configure_resp_msg),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_ID_CREATE_REQ,
+	 gpds_context_id_create_resp_msg1,
+	 sizeof(gpds_context_id_create_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_LL_CONFIGURE_REQ,
+	 gpds_ll_configure_resp_msg1,
+	 sizeof(gpds_ll_configure_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_CONFIGURE_REQ,
+	 gpds_context_configure_resp_msg1,
+	 sizeof(gpds_context_configure_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_AUTH_REQ,
+	 gpds_context_auth_resp_msg1,
+	 sizeof(gpds_context_auth_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_ACTIVATE_REQ,
+	 gpds_context_activate_resp_msg1,
+	 sizeof(gpds_context_activate_resp_msg1),
+	 gpds_context_activate_ind_msg1}
+	,
+	{
+	 PN_GPDS, GPDS_CONTEXT_DEACTIVATE_REQ,
+	 gpds_context_deactivate_resp_msg1,
+	 sizeof(gpds_context_deactivate_resp_msg1),
+	 gpds_context_deactivate_ind_msg1}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_context_activate_ind_msg1,
+	 sizeof(gpds_context_activate_ind_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_context_deactivate_ind_msg1,
+	 sizeof(gpds_context_deactivate_ind_msg1),
+	 gpds_context_id_delete_ind_msg1}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_context_id_delete_ind_msg1,
+	 sizeof(gpds_context_id_delete_ind_msg1),
+	 NULL}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_detach_ind_msg1,
+	 sizeof(gpds_detach_ind_msg1),
+	 gpds_transfer_status_ind_not_avail_detach_msg}
+	,
+	{
+	 PN_GPDS, -1,
+	 gpds_transfer_status_ind_not_avail_detach_msg,
+	 sizeof(gpds_transfer_status_ind_not_avail_detach_msg),
+	 NULL}
+	,
+
+	/* PIPE/PEP messages */
+	{
+	 PN_PIPE, PNS_PEP_CONNECT_REQ,
+	 pns_pep_connect_resp_msg1,
+	 sizeof(pns_pep_connect_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_PIPE, PNS_PEP_DISCONNECT_REQ,
+	 pns_pep_disconnect_resp_msg1,
+	 sizeof(pns_pep_disconnect_resp_msg1),
+	 NULL}
+	,
+	{
+	 PN_PIPE, PNS_PEP_ENABLE_REQ,
+	 pns_pep_enable_resp_msg1,
+	 sizeof(pns_pep_enable_resp_msg1),
+	 NULL}
+	,
+
+	/*UICC messages */
+	/*SMS SCA query is here */
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 sms_sca_query_resp_fail,
+	 sizeof(sms_sca_query_resp_fail),
+	 NULL,
+	 sms_appl_cmd_linear_req,
+	 sizeof(sms_appl_cmd_linear_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 sms_sca_set_resp_fail,
+	 sizeof(sms_sca_set_resp_fail),
+	 NULL,
+	 sms_appl_cmd_linear_update_req,
+	 sizeof(sms_appl_cmd_linear_update_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_CARD_IND,
+	 uicc_card_ind_card_ready,
+	 sizeof(uicc_card_ind_card_ready),
+	 NULL}
+	,
+	{
+	 PN_UICC, UICC_PIN_IND,
+	 uicc_pin1_ind_pin_verified,
+	 sizeof(uicc_pin1_ind_pin_verified),
+	 uicc_pin2_ind_pin_verified}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin2_ind_pin_verified,
+	 sizeof(uicc_pin2_ind_pin_verified),
+	 uicc_pin_phnet_ind_pin_verified}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin_phnet_ind_pin_verified,
+	 sizeof(uicc_pin_phnet_ind_pin_verified),
+	 uicc_pin1_ind_puk_required}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin1_ind_puk_required,
+	 sizeof(uicc_pin1_ind_puk_required),
+	 uicc_pin2_ind_puk_required}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin2_ind_puk_required,
+	 sizeof(uicc_pin2_ind_puk_required),
+	 uicc_pin_phnet_ind_puk_required}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_pin_phnet_ind_puk_required,
+	 sizeof(uicc_pin_phnet_ind_puk_required),
+	 uicc_ind_startup_complete}
+	,
+	{
+	 PN_UICC, -1,
+	 uicc_ind_startup_complete,
+	 sizeof(uicc_ind_startup_complete),
+	 NULL}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFIMSI_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFIMSI_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFIMSI_req,
+	 sizeof(uicc_appl_cmd_file_info_EFIMSI_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFPNN_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFPNN_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFPNN_req,
+	 sizeof(uicc_appl_cmd_file_info_EFPNN_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFMSISDN_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFMSISDN_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFMSISDN_req,
+	 sizeof(uicc_appl_cmd_file_info_EFMSISDN_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFPNN_SIM_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFPNN_SIM_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFPNN_SIM_req,
+	 sizeof(uicc_appl_cmd_file_info_EFPNN_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFECC_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFECC_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFECC_req,
+	 sizeof(uicc_appl_cmd_file_info_EFECC_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFICI_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFICI_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFICI_req,
+	 sizeof(uicc_appl_cmd_file_info_EFICI_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFADN_SIM_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFADN_SIM_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFADN_SIM_req,
+	 sizeof(uicc_appl_cmd_file_info_EFADN_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFPBR_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFPBR_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFPBR_req,
+	 sizeof(uicc_appl_cmd_file_info_EFPBR_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFADN_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFADN_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFADN_req,
+	 sizeof(uicc_appl_cmd_file_info_EFADN_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFEXT1_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFEXT1_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFEXT1_req,
+	 sizeof(uicc_appl_cmd_file_info_EFEXT1_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFEMAIL_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFEMAIL_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFEMAIL_req,
+	 sizeof(uicc_appl_cmd_file_info_EFEMAIL_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFSNE_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFSNE_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFSNE_req,
+	 sizeof(uicc_appl_cmd_file_info_EFSNE_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_EFANR_resp,
+	 sizeof(uicc_appl_cmd_file_info_EFANR_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_EFANR_req,
+	 sizeof(uicc_appl_cmd_file_info_EFANR_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_general_transparent_SIM_resp,
+	 sizeof(uicc_appl_cmd_file_info_general_transparent_SIM_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_general_transparent_SIM_req,
+	 sizeof(uicc_appl_cmd_file_info_general_transparent_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_file_info_general_transparent_resp,
+	 sizeof(uicc_appl_cmd_file_info_general_transparent_resp),
+	 NULL,
+	 uicc_appl_cmd_file_info_general_transparent_req,
+	 sizeof(uicc_appl_cmd_file_info_general_transparent_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_transparent_response,
+	 sizeof(uicc_appl_cmd_transparent_response),
+	 NULL,
+	 uicc_appl_cmd_transparent_req,
+	 sizeof(uicc_appl_cmd_transparent_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFPBR1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFPBR1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFPBR1_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFPBR1_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFPBR2_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFPBR2_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFPBR2_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFPBR2_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN1_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN1_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN2_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN2_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN2_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN2_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN3_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN3_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN3_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN3_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN4_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN4_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN4_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN4_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN5_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN5_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN5_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN5_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADNx_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADNx_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADNx_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADNx_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN1_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN1_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADN2_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN2_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADN2_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADN2_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_ADNx_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADNx_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_ADNx_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_ADNx_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFMSISDN_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFMSISDN_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFMSISDN_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFMSISDN_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EXT1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EXT1_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT1_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EXT1_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT1_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EXT1_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT1_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EXT3_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT3_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EXT3_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT3_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EXT3_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT3_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EXT3_SIM_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EXT3_SIM_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFEMAIL_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFEMAIL_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFEMAIL_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFEMAIL_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFSNE_resp,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFSNE_resp),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFSNE_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFSNE_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_EFANR_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFANR_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_EFANR_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_EFANR_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_response,
+	 sizeof(uicc_appl_cmd_linear_fixed_response),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_cyclic_response,
+	 sizeof(uicc_appl_cmd_cyclic_response),
+	 NULL,
+	 uicc_appl_cmd_cyclic_req,
+	 sizeof(uicc_appl_cmd_cyclic_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_transparent_write_resp,
+	 sizeof(uicc_appl_cmd_transparent_write_resp),
+	 NULL,
+	 uicc_appl_cmd_transparent_write_req,
+	 sizeof(uicc_appl_cmd_transparent_write_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_linear_fixed_write_resp,
+	 sizeof(uicc_appl_cmd_linear_fixed_write_resp),
+	 NULL,
+	 uicc_appl_cmd_linear_fixed_write_req,
+	 sizeof(uicc_appl_cmd_linear_fixed_write_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_APPL_CMD_REQ,
+	 uicc_appl_cmd_cyclic_write_resp,
+	 sizeof(uicc_appl_cmd_cyclic_write_resp),
+	 NULL,
+	 uicc_appl_cmd_cyclic_write_req,
+	 sizeof(uicc_appl_cmd_cyclic_write_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_verify_resp,
+	 sizeof(uicc_pin_verify_resp),
+	 uicc_ind_startup_complete,
+	 uicc_pin_verify_req,
+	 sizeof(uicc_pin_verify_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_enable_resp,
+	 sizeof(uicc_pin_enable_resp),
+	 NULL,
+	 uicc_pin_enable_req,
+	 sizeof(uicc_pin_enable_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_disable_resp,
+	 sizeof(uicc_pin_disable_resp),
+	 NULL,
+	 uicc_pin_disable_req,
+	 sizeof(uicc_pin_disable_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_reset_resp,
+	 sizeof(uicc_pin_reset_resp),
+	 uicc_pin1_ind_pin_required,
+	 uicc_pin_reset_req,
+	 sizeof(uicc_pin_reset_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_change_resp,
+	 sizeof(uicc_pin_change_resp),
+	 NULL,
+	 uicc_pin_change_req,
+	 sizeof(uicc_pin_change_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_query_resp,
+	 sizeof(uicc_pin_query_resp),
+	 NULL,
+	 uicc_pin_query_req,
+	 sizeof(uicc_pin_query_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_PIN_REQ,
+	 uicc_pin_prompt_resp,
+	 sizeof(uicc_pin_prompt_resp),
+	 NULL,
+	 uicc_pin_prompt_req,
+	 sizeof(uicc_pin_prompt_req) / 2}
+	,
+	{
+	 PN_UICC, UICC_SIMLOCK_REQ,
+	 uicc_simlock_query_resp,
+	 sizeof(uicc_simlock_query_resp),
+	 NULL,
+	 uicc_simlock_query_req,
+	 sizeof(uicc_simlock_query_req) / 2}
+	,
+
+	/*CALL messages */
+	{
+	 PN_MODEM_CALL, CALL_MODEM_STATUS_REQ,
+	 call_modem_status_resp_msg,
+	 sizeof(call_modem_status_resp_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CREATE_REQ,
+	 call_modem_create_resp_msg2,
+	 sizeof(call_modem_create_resp_msg2),
+	 call_modem_status_ind_idle_msg}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_idle_msg,
+	 sizeof(call_modem_status_ind_idle_msg),
+	 call_modem_status_ind_create_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_create_msg2,
+	 sizeof(call_modem_status_ind_create_msg2),
+	 call_modem_status_ind_proceeding_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_proceeding_msg2,
+	 sizeof(call_modem_status_ind_proceeding_msg2),
+	 call_modem_status_ind_mo_alert_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_mo_alert_msg2,
+	 sizeof(call_modem_status_ind_mo_alert_msg2),
+	 call_modem_status_ind_active_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_active_msg2,
+	 sizeof(call_modem_status_ind_active_msg2),
+	 call_modem_control_ind_msg}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_RELEASE_REQ,
+	 call_modem_relese_resp_waiting_msg,
+	 sizeof(call_modem_relese_resp_waiting_msg),
+	 call_modem_status_ind_idle_msg,
+	 call_modem_relese_req_waiting_msg,
+	 sizeof(call_modem_relese_req_waiting_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_RELEASE_REQ,
+	 call_modem_release_resp_msg2,
+	 sizeof(call_modem_release_resp_msg2),
+	 call_modem_status_ind_mo_release_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_mo_release_msg2,
+	 sizeof(call_modem_status_ind_mo_release_msg2),
+	 call_modem_status_ind_idle_msg2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_idle_msg2,
+	 sizeof(call_modem_status_ind_idle_msg2),
+	 call_modem_status_ind_mt_release_msg3}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_hold_msg,
+	 sizeof(call_modem_control_resp_hold_msg),
+	 call_modem_status_ind_hold_init_msg3,
+	 call_modem_control_req_hold_msg,
+	 sizeof(call_modem_control_req_hold_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_retr_msg,
+	 sizeof(call_modem_control_resp_retr_msg),
+	 call_modem_status_ind_active_msg3,
+	 call_modem_control_req_retr_msg,
+	 sizeof(call_modem_control_req_retr_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_swap_msg,
+	 sizeof(call_modem_control_resp_swap_msg),
+	 call_modem_status_ind_hold_msg2,
+	 call_modem_control_req_swap_msg,
+	 sizeof(call_modem_control_req_swap_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_transfer_msg,
+	 sizeof(call_modem_control_resp_transfer_msg),
+	 call_modem_control_ind_error_msg,
+	 call_modem_control_req_transfer_msg,
+	 sizeof(call_modem_control_req_transfer_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_conf_build_msg,
+	 sizeof(call_modem_control_resp_conf_build_msg),
+	 call_modem_status_ind_active_msg2,
+	 call_modem_control_req_conf_build_msg,
+	 sizeof(call_modem_control_req_conf_build_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_CONTROL_REQ,
+	 call_modem_control_resp_pri_chat_msg,
+	 sizeof(call_modem_control_resp_pri_chat_msg),
+	 call_modem_status_ind_hold_msg3,
+	 call_modem_control_req_pri_chat_msg,
+	 sizeof(call_modem_control_req_pri_chat_msg) / 2}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_hold_init_msg3,
+	 sizeof(call_modem_status_ind_hold_init_msg3),
+	 call_modem_status_ind_hold_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_hold_msg3,
+	 sizeof(call_modem_status_ind_hold_msg3),
+	 call_modem_control_ind_msg}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_hold_msg2,
+	 sizeof(call_modem_status_ind_hold_msg2),
+	 call_modem_status_ind_active_msg3}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_STATUS_IND,
+	 call_modem_status_ind_coming_msg3,
+	 sizeof(call_modem_status_ind_coming_msg3),
+	 call_modem_status_ind_proceeding_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_proceeding_msg3,
+	 sizeof(call_modem_status_ind_proceeding_msg3),
+	 call_modem_status_ind_mt_alerting_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_mt_alerting_msg3,
+	 sizeof(call_modem_status_ind_mt_alerting_msg3),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_ANSWER_REQ,
+	 call_modem_answer_resp_msg3,
+	 sizeof(call_modem_answer_resp_msg3),
+	 call_modem_status_ind_answered_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_answered_msg3,
+	 sizeof(call_modem_status_ind_answered_msg3),
+	 call_modem_status_ind_active_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_active_msg3,
+	 sizeof(call_modem_status_ind_active_msg3),
+	 call_modem_control_ind_msg}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_mt_release_msg3,
+	 sizeof(call_modem_status_ind_mt_release_msg3),
+	 call_modem_status_ind_idle_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_idle_msg3,
+	 sizeof(call_modem_status_ind_idle_msg3),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_DTMF_SEND_REQ,
+	 call_modem_dtmf_send_resp_msg2,
+	 sizeof(call_modem_dtmf_send_resp_msg2),
+	 call_modem_status_ind_hold_msg2multi}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_hold_msg2multi,
+	 sizeof(call_modem_status_ind_hold_msg2multi),
+	 call_modem_status_ind_hold_msg3}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_control_ind_msg,
+	 sizeof(call_modem_control_ind_msg),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_control_ind_error_msg,
+	 sizeof(call_modem_control_ind_error_msg),
+	 call_modem_status_ind_waiting_msg}
+	,
+	{
+	 PN_MODEM_CALL, CALL_MODEM_NOTIFICATION_IND,
+	 call_modem_notification_ind_test,
+	 sizeof(call_modem_notification_ind_test),
+	 call_modem_notification_ind_barring_inc}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_barring_inc,
+	 sizeof(call_modem_notification_ind_barring_inc),
+	 call_modem_notification_ind_barring_out}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_barring_out,
+	 sizeof(call_modem_notification_ind_barring_out),
+	 call_modem_notification_ind_forwarding_uncond}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_forwarding_uncond,
+	 sizeof(call_modem_notification_ind_forwarding_uncond),
+	 call_modem_notification_ind_forwarding_cond}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_forwarding_cond,
+	 sizeof(call_modem_notification_ind_forwarding_cond),
+	 call_modem_notification_ind_call_hold}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_call_hold,
+	 sizeof(call_modem_notification_ind_call_hold),
+	 call_modem_notification_ind_mpty}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_mpty,
+	 sizeof(call_modem_notification_ind_mpty),
+	 call_modem_notification_ind_cug_call}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_notification_ind_cug_call,
+	 sizeof(call_modem_notification_ind_cug_call),
+	 NULL}
+	,
+	{
+	 PN_MODEM_CALL, -1,
+	 call_modem_status_ind_waiting_msg,
+	 sizeof(call_modem_status_ind_waiting_msg),
+	 NULL}
+	,
+
+	/* INFO messages */
+	{
+	 PN_MODEM_INFO, M_INFO_VERSION_READ_REQ,
+	 version_info_query_resp_ok,
+	 sizeof(version_info_query_resp_ok),
+	 NULL}
+	,
+
+	/*SMS messages */
+	/* Receive */
+	{
+	 PN_SMS, SMS_RECEIVED_MSG_IND,
+	 sms_received_incorrect_msg_ind,
+	 sizeof(sms_received_incorrect_msg_ind),
+	 sms_received_msg_ind}
+	,
+	{
+	 PN_SMS, -1,
+	 sms_received_msg_ind,
+	 sizeof(sms_received_msg_ind)
+	 }
+	,
+
+	{
+	 PN_SMS, SMS_RECEIVE_MESSAGE_REQ,
+	 sms_receive_message_resp_active,
+	 sizeof(sms_receive_message_resp_active)
+	 }
+	,
+	{
+	 PN_SMS, SMS_RECEIVED_MSG_REPORT_REQ,
+	 sms_received_msg_report_resp_fail,
+	 sizeof(sms_received_msg_report_resp_fail)
+	 }
+	,
+	/* Send */
+	{
+	 PN_SMS, SMS_MESSAGE_SEND_REQ,
+	 sms_message_send_resp_fail,
+	 sizeof(sms_message_send_resp_fail)
+	 }
+	,
+	/* SETTINGS_UPDATE */
+	{
+	 PN_SMS, SMS_SETTINGS_UPDATE_REQ,
+	 sms_settings_update_resp_false,
+	 sizeof(sms_settings_update_resp_false)
+	 }
+	,
+	/* Route settings query */
+	{
+	 PN_SMS, SMS_SETTINGS_READ_REQ,
+	 sms_settings_read_resp_cs_only,
+	 sizeof(sms_settings_read_resp_cs_only)
+	 }
+	,
+
+	 /*CBS*/ {
+		  PN_SMS, SMS_CB_ROUTING_REQ,
+		  req_cbs_routing_resp,
+		  sizeof(req_cbs_routing_resp),
+		  sms_received_cbs_msg_ind,
+		  }
+	,
+	/*Receive cbs */
+	{
+	 PN_SMS, -1,
+	 sms_received_cbs_msg_ind,
+	 sizeof(sms_received_cbs_msg_ind),
+	 NULL}
+	,
+
+	/*Advanced voice calls */
+	/*Call forwarding */
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_forw,
+	 sizeof(call_forward_query_resp_forw),
+	 NULL,
+	 req_query_forw,
+	 sizeof(req_query_forw) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_A0,
+	 sizeof(call_forward_query_resp_A0),
+	 NULL,
+	 req_query_forw_A0,
+	 sizeof(req_query_forw_A0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_B0,
+	 sizeof(call_forward_query_resp_B0),
+	 NULL,
+	 req_query_forw_B0,
+	 sizeof(req_query_forw_B0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_C0,
+	 sizeof(call_forward_query_resp_C0),
+	 NULL,
+	 req_query_forw_C0,
+	 sizeof(req_query_forw_C0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_D0,
+	 sizeof(call_forward_query_resp_D0),
+	 NULL,
+	 req_query_forw_D0,
+	 sizeof(req_query_forw_D0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_erase,
+	 sizeof(call_forward_query_resp_erase),
+	 NULL,
+	 req_query_forw_erase,
+	 sizeof(req_query_forw_erase) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_erase_A0,
+	 sizeof(call_forward_query_resp_erase_A0),
+	 NULL,
+	 req_query_forw_erase_A0,
+	 sizeof(req_query_forw_erase_A0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_forward_query_resp_erase_B0,
+	 sizeof(call_forward_query_resp_erase_B0),
+	 NULL,
+	 req_query_forw_erase_B0,
+	 sizeof(req_query_forw_erase_B0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 forw_no_reply_set_resp,
+	 sizeof(forw_no_reply_set_resp),
+	 NULL,
+	 forw_no_reply_set_req,
+	 sizeof(forw_no_reply_set_req) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 forw_uncond_set_resp,
+	 sizeof(forw_uncond_set_resp),
+	 NULL,
+	 forw_uncond_set_req,
+	 sizeof(forw_uncond_set_req) / 2}
+	,
+	{
+	 PN_SS, SS_GSM_USSD_SEND_REQ,
+	 req_ussd_init_resp,
+	 sizeof(req_ussd_init_resp),
+	 req_ussd_init_ind,
+	 req_ussd_init,
+	 sizeof(req_ussd_init) / 2}
+	,
+	{
+	 PN_SS, -1,
+	 req_ussd_init_ind,
+	 sizeof(req_ussd_init_ind),
+	 NULL,
+	 NULL,
+	 0}
+	,
+	{
+	 PN_SS, SS_GSM_USSD_SEND_REQ,
+	 req_ussd_cancel_resp,
+	 sizeof(req_ussd_cancel_resp),
+	 NULL,
+	 req_ussd_cancel,
+	 sizeof(req_ussd_cancel) / 2}
+	,
+
+	/*Call Barring */
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_AO,
+	 sizeof(call_barring_query_resp_AO),
+	 NULL,
+	 req_query_AO,
+	 sizeof(req_query_AO) / 2}
+	,
+	/* ISIMODEM2.5 messages */
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_AO,
+	 sizeof(call_barring_query_resp_AO),
+	 NULL,
+	 req_query_AO,
+	 sizeof(req_query_AO) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_OI,
+	 sizeof(call_barring_query_resp_OI),
+	 NULL, req_query_OI,
+	 sizeof(req_query_OI) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_OX,
+	 sizeof(call_barring_query_resp_OX),
+	 NULL,
+	 req_query_OX,
+	 sizeof(req_query_OX) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_AI,
+	 sizeof(call_barring_query_resp_AI),
+	 NULL,
+	 req_query_AI,
+	 sizeof(req_query_AI) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_query_resp_IR,
+	 sizeof(call_barring_query_resp_IR),
+	 NULL,
+	 req_query_IR,
+	 sizeof(req_query_IR) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_disable_all_in_msg,
+	 sizeof(call_barring_disable_all_in_msg),
+	 NULL,
+	 req_disable_all_in,
+	 sizeof(req_disable_all_in) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_disable_all_out_msg,
+	 sizeof(call_barring_disable_all_out_msg),
+	 NULL,
+	 req_disable_all_out,
+	 sizeof(req_disable_all_out) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_enable_all_in_msg,
+	 sizeof(call_barring_enable_all_in_msg),
+	 NULL,
+	 req_enable_all_in,
+	 sizeof(req_enable_all_in) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_barring_enable_all_out_msg,
+	 sizeof(call_barring_enable_all_out_msg),
+	 NULL,
+	 req_enable_all_out,
+	 sizeof(req_enable_all_out) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 req_change_cb_password_msg,
+	 sizeof(req_change_cb_password_msg),
+	 NULL,
+	 req_change_cb_password,
+	 sizeof(req_change_cb_password) / 2}
+	,
+	/*Call waiting */
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_waiting_query_resp,
+	 sizeof(call_waiting_query_resp),
+	 NULL, req_query_cw,
+	 sizeof(req_query_cw) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_waiting_query_resp_A0,
+	 sizeof(call_waiting_query_resp_A0),
+	 NULL,
+	 req_query_cw_A0,
+	 sizeof(req_query_cw_A0) / 2}
+	,
+	{
+	 PN_SS, SS_SERVICE_REQ,
+	 call_waiting_query_resp_B0,
+	 sizeof(call_waiting_query_resp_B0),
+	 NULL,
+	 req_query_cw_B0,
+	 sizeof(req_query_cw_B0) / 2}
+	,
+	 /*CLIP*/ {
+		   PN_SS, SS_SERVICE_REQ,
+		   clip_query_resp,
+		   sizeof(clip_query_resp),
+		   NULL,
+		   req_query_clip,
+		   sizeof(req_query_clip) / 2}
+	,
+	 /*CLIR*/ {
+		   PN_SS, SS_SERVICE_REQ,
+		   clir_query_resp,
+		   sizeof(clir_query_resp),
+		   NULL,
+		   req_query_clir,
+		   sizeof(req_query_clir) / 2}
+	,
+	 /*COLP*/ {
+		   PN_SS, SS_SERVICE_REQ,
+		   colp_query_resp,
+		   sizeof(colp_query_resp),
+		   NULL,
+		   req_query_colp,
+		   sizeof(req_query_colp) / 2}
+	,
+	 /*COLR*/ {
+		   PN_SS, SS_SERVICE_REQ,
+		   colr_query_resp,
+		   sizeof(colr_query_resp),
+		   NULL,
+		   req_query_colr,
+		   sizeof(req_query_colr) / 2}
+	,
+};
+
+static void ChangeResponses()
+{
+	fakeresps[0].response = uicc_app_list_fail_resp;
+	fakeresps[0].len = sizeof(uicc_app_list_fail_resp);
+}
diff --git a/drivers/isimodem2.5/sms.c b/drivers/isimodem2.5/sms.c
new file mode 100644
index 0000000..e9c2a79
--- /dev/null
+++ b/drivers/isimodem2.5/sms.c
@@ -0,0 +1,869 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/sms.h>
+
+#include <glib.h>
+
+#include "debug.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "sms.h"
+#include "smsutil.h"
+#include "timeout.h"
+#include "uicc_interface.h"
+
+struct sms_data {
+	GIsiClient *client;
+};
+
+struct sms_sca_data {
+	struct ofono_phone_number sca;
+};
+struct sms_sca_data *new_sca;
+
+int alpha_identifier = -1;
+int mf_path = 0x3F00;
+int df_path = 0x7F10;
+int df_len = 4;
+const unsigned char SMS_STATUS_REPORT = 0x02;
+GIsiClient *pn_sms_client;
+
+static void isi_sca_set(struct ofono_sms *sms,
+			const struct ofono_phone_number *sca,
+			ofono_sms_sca_set_cb_t cb, void *user_data);
+
+static gboolean handle_failure(ofono_sms_sca_query_cb_t cb,
+					struct isi_cb_data *cbd)
+{
+	if (!new_sca)
+		CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+	else
+		CALLBACK_WITH_FAILURE(cb, cbd->data, NULL);
+
+	g_free(cbd);
+	g_free(new_sca);
+	new_sca = NULL;
+	return TRUE;
+}
+
+static gboolean isi_sca_query_cb(GIsiClient *client, const void *restrict data,
+							size_t len,
+							uint16_t object,
+							void *opaque)
+{
+	const uint8_t *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sms_sca_query_cb_t cb = cbd->cb;
+	struct ofono_phone_number sca;
+	const uint8_t *bcd;
+	uint8_t bcd_len;
+
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return handle_failure(cb, cbd);
+	}
+
+	if (msg[0] != UICC_APPL_CMD_RESP
+			|| msg[1] != UICC_APPL_READ_LINEAR_FIXED) {
+		return FALSE;
+	}
+
+	if ((msg[2] != UICC_STATUS_OK) || (msg[6] == 0))
+		return handle_failure(cb, cbd);
+	else {
+		GIsiSubBlockIter iter;
+		uint32_t data_len = 0;
+
+		g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[7]);
+
+		if (g_isi_sb_iter_get_id(&iter) == UICC_SB_FILE_DATA)
+			g_isi_sb_iter_get_dword(&iter, &data_len, 4);
+
+		if (data_len < 28)
+			return handle_failure(cb, cbd);
+
+		/*y is alphaidentifier see 3GPP TS 31.102*/
+		alpha_identifier = data_len - 28;
+
+		/*if TS‑Service Centre Address absent*/
+		if (msg[14 + alpha_identifier + 1] & 0x2)
+			return handle_failure(cb, cbd);
+
+		/*the beginning of TS-SCA */
+		bcd = msg + 14 + alpha_identifier + 1 + 12 + 1;
+		bcd_len = bcd[0];
+
+		if (bcd_len <= 1 || bcd_len > 12)
+			return handle_failure(cb, cbd);
+
+		extract_bcd_number(bcd + 2, bcd_len - 1, sca.number);
+		sca.type = bcd[1];
+
+		if (new_sca) {
+			isi_sca_set(cbd->user, &new_sca->sca,
+					(ofono_sms_sca_set_cb_t)cbd->cb,
+								cbd->data);
+			g_free(cbd);
+			return TRUE;
+		}
+
+		CALLBACK_WITH_SUCCESS(cb, &sca, cbd->data);
+		g_free(cbd);
+		return TRUE;
+	}
+}
+static void isi_sca_query(struct ofono_sms *sms, ofono_sms_sca_query_cb_t cb,
+				void *user_data)
+{
+	int8_t app_id = -1;
+	uint8_t client_id = 0;
+	int app_type = -1;
+	struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, user_data);
+	GIsiClient *uicc_client = read_pn_uicc_client();
+
+	DBG("");
+	app_id = get_app_id();
+	app_type = get_app_type() ;
+	client_id = get_client_id();
+
+	if ((app_id == -1) || !client_id || !uicc_client || !cbd) {
+		if (!new_sca)
+			CALLBACK_WITH_FAILURE(cb, NULL, user_data);
+		else
+			CALLBACK_WITH_FAILURE(cb, user_data, NULL);
+
+		g_free(cbd);
+		g_free(new_sca);
+		new_sca = NULL;
+		return;
+	}
+
+	DBG("app_id: %04X", app_id);
+	DBG("client_id: %04X", client_id);
+
+	if (app_type == UICC_APPL_TYPE_UICC_USIM)
+		df_path = 0x7FFF;
+	else
+		df_path = 0x7F10;
+
+	if (cbd) {
+		uint8_t msg[] = {
+			UICC_APPL_CMD_REQ,
+			UICC_APPL_READ_LINEAR_FIXED,
+			app_id,
+			UICC_SESSION_ID_NOT_USED,
+			0, 0, /*fillers*/
+			3, /*nro of sub blocks*/
+
+			UICC_SB_CLIENT >> 8, /*1st subblock*/
+			UICC_SB_CLIENT & 0xFF,
+			0,/*subblock length*/
+			8,/*subblock length*/
+			0, 0, 0,/*fillers*/
+			client_id,
+
+			UICC_SB_APPL_PATH >> 8,/*2nd subblock*/
+			UICC_SB_APPL_PATH & 0xFF,
+			0,/*subblock length*/
+			16,/*subblock length*/
+			0x6F42 >> 8,/*Elementary file ID for EFsmsp*/
+			0x6F42 & 0xFF,
+			UICC_SFI_NOT_PRESENT,
+			0,/*filler*/
+			df_len,/*Path length*/
+			0,/*filler*/
+			mf_path >> 8,/*DF Path MF*/
+			mf_path & 0xFF,
+			df_path >> 8,/*DF Path DFtelecom*/
+			df_path & 0xFF,
+			0, 0,/*fillers 0-3*/
+			UICC_SB_LINEAR_FIXED >> 8,/*3rd subblock*/
+			UICC_SB_LINEAR_FIXED & 0xFF,
+			0,/*subblock length*/
+			8,/*subblock length*/
+			1,/*The record in the file*/
+			0,/*offset 0 == beginning of the record*/
+			0,/*data amount 0 == until end of record*/
+			0,/*filler*/
+		};
+
+		if (g_isi_request_make(uicc_client, msg, sizeof(msg),
+				SIM_TIMEOUT, isi_sca_query_cb, cbd))
+			return;
+	}
+
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+	/* No need to free cbd */
+}
+static gboolean sca_set_resp_cb(GIsiClient *client,
+				const void *restrict data, size_t len,
+				uint16_t object, void *opaque)
+{
+	const uint8_t *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sms_sca_set_cb_t cb = cbd->cb;
+
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+		return TRUE;
+	}
+
+	if (msg[0] != UICC_APPL_CMD_RESP
+			|| msg[1] != UICC_APPL_UPDATE_LINEAR_FIXED) {
+		return FALSE;
+	}
+
+	if (msg[2] != UICC_STATUS_OK) {
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(cbd);
+		return TRUE;
+	}
+
+	if (new_sca) {
+		g_free(new_sca);
+		new_sca = NULL;
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	g_free(cbd);
+	return TRUE;
+}
+static void isi_sca_set(struct ofono_sms *sms,
+			const struct ofono_phone_number *sca,
+			ofono_sms_sca_set_cb_t cb, void *user_data)
+{
+	DBG("");
+	DBG("original sca: %04X", (unsigned int) strlen(sca->number));
+
+	if (alpha_identifier < 0) {
+		new_sca = g_try_new(struct sms_sca_data,
+					1);
+		if (!new_sca) {
+			CALLBACK_WITH_FAILURE(cb, user_data);
+			return;
+		}
+
+		strncpy(new_sca->sca.number,
+			sca->number, OFONO_MAX_PHONE_NUMBER_LENGTH);
+		new_sca->sca.number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
+
+		new_sca->sca.type = sca->type;
+		isi_sca_query(sms, (ofono_sms_sca_query_cb_t)cb, user_data);
+	} else {
+		struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, user_data);
+		GIsiClient *uicc_client = read_pn_uicc_client();
+		int8_t app_id = get_app_id();
+		int8_t client_id = get_client_id();
+		int the_length_of_sca = 1 + (strlen(sca->number) + 1) / 2;
+		size_t sb_file_data_legth = 2 + 2 + 4 + 12;
+		int fillers = sb_file_data_legth -
+				(2 + 2 + 4 + the_length_of_sca + 1);
+
+		uint8_t bcd[12];
+
+		DBG("app_id: %04X", app_id);
+		DBG("client_id: %04X", client_id);
+		DBG("sca_length: %04X", the_length_of_sca);
+
+		encode_bcd_number(sca->number, bcd + 2);
+
+		bcd[0] = 1 + (strlen(sca->number) + 1) / 2;
+		bcd[1] = sca->type;
+
+		if (fillers) {
+			int i;
+			for (i = 0; i < fillers; i++)
+				bcd[the_length_of_sca + 1 + i] = 0xFF;
+		}
+
+		DBG("sca_length: %04X", the_length_of_sca);
+		DBG("nro fillers: %04X", fillers);
+		DBG("file_data_length: %04X", the_length_of_sca + 1);
+		DBG("bcd: %04X", (unsigned int) sizeof(bcd));
+
+		if ((app_id == -1) || (client_id == -1) || !uicc_client
+							|| !cbd) {
+
+			CALLBACK_WITH_FAILURE(cb, user_data);
+			g_free(cbd);
+			return;
+		} else {
+
+			uint8_t msg[] = {
+				UICC_APPL_CMD_REQ,
+				UICC_APPL_UPDATE_LINEAR_FIXED,
+				app_id,
+				UICC_SESSION_ID_NOT_USED,
+				0, 0, /*fillers*/
+				4, /*nro of sub blocks*/
+		/*1*/
+				UICC_SB_CLIENT >> 8, /*1st subblock*/
+				UICC_SB_CLIENT & 0xFF,
+				0,/*subblock length*/
+				8,/*subblock length*/
+				0, 0, 0,/*fillers*/
+				client_id,
+		/*2*/
+				UICC_SB_LINEAR_FIXED >> 8,/*3rd subblock*/
+				UICC_SB_LINEAR_FIXED & 0xFF,
+				0,/*subblock length*/
+				8,/*subblock length*/
+				1,/*The record in the file*/
+				alpha_identifier + 14-1,/* offset 0 == beginning
+							 * of the record
+							 */
+				the_length_of_sca + 1, /* data amount 0
+							* == until end of
+							* record
+							*/
+				0,/*filler*/
+		/*3*/
+				UICC_SB_APPL_PATH >> 8,/*2nd subblock*/
+				UICC_SB_APPL_PATH & 0xFF,
+				0,/*subblock length*/
+				16,/*subblock length*/
+				0x6F42 >> 8,/*Elementary file ID for EFsmsp*/
+				0x6F42 & 0xFF,
+				UICC_SFI_NOT_PRESENT,
+				0,/*filler*/
+				df_len,/*Path length*/
+				0,/*filler*/
+				mf_path >> 8,/*DF Path MF*/
+				mf_path & 0xFF,
+				df_path >> 8,/*DF Path DFtelecom*/
+				df_path & 0xFF,
+				0, 0,/*fillers 0-3*/
+		/*4*/
+				UICC_SB_FILE_DATA >> 8,
+				UICC_SB_FILE_DATA & 0xFF,
+				sb_file_data_legth >> 8,
+				sb_file_data_legth & 0xFF,
+				(the_length_of_sca + 1) >> 24,
+				(the_length_of_sca + 1) >> 16,
+				(the_length_of_sca + 1) >> 8,
+				(the_length_of_sca + 1) & 0xFF,
+			};
+
+			struct iovec iov[2] = {
+				{ msg, sizeof(msg) },
+				{ bcd, sizeof(bcd) },
+			};
+
+			if (g_isi_request_vmake(uicc_client,
+					iov, 2, SIM_TIMEOUT,
+					sca_set_resp_cb, cbd))
+				return;
+		}
+	}
+}
+static gboolean isi_submit_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sms_submit_cb_t cb = cbd->cb;
+	int msg_reference = -1;
+	DBG("");
+
+	if (!msg)
+		goto error;
+
+	if (msg[0] != SMS_MESSAGE_SEND_RESP)
+		return FALSE;
+
+	if (msg[1] == SMS_CAUSE_TYPE_COMMON) {
+		if (msg[2] != SMS_OK)
+			goto error;
+		else
+			msg_reference = msg[3];
+	}
+
+	if (msg_reference == -1)
+		goto error;
+
+	CALLBACK_WITH_SUCCESS(cb, msg_reference, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_submit(struct ofono_sms *sms, 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 isi_cb_data *cbd = isi_cb_data_new(sms, cb, user_data);
+	uint8_t sca_len = pdu_len - tpdu_len;
+	uint8_t *tpdu = pdu + sca_len;
+	uint8_t msg[] = {
+		SMS_MESSAGE_SEND_REQ,
+		mms,			/* More messages to send*/
+		SMS_ROUTE_DEFAULT,
+		FALSE,			/* Repeated message*/
+		0, 0,			/* fillers*/
+		2,			/* nro of subblocks*/
+		SMS_SB_TPDU >> 8,	/* first subblock*/
+		SMS_SB_TPDU & 0xFF,
+		(tpdu_len + 6) >> 8,
+		(tpdu_len + 6) & 0xFF,
+		tpdu_len,
+		0x00,
+		/* databytes come here */
+	};
+	uint8_t parameters[] = {
+		SMS_SB_SMS_PARAMETERS >> 8,
+		SMS_SB_SMS_PARAMETERS & 0xFF,
+		8 >> 8,			/* subblock length*/
+		8 & 0xFF,
+		/*
+		 * location. We might have to fetch this by
+		 * SMS_SETTINGS_READ_REQ
+		 */
+		1, /*SMS_DEFAULT_PARAMETER_LOCATION = 0 else range 1-255*/
+		0x02,/*SMS_PI_SERVICE_CENTRE_ADDRESS*/
+		0, 0,
+	};
+	struct iovec iov[3] = {
+		{ msg, sizeof(msg) },
+		{ tpdu, tpdu_len },
+		{ parameters, sizeof(parameters) },
+	};
+
+	DBG("");
+
+	if (cbd && (g_isi_request_vmake(sd->client, iov, 3, SMS_TIMEOUT,
+					isi_submit_cb, cbd)))
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, -1, user_data);
+	g_free(cbd);
+}
+
+static gboolean report_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const uint8_t *msg = data;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return FALSE;
+	}
+
+	if (len < 3 || msg[0] != SMS_RECEIVED_MSG_REPORT_RESP)
+		return FALSE;
+
+	DBG("Report resp cause=0x%"PRIx8, msg[1]);
+	return TRUE;
+}
+
+static gboolean send_received_deliver_report(GIsiClient *client,
+						gboolean success)
+{
+	uint8_t cause_type = !success ? SMS_CAUSE_TYPE_EXT : 0;
+	uint8_t cause = !success ? SMS_EXT_ERR_MEMORY_CAPACITY_EXC : 0;
+	uint8_t msg[] = {
+		SMS_RECEIVED_MSG_REPORT_REQ,
+		cause_type,
+		cause,
+		0, 0, 0,	/* Filler */
+		0,		/* nro of subblocks*/
+	};
+
+	DBG("");
+	return g_isi_request_make(client, msg, sizeof(msg), SMS_TIMEOUT,
+					report_resp_cb, NULL) != NULL;
+}
+static void received_msg_ind_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const uint8_t *msg = data;
+	struct ofono_sms *sms = opaque;
+	GIsiSubBlockIter iter;
+	uint8_t *sca = NULL;
+	uint8_t sca_len = 0;
+	uint8_t *tpdu = NULL;
+	uint8_t tpdu_len = 0;
+	unsigned char pdu[176];
+	unsigned char type;
+	/*subblocks SMS_SB_ADDRESS and SMS_SB_TPDU*/
+	DBG("len = %d", (int) len);
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		return;
+	}
+
+	if (len < 3 || msg[0] != SMS_RECEIVED_MSG_IND)
+		return;
+
+	for (g_isi_sb_iter_init_full(&iter, msg, len, 3, TRUE, msg[2]);
+			g_isi_sb_iter_is_valid(&iter);
+			g_isi_sb_iter_next(&iter)) {
+		switch (g_isi_sb_iter_get_id(&iter)) {
+			uint8_t type;
+			void *data;
+			uint8_t data_len;
+		case SMS_SB_ADDRESS:
+
+			if (!g_isi_sb_iter_get_byte(&iter, &type, 4)
+				|| !g_isi_sb_iter_get_byte(&iter, &data_len, 5)
+				|| !g_isi_sb_iter_get_data(&iter, &data, 6)
+				|| type != SMS_SMSC_ADDRESS)
+				break;
+
+			sca = data;
+			sca_len = data_len;
+			break;
+		case SMS_SB_TPDU:
+
+			if (!g_isi_sb_iter_get_byte(&iter, &data_len, 4)
+				|| !g_isi_sb_iter_get_data(&iter, &data, 6))
+				break;
+
+			tpdu = data;
+			tpdu_len = data_len;
+			break;
+		}
+	}
+
+	if (!tpdu || !sca || tpdu_len + sca_len > sizeof(pdu))
+		return;
+
+	memmove(pdu, sca, sca_len);
+	memmove(pdu + sca_len, tpdu, tpdu_len);
+	/* 23.040 9.2.3.1 */
+	type = tpdu[0] & 0x03;
+	DBG("Type of TPDU=%d", type);
+
+	if (type == SMS_STATUS_REPORT) {
+		ofono_sms_status_notify(sms,
+					pdu, tpdu_len + sca_len, tpdu_len);
+	} else {
+		ofono_sms_deliver_notify(sms,
+					 pdu, tpdu_len + sca_len, tpdu_len);
+	}
+
+	send_received_deliver_report(client, TRUE);
+}
+
+static gboolean routing_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_sms *sms = opaque;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if (len < 3 || msg[0] != SMS_RECEIVE_MESSAGE_RESP)
+		goto error;
+
+	if (msg[1] != SMS_RECEPTION_ACTIVE) {
+		DBG("Request failed: 0x%02X", msg[1]);
+		goto error;
+	}
+
+	/*for received indications*/
+	g_isi_subscribe(client, SMS_RECEIVED_MSG_IND, received_msg_ind_cb, sms);
+	new_sca = NULL;
+	alpha_identifier = -1;
+	ofono_sms_register(sms);
+	return TRUE;
+error:
+	DBG("Unable to bootstrap SMS routing.");
+	return FALSE;
+}
+
+static int isi_sms_probe(struct ofono_sms *sms, unsigned int vendor,
+				void *user)
+{
+	GIsiModem *idx = user;
+	struct sms_data *data = g_try_new0(struct sms_data, 1);
+	const unsigned char msg[] = {
+		SMS_RECEIVE_MESSAGE_REQ,
+		SMS_RECEPTION_ACTIVATE,
+		0,
+	};
+
+	DBG("");
+
+	if (!data)
+		return -ENOMEM;
+
+	data->client = get_pn_sms_client(idx, PN_SMS);
+
+	if (!data->client)
+		return -ENOMEM;
+
+	ofono_sms_set_data(sms, data);
+
+	if (!g_isi_request_make(data->client, msg, sizeof(msg),
+				SMS_TIMEOUT, routing_resp_cb, sms))
+		DBG("Failed to set SMS routing.");
+
+	return 0;
+}
+
+static void isi_sms_remove(struct ofono_sms *sms)
+{
+	struct sms_data *data = ofono_sms_get_data(sms);
+	const unsigned char msg[] = {
+		SMS_RECEIVE_MESSAGE_REQ,
+		SMS_RECEPTION_DEACTIVATE,
+		0x0,
+	};
+
+	DBG("");
+
+	if (!data)
+		return;
+
+	if (is_pn_sms_client()) {
+		g_isi_request_make(data->client, msg, sizeof(msg),
+					SMS_TIMEOUT, NULL, NULL);
+		pn_sms_client_destroy(data->client);
+	}
+
+	if (new_sca) {
+		g_free(new_sca);
+		new_sca = NULL;
+	}
+
+	g_free(data);
+}
+
+static int bearer_query_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sms_bearer_query_cb_t cb = cbd->cb;
+	int bearer = 0;
+
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if ((len < 3 || msg[0] != SMS_SETTINGS_READ_RESP) || (msg[1] != SMS_OK))
+		goto error;
+
+	/* check what bearer type was set */
+	if (msg[7] == 0x00 && msg[8] == 0x01)
+		bearer = 0;
+	else if (msg[7] == 0x01 && msg[8] == 0x00)
+		bearer = 1;
+	else if (msg[7] == 0x02 && msg[8] == 0x01)
+		bearer = 2;
+	else if (msg[7] == 0x01 && msg[8] == 0x02)
+		bearer = 3;
+
+	DBG("bearer = %d", bearer);
+	CALLBACK_WITH_SUCCESS(cb, bearer, cbd->data);
+	goto out;
+error:
+	DBG("Error");
+	CALLBACK_WITH_FAILURE(cb, bearer, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_bearer_query(struct ofono_sms *sms,
+				ofono_sms_bearer_query_cb_t cb, void *data)
+{
+	struct sms_data *sd = ofono_sms_get_data(sms);
+	struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
+	unsigned char msg[] = {
+		SMS_SETTINGS_READ_REQ,
+		SMS_SETTING_TYPE_ROUTE,
+		0
+	};
+	DBG("");
+
+	if (cbd && g_isi_request_make(sd->client, msg, sizeof(msg),
+					SMS_TIMEOUT, bearer_query_resp_cb, cbd))
+		return;
+
+	CALLBACK_WITH_FAILURE(cb, 0, data);
+	g_free(cbd);
+}
+
+
+static gboolean set_resp_cb(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sms_bearer_set_cb_t cb = cbd->cb;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if (len < 3 || msg[0] != SMS_SETTINGS_UPDATE_RESP)
+		return FALSE;
+
+	if (msg[2] != SMS_OK)
+		goto error;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	goto out;
+error:
+	DBG(" Error");
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_bearer_set(struct ofono_sms *sms, int bearer,
+			   ofono_sms_bearer_set_cb_t cb, void *data)
+{
+	struct sms_data *sd = ofono_sms_get_data(sms);
+	struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
+	unsigned char bearer_type[2] = {SMS_ROUTE_NOT_AVAILABLE,
+					SMS_ROUTE_NOT_AVAILABLE
+	};
+
+	DBG("");
+	switch (bearer) {
+	case 0:
+		bearer_type[0] = SMS_ROUTE_NOT_AVAILABLE;
+		bearer_type[1] = SMS_ROUTE_PRIORITY_1;
+		break;
+	case 1:
+		bearer_type[0] = SMS_ROUTE_PRIORITY_1;
+		bearer_type[1] = SMS_ROUTE_NOT_AVAILABLE;
+		break;
+	case 2:
+		bearer_type[0] = SMS_ROUTE_PRIORITY_2;
+		bearer_type[1] = SMS_ROUTE_PRIORITY_1;
+		break;
+	case 3:
+		bearer_type[0] = SMS_ROUTE_PRIORITY_1;
+		bearer_type[1] = SMS_ROUTE_PRIORITY_2;
+		break;
+	}
+
+	if (cbd && sd) {
+		unsigned char msg[] = {
+			SMS_SETTINGS_UPDATE_REQ,
+			SMS_SETTING_TYPE_ROUTE,
+			1, /* one subblock */
+			SMS_SB_ROUTE_INFO >> 8,
+			SMS_SB_ROUTE_INFO & 0xFF,
+			8 >> 8,
+			8 & 0xFF,
+			bearer_type[0], /* cs priority */
+			bearer_type[1], /* ps priority */
+			0, 0
+		};
+
+		if (g_isi_request_make(sd->client, msg, sizeof(msg),
+				SMS_TIMEOUT, set_resp_cb, cbd))
+			return;
+	}
+
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+static struct ofono_sms_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_sms_probe,
+	.remove			= isi_sms_remove,
+	.sca_query		= isi_sca_query,
+	.sca_set		= isi_sca_set,
+	.submit			= isi_submit,
+	.bearer_query		= isi_bearer_query,
+	.bearer_set		= isi_bearer_set
+};
+
+void isi_sms_init()
+{
+	DBG("");
+	pn_sms_client = NULL;
+	ofono_sms_driver_register(&driver);
+}
+
+void isi_sms_exit()
+{
+	DBG("");
+	ofono_sms_driver_unregister(&driver);
+}
+
+GIsiClient *get_pn_sms_client(GIsiModem *modem, uint8_t resource)
+{
+	if (!pn_sms_client)
+		pn_sms_client = g_isi_client_create(modem, resource);
+
+	return pn_sms_client;
+}
+
+void pn_sms_client_destroy(GIsiClient *client)
+{
+	if (pn_sms_client) {
+		g_isi_client_destroy(client);
+		pn_sms_client = NULL;
+	}
+}
+
+gboolean is_pn_sms_client()
+{
+	return (pn_sms_client != NULL);
+}
diff --git a/drivers/isimodem2.5/sms.h b/drivers/isimodem2.5/sms.h
new file mode 100644
index 0000000..c58158c
--- /dev/null
+++ b/drivers/isimodem2.5/sms.h
@@ -0,0 +1,188 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_SMS_H
+#define __ISIMODEM25_SMS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SMS_DEFAULT_PARAMETER_LOCATION		0x00
+#define PN_SMS					0x02
+#define CBS_TIMEOUT				5
+
+enum sms_cause {
+	SMS_OK =				0x00,
+	SMS_ERR_PP_RESERVED =			0x04,
+	SMS_ERR_CS_INACTIVE =			0x11
+};
+enum sms_cause_type {
+	SMS_CAUSE_TYPE_COMMON =			0x00,
+	SMS_CAUSE_TYPE_EXT =			0x01
+};
+enum sms_ext_cause {
+	SMS_EXT_ERR_MEMORY_CAPACITY_EXC =	0x16
+};
+enum sms_message_id {
+	SMS_MESSAGE_CAPABILITY_REQ =		0x00,
+	SMS_MESSAGE_CAPABILITY_RESP =		0x01,
+	SMS_MESSAGE_SEND_REQ =			0x02,
+	SMS_MESSAGE_SEND_RESP =			0x03,
+	SMS_RECEIVED_MT_PP_IND =		0x04,
+	SMS_RECEIVED_MWI_PP_IND =		0x05,
+	SMS_PP_ROUTING_REQ =			0x06,
+	SMS_PP_ROUTING_RESP =			0x07,
+	SMS_PP_ROUTING_NTF =			0x08,
+	SMS_GSM_RECEIVED_PP_REPORT_REQ =	0x09,
+	SMS_GSM_RECEIVED_PP_REPORT_RESP =	0x0A,
+	SMS_GSM_CB_ROUTING_REQ =		0x0B,
+	SMS_GSM_CB_ROUTING_RESP =		0x0C,
+	SMS_GSM_CB_ROUTING_NTF =		0x0D,
+	SMS_GSM_TEMP_CB_ROUTING_REQ =		0x0E,
+	SMS_GSM_TEMP_CB_ROUTING_RESP =		0x0F,
+	SMS_GSM_TEMP_CB_ROUTING_NTF =		0x10,
+	SMS_GSM_CBCH_PRESENT_IND =		0x11,
+	SMS_PARAMETERS_UPDATE_REQ =		0x12,
+	SMS_PARAMETERS_UPDATE_RESP =		0x13,
+	SMS_PARAMETERS_READ_REQ =		0x14,
+	SMS_PARAMETERS_READ_RESP =		0x15,
+	SMS_PARAMETERS_CAPACITY_REQ =		0x16,
+	SMS_PARAMETERS_CAPACITY_RESP =		0x17,
+	SMS_GSM_SETTINGS_UPDATE_REQ =		0x18,
+	SMS_GSM_SETTINGS_UPDATE_RESP =		0x19,
+	SMS_GSM_SETTINGS_READ_REQ =		0x1A,
+	SMS_GSM_SETTINGS_READ_RESP =		0x1B,
+	SMS_GSM_MCN_SETTING_CHANGED_IND =	0x1C,
+	SMS_MEMORY_CAPACITY_EXC_IND =		0x1D,
+	SMS_STORAGE_STATUS_UPDATE_REQ =		0x1E,
+	SMS_STORAGE_STATUS_UPDATE_RESP =	0x1F,
+	SMS_MESSAGE_SEND_STATUS_IND =		0x22,
+	SMS_GSM_RESEND_CANCEL_REQ =		0x23,
+	SMS_GSM_RESEND_CANCEL_RESP =		0x24,
+	SMS_SM_CONTROL_ACTIVATE_REQ =		0x25,
+	SMS_SM_CONTROL_ACTIVATE_RESP =		0x26,
+	SMS_GSM_INDICATE_STORAGE_REQ =		0x2A,
+	SMS_GSM_INDICATE_STORAGE_RESP =		0x2B,
+	SMS_STATUS_IND =			0x2D,
+	SMS_STATUS_REQ =			0x2E,
+	SMS_STATUS_RESP =			0x2F,
+	SMS_SETTINGS_UPDATE_REQ =		0x30,
+	SMS_SETTINGS_UPDATE_RESP =		0x31,
+	SMS_SETTINGS_READ_REQ =			0x32,
+	SMS_SETTINGS_READ_RESP =		0x33,
+	SMS_CB_ROUTING_REQ =			0x34,
+	SMS_CB_ROUTING_RESP =			0x35,
+	SMS_CB_ROUTING_IND =			0x36,
+	SMS_CB_SIM_ROUTING_IND =		0x37,
+	SMS_RECEIVED_MSG_REPORT_REQ =		0x3B,
+	SMS_RECEIVED_MSG_REPORT_RESP =		0x3C,
+	SMS_RECEIVE_MESSAGE_REQ =		0x41,
+	SMS_RECEIVE_MESSAGE_RESP =		0x42,
+	SMS_RECEIVED_MSG_IND =			0x43,
+	SMS_RECEIVED_SIM_MSG_IND =		0x44,
+	SMS_RESOURCE_CONF_REQ =			0x45,
+	SMS_RESOURCE_CONF_RESP =		0x46,
+	SMS_RESOURCE_CONF_IND =			0x47,
+	SMS_RESOURCE_CLEAR_IND =		0x48,
+	SMS_RESOURCE_REQ =			0x49,
+	SMS_RESOURCE_RESP =			0x4A,
+	SMS_RESOURCE_IND =			0x4B,
+	SMS_MODEM_MEM_SETTINGS_UPDATE_REQ =	0x4C,
+	SMS_MODEM_MEM_SETTINGS_UPDATE_RESP =	0x4D,
+	SMS_MODEM_MEM_SETTINGS_IND =		0x4E,
+	SMS_MODEM_MEM_SETTINGS_READ_REQ =	0x4F,
+	SMS_MODEM_MEM_SETTINGS_READ_RESP =	0x50,
+	SMS_MODEM_MEM_DATA_READ_REQ =		0x53,
+	SMS_MODEM_MEM_DATA_READ_RESP =		0x54,
+	SMS_MODEM_MEM_RECORD_STATUS_READ_REQ =	0x55,
+	SMS_MODEM_MEM_RECORD_STATUS_READ_RESP =	0x56,
+	SMS_MODEM_MEM_RECORD_ERASE_REQ =	0x57,
+	SMS_MODEM_MEM_RECORD_ERASE_RESP =	0x58,
+	SMS_MODEM_MEM_RECORD_QUERY_REQ =	0x59,
+	SMS_MODEM_MEM_RECORD_QUERY_RESP =	0x5A,
+	SMS_MODEM_MEM_DATA_STORED_IND =		0x5B,
+};
+enum sms_reception_command {
+	SMS_RECEPTION_ACTIVATE =		0x01,
+	SMS_RECEPTION_DEACTIVATE =		0x02
+};
+enum sms_reception_status {
+	SMS_RECEPTION_ACTIVE =			0x01,
+	SMS_RECEPTION_INACTIVE =		0x02
+};
+enum sms_subblock_id {
+	SMS_SB_CB_MESSAGE =			0x000E,
+	SMS_SB_TPDU =				0x001C,
+	SMS_SB_ROUTE_INFO =			0x0023,
+	SMS_SB_CBS_SUBSCRIPTION =		0x002D,
+	SMS_SB_CAUSE =				0x0029,
+	SMS_SB_SMS_PARAMETERS =			0x0031,
+	SMS_SB_ADDRESS =			0x0082
+};
+enum sms_address_type {
+	SMS_SMSC_ADDRESS =			0x02
+};
+enum sms_route {
+	SMS_ROUTE_CS =				0x01,
+	SMS_ROUTE_DEFAULT =			0x04
+};
+enum sms_route_priority {
+	SMS_ROUTE_NOT_AVAILABLE =		0x00,
+	SMS_ROUTE_PRIORITY_1 =			0x01,
+	SMS_ROUTE_PRIORITY_2 =			0x02
+};
+enum sms_parameter_indicator {
+	SMS_PI_SERVICE_CENTRE_ADDRESS =		0x02
+};
+
+enum sms_setting_type {
+	SMS_SETTING_TYPE_ROUTE =		0x02
+};
+enum sms_server_status {
+	SMS_SERVER_READY =			0x00,
+	SMS_SERVER_NOT_READY =			0x01
+};
+enum sms_routing_command {
+	SMS_ROUTING_RELEASE =			0x00,
+	SMS_ROUTING_SET =			0x01,
+	SMS_ROUTING_UPDATE =			0x04,
+	SMS_ROUTING_QUERRY_ALL =		0x06
+};
+enum sms_gsm_routing_mode {
+	SMS_GSM_ROUTING_MODE_ALL =		0x0B,
+};
+
+enum sms_gsm_cb_subject_list_type {
+	SMS_CB_ALLOWED_IDS_LIST =		0x00,
+	SMS_CB_NOT_ALLOWED_IDS_LIST =		0x01,
+};
+
+GIsiClient *get_pn_sms_client(GIsiModem * modem, uint8_t resource);
+void pn_sms_client_destroy(GIsiClient *client);
+gboolean is_pn_sms_client();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __ISIMODEM25_SMS_H */
diff --git a/drivers/isimodem2.5/ss.h b/drivers/isimodem2.5/ss.h
new file mode 100644
index 0000000..1716822
--- /dev/null
+++ b/drivers/isimodem2.5/ss.h
@@ -0,0 +1,174 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_SS_H
+#define __ISIMODEM25_SS_H
+
+#include <gisi/client.h>
+
+#define PN_SS				0x06
+#define SS_TIMEOUT			15
+#define SS_MAX_USSD_LENGTH		160
+
+enum ss_message_id {
+	SS_SERVICE_REQ =			0x00,
+	SS_SERVICE_COMPLETED_RESP =		0x01,
+	SS_SERVICE_FAILED_RESP =		0x02,
+	SS_SERVICE_NOT_SUPPORTED_RESP =		0x03,
+	SS_GSM_USSD_SEND_REQ =			0x04,
+	SS_GSM_USSD_SEND_RESP =			0x05,
+	SS_GSM_USSD_RECEIVE_IND =		0x06,
+	SS_STATUS_IND =				0x09,
+	SS_SERVICE_COMPLETED_IND =		0x10,
+	SS_CANCEL_REQ =				0x11,
+	SS_CANCEL_RESP =			0x12,
+	SS_RESOURCE_CONTROL_IND =		0x21,
+	SS_RESOURCE_CONTROL_REQ =		0x22,
+	SS_RESOURCE_CONTROL_RESP =		0x23,
+	SS_RESOURCE_CONF_IND =			0x24,
+	SS_RESOURCE_CONF_REQ =			0x25,
+	SS_RESOURCE_CONF_RESP =			0x26
+};
+
+enum ss_ussd_type {
+	SS_GSM_USSD_MT_REPLY =			0x01,
+	SS_GSM_USSD_COMMAND =			0x02,
+	SS_GSM_USSD_REQUEST =			0x03,
+	SS_GSM_USSD_NOTIFY =			0x04,
+	SS_GSM_USSD_END =			0x05
+};
+
+enum ss_ussd_status {
+	SS_GSM_STATUS_REQUEST_USSD_START =	0x02,
+	SS_GSM_STATUS_REQUEST_USSD_STOP =	0x03,
+	SS_GSM_STATUS_REQUEST_USSD_FAILED =	0x04
+};
+
+enum ss_operations {
+	SS_ACTIVATION =				0x01,
+	SS_DEACTIVATION =			0x02,
+	SS_REGISTRATION =			0x03,
+	SS_ERASURE =				0x04,
+	SS_INTERROGATION =			0x05,
+	SS_GSM_PASSWORD_REGISTRATION =		0x06
+};
+
+enum ss_basic_service_codes {
+	SS_ALL_TELE_AND_BEARER =		0,
+	SS_GSM_ALL_TELE =			10,
+	SS_GSM_TELEPHONY =			11,
+	SS_GSM_ALL_DATA_TELE =			12,
+	SS_GSM_FACSIMILE =			13,
+	SS_GSM_SMS =				16,
+	SS_GSM_VOICE_GROUP =			17,
+	SS_GSM_ALL_TELE_EXC_SMS =		19,
+	SS_GSM_ALL_BEARER =			20,
+	SS_GSM_ALL_ASYNC =			21,
+	SS_GSM_ALL_SYNC =			22,
+	SS_GSM_ALL_DATA_CIRCUIT_SYNC =		24,
+	SS_GSM_ALL_DATA_CIRCUIT_ASYNC =		25,
+	SS_GSM_ALL_DATA_PACKET_SYNC =		26,
+	SS_GSM_ALL_PAD_ACCESS =			27
+};
+
+enum ss_codes {
+	SS_GSM_ALL_SS =				0x0000,
+	SS_GSM_ALL_FORWARDINGS =		0x0002,
+	SS_GSM_ALL_COND_FORWARDINGS =		0x0004,
+	SS_GSM_FORW_UNCONDITIONAL =		0x0015,
+	SS_GSM_FORW_BUSY =			0x0043,
+	SS_GSM_FORW_NO_REPLY =			0x003D,
+	SS_GSM_FORW_NO_REACH =			0x003E,
+	SS_GSM_ALL_BARRINGS =			0x014A,
+	SS_GSM_BARR_ALL_OUT =			0x0021,
+	SS_GSM_BARR_OUT_INTER =			0x014B,
+	SS_GSM_BARR_OUT_INTER_EXC_HOME =	0x014C,
+	SS_GSM_BARR_ALL_IN =			0x0023,
+	SS_GSM_BARR_ALL_IN_ROAM =		0x015F,
+	SS_GSM_OUTGOING_BARR_SERV =		0x014D,
+	SS_GSM_INCOMING_BARR_SERV =		0x0161,
+	SS_GSM_CALL_WAITING =			0x002B,
+	SS_GSM_CLIP =				0x001E,
+	SS_GSM_CLIR =				0x001F,
+	SS_GSM_COLP =				0x004C,
+	SS_GSM_COLR =				0x004D,
+	SS_GSM_CNAP =				0x012C,
+	SS_GSM_ECT =				0x0060
+};
+
+enum ss_response_data {
+	SS_SEND_ADDITIONAL_INFO =		0x01
+};
+
+enum ss_subblock {
+	SS_FORWARDING =				0x00,
+	SS_STATUS_RESULT =			0x01,
+	SS_OTHER_ERROR =			0x02,
+	SS_GSM_PASSWORD =			0x03,
+	SS_GSM_FORWARDING_INFO =		0x04,
+	SS_GSM_FORWARDING_FEATURE =		0x05,
+	SS_GSM_BARRING_INFO =			0x06,
+	SS_GSM_BARRING_FEATURE =		0x07,
+	SS_GSM_DATA =				0x08,
+	SS_GSM_BSC_INFO =			0x09,
+	SS_GSM_GENERIC_SERVICE_INFO =		0x0A,
+	SS_GSM_PASSWORD_INFO =			0x0B,
+	SS_GSM_CLIR_INFO =			0x0C,
+	SS_GSM_INDICATE_PASSWORD_ERROR =	0x0D,
+	SS_GSM_INDICATE_ERROR =			0x0E,
+	SS_GSM_INDICATE_PROBLEM =		0x0F,
+	SS_GSM_INDICATE_MSG_ERROR =		0x10,
+	SS_GSM_ADDITIONAL_INFO =		0x2F,
+	SS_GSM_MM_RELEASED =			0x30,
+	SS_GSM_USSD_STRING =			0x32,
+	SS_SB_RESOURCE =			0x41,
+	SS_SB_RESOURCE_SEQ_ID =			0x42,
+	SS_SB_RESOURCE_STATUS =			0x43,
+	SS_SB_SS_CONTROL =			0x44,
+	SS_SB_USSD_CONTROL =			0x45,
+	SS_SB_RESOURCE_CONTROL_INFO =		0x46,
+	SS_SB_CHECK_INFO =			0x47,
+	SS_SB_RESOURCE_CONF_REQUIRED =		0x48,
+	SS_SB_RESOURCE_CONF =			0x49
+};
+
+enum ss_isi_cause {
+	SS_GSM_ACTIVE =				0x01,
+	SS_GSM_REGISTERED =			0x02,
+	SS_GSM_PROVISIONED =			0x04,
+	SS_GSM_QUIESCENT =			0x08
+};
+enum ss_gsm_cli_restriction_option {
+	SS_GSM_CLI_PERMANENT =			0x00,
+	SS_GSM_DEFAULT_RESTRICTED =		0x01,
+	SS_GSM_CLI_DEFAULT_ALLOWED =		0x02,
+	SS_GSM_OVERRIDE_ENABLED =		0x03,
+	SS_GSM_OVERRIDE_DISABLED =		0x04
+};
+enum ss_constants {
+	SS_UNDEFINED_TIME =			0x00,
+};
+
+GIsiClient *get_pn_ss_client(GIsiModem *modem, uint8_t resource);
+void pn_ss_client_destroy(GIsiClient *client);
+
+#endif /* __ISIMODEM25_SS_H */
diff --git a/drivers/isimodem2.5/ssn.c b/drivers/isimodem2.5/ssn.c
new file mode 100644
index 0000000..b948500
--- /dev/null
+++ b/drivers/isimodem2.5/ssn.c
@@ -0,0 +1,456 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/ssn.h>
+
+#include <glib.h>
+
+#include "call.h"
+#include "isimodem.h"
+
+#define NOT_3GGP_NOTIFICATION -1
+
+/* Specified by 3GGP in TS.27007 */
+enum gpp_cssi_codes {
+	UNCONDITIONAL_CALL_FORWARDING_IS_ACTIVE,
+	SOME_OF_CONDITIONAL_CALL_FORWARDINGS_ARE_ACTIVE,
+	CALL_HAS_BEEN_FORWARDED,
+	CALL_IS_WAITING,
+	THIS_IS_A_CUG_CALL,
+	OUTGOING_CALLS_ARE_BARRED,
+	INCOMING_CALLS_ARE_BARRED,
+	CLIR_SUPPRESSION_REJECTED,
+	CALL_HAS_BEEN_DEFLECTED
+};
+
+enum gpp_cssu_codes {
+	THIS_IS_A_FORWARDED_CALL,
+	THIS_IS_A_CUG_CALL_CSSU,
+	CALL_HAS_BEEN_PUT_ON_HOLD,
+	CALL_HAS_BEEN_RETRIEVED,
+	MULTIPARTY_CALL_ENTERED,
+	CALL_ON_HOLD_HAS_BEEN_RELEASED,
+	FORWARD_CHECK_SS_MESSAGE_RECEIVED,
+	CALL_IS_BEING_CON_WT_RM_PARTY_ALRT,
+	CALL_IS_BEING_CON_WT_OTH_RM_PARTY_EXPL,
+	THIS_IS_A_DEFLECTED_CALL,
+	ADDITIONAL_INCOMING_CALL_FORWARDED
+};
+
+
+struct ssn_data {
+	GIsiClient *client;
+};
+
+struct isi_ssn_prop {
+	char		number[OFONO_MAX_PHONE_NUMBER_LENGTH + 1];
+	int		type;
+	uint16_t	cug_index;
+};
+
+struct isi_ssn {
+	GIsiClient *client;
+	struct isi_call_req_context *queue;
+};
+
+static void isi_cm_sb_rem_address_sb_proc(struct isi_ssn_prop *ssn_prop,
+						GIsiSubBlockIter const *sb)
+{
+	uint8_t addr_type, addr_len;
+	char *address;
+	DBG("CALL_MODEM_SB_REMOTE_ADDRESS");
+
+	if (!g_isi_sb_iter_get_byte(sb, &addr_type, 2) ||
+			/* address type */
+			/* presentation indicator */
+			/* fillerbyte */
+		!g_isi_sb_iter_get_byte(sb, &addr_len, 5) ||
+		!g_isi_sb_iter_get_alpha_tag(sb, &address, 2 * addr_len, 6))
+		return;
+
+	strncpy(ssn_prop->number, address, addr_len);
+
+	g_free(address);
+}
+
+static void isi_ssn_notify_ofono(void *_ssn, int cssi, int cssu,
+					struct isi_ssn_prop *ssn_prop)
+{
+	struct ofono_phone_number *phone_nr =
+			(struct ofono_phone_number *) ssn_prop;
+
+	if (cssi != NOT_3GGP_NOTIFICATION)
+		ofono_ssn_cssi_notify(_ssn, cssi, ssn_prop->cug_index);
+
+	if (cssu != NOT_3GGP_NOTIFICATION)
+		ofono_ssn_cssu_notify(_ssn, cssi, ssn_prop->cug_index,
+					phone_nr);
+}
+
+static void isi_ssn_call_modem_sb_notify(GIsiSubBlockIter const *sb)
+{
+	uint8_t sb_property;
+	g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+	if (sb_property == CALL_MODEM_NOTIFY_USER_SUSPENDED)
+		DBG("CALL_MODEM_NOTIFY_USER_SUSPENDED");
+
+	if (sb_property == CALL_MODEM_NOTIFY_USER_RESUMED)
+		DBG("CALL_MODEM_NOTIFY_USER_RESUMED");
+
+	if (sb_property == CALL_MODEM_NOTIFY_BEARER_CHANGE)
+		DBG("CALL_MODEM_NOTIFY_BEARER_CHANGE");
+}
+
+static void isi_ssn_call_modem_sb_ss_code(GIsiSubBlockIter const *sb,
+						int *cssi_p, int *cssu_p)
+{
+	uint16_t sb_property;
+	g_isi_sb_iter_get_word(sb, &sb_property, 2);
+
+	switch (sb_property) {
+	case(CALL_MODEM_SSC_ALL_FWDS):
+		DBG("Call forwarding is active");
+		break;
+	case(CALL_MODEM_SSC_ALL_COND_FWD): {
+		*(cssi_p) = SOME_OF_CONDITIONAL_CALL_FORWARDINGS_ARE_ACTIVE;
+		DBG("Some of conditional call forwardings active");
+	}
+	break;
+	case(CALL_MODEM_SSC_CFU): {
+		*(cssi_p) = UNCONDITIONAL_CALL_FORWARDING_IS_ACTIVE;
+		DBG("Unconditional call forwarding is active");
+	}
+	break;
+	case(CALL_MODEM_SSC_CFB):
+		DBG("Unknown notification #1");
+		break;
+	case(CALL_MODEM_SSC_CFNRY):
+		DBG("Unknown notification #2");
+		break;
+	case(CALL_MODEM_SSC_CFGNC):
+		DBG("Unknown notification #3");
+		break;
+	case(CALL_MODEM_SSC_OUTGOING_BARR_SERV): {
+		*(cssi_p) = OUTGOING_CALLS_ARE_BARRED;
+		DBG("Outgoing calls are barred");
+	}
+	break;
+	case(CALL_MODEM_SSC_INCOMING_BARR_SERV): {
+		*(cssi_p) = INCOMING_CALLS_ARE_BARRED;
+		DBG("Incoming calls are barred");
+	}
+	break;
+	case(CALL_MODEM_SSC_CALL_WAITING):
+		DBG("Incoming calls are barred");
+		break;
+	case(CALL_MODEM_SSC_CLIR):
+		DBG("CLIR connected unknown indication.");
+		break;
+	case(CALL_MODEM_SSC_ETC):
+		DBG("Unknown notification #4");
+		break;
+	case(CALL_MODEM_SSC_MPTY): {
+		*(cssu_p) = MULTIPARTY_CALL_ENTERED;
+		DBG("Multiparty call entered.");
+	}
+	break;
+	case(CALL_MODEM_SSC_CALL_HOLD): {
+		*(cssu_p) = CALL_ON_HOLD_HAS_BEEN_RELEASED;
+		DBG("Call on hold has been released.");
+	}
+	break;
+	default:
+		break;
+	}
+}
+
+static void isi_ssn_call_modem_sb_ss_status(GIsiSubBlockIter const *sb)
+{
+	uint8_t sb_property;
+	g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+	if (sb_property & CALL_MODEM_SS_STATUS_ACTIVE)
+		DBG("CALL_MODEM_SS_STATUS_ACTIVE");
+
+	if (sb_property & CALL_MODEM_SS_STATUS_REGISTERED)
+		DBG("CALL_MODEM_SS_STATUS_REGISTERED");
+
+	if (sb_property & CALL_MODEM_SS_STATUS_PROVISIONED)
+		DBG("CALL_MODEM_SS_STATUS_PROVISIONED");
+
+	if (sb_property & CALL_MODEM_SS_STATUS_QUIESCENT)
+		DBG("CALL_MODEM_SS_STATUS_QUIESCENT");
+}
+
+static void isi_ssn_call_modem_sb_ss_notify(GIsiSubBlockIter const *sb,
+						int *cssi_p, int *cssu_p)
+{
+	uint8_t sb_property;
+	g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+	if (sb_property & CALL_MODEM_SSN_INCOMING_IS_FWD) {
+		*(cssu_p) = THIS_IS_A_FORWARDED_CALL;
+		DBG("This is a forwarded call #1.");
+	}
+
+	if (sb_property & CALL_MODEM_SSN_INCOMING_FWD)
+		DBG("This is a forwarded call #2.");
+
+	if (sb_property & CALL_MODEM_SSN_OUTGOING_FWD) {
+		*(cssi_p) = CALL_HAS_BEEN_FORWARDED;
+		DBG("Call has been forwarded.");
+	}
+}
+
+static void isi_ssn_call_modem_sb_ss_notify_ind(GIsiSubBlockIter const *sb,
+						int *cssi_p)
+{
+	uint8_t sb_property;
+	g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+	if (sb_property & CALL_MODEM_SSI_CALL_IS_WAITING) {
+		*(cssi_p) = CALL_IS_WAITING;
+		DBG("Call is waiting.");
+	}
+
+	if (sb_property & CALL_MODEM_SSI_MPTY)
+		DBG("Multiparty call.");
+
+	if (sb_property & CALL_MODEM_SSI_CLIR_SUPPR_REJ) {
+		*(cssi_p) = CLIR_SUPPRESSION_REJECTED;
+		DBG("CLIR suppression rejected.");
+	}
+}
+
+static void isi_ssn_call_modem_sb_ss_hold(GIsiSubBlockIter const *sb,
+						int *cssu_p)
+{
+	uint8_t sb_property;
+	g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+	if (sb_property & CALL_MODEM_HOLD_IND_RETRIEVED) {
+		*(cssu_p) = CALL_HAS_BEEN_RETRIEVED;
+		DBG("Call has been retrieved.");
+	}
+
+	if (sb_property & CALL_MODEM_HOLD_IND_ON_HOLD) {
+		*(cssu_p) = CALL_HAS_BEEN_PUT_ON_HOLD;
+		DBG("Call has been put on hold.");
+	}
+}
+
+static void isi_ssn_call_modem_sb_ss_ect_ind(GIsiSubBlockIter const *sb,
+						int *cssu_p)
+{
+	uint8_t sb_property;
+	g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+
+	if (sb_property & CALL_MODEM_ECT_CALL_STATE_ALERT) {
+		*(cssu_p) = CALL_IS_BEING_CON_WT_RM_PARTY_ALRT;
+		DBG("Call is being connected with the remote party");
+		DBG("in alerting state.");
+	}
+
+	if (sb_property & CALL_MODEM_ECT_CALL_STATE_ACTIVE) {
+		*(cssu_p) = CALL_IS_BEING_CON_WT_OTH_RM_PARTY_EXPL;
+		DBG("Call has been connected with the other remote");
+		DBG("party in explicit call transfer operation.");
+	}
+}
+
+static int isi_ssn_call_modem_sb_cug_info(GIsiSubBlockIter const *sb,
+						struct isi_ssn_prop *ssn_prop)
+{
+	uint8_t sb_property;
+	g_isi_sb_iter_get_byte(sb, &sb_property, 2);
+	DBG("CALL_MODEM_SB_CUG_INFO: This is a CUG Call.");
+	DBG("Preferential CUG: 0x%x,", sb_property);
+	g_isi_sb_iter_get_byte(sb, &sb_property, 3);
+	DBG("Cug Output Access: 0x%x,", sb_property);
+	g_isi_sb_iter_get_word(sb, &ssn_prop->cug_index, 4);
+	DBG("Cug Call Index: 0x%x,", ssn_prop->cug_index);
+	return THIS_IS_A_CUG_CALL;
+}
+
+
+static void isi_callmodem_notif_ind_cb(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *_ssn)
+{
+	struct ofono_ssn *ssn = _ssn;
+	struct isi_ssn *issn = ofono_ssn_get_data(ssn);
+	struct isi_ssn_prop *ssn_prop = g_try_new0(struct isi_ssn_prop, 1);
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	int cssi = NOT_3GGP_NOTIFICATION;
+	int cssu = NOT_3GGP_NOTIFICATION;
+	GIsiSubBlockIter sb[1];
+	DBG("Received CallServer notification.");
+
+	if (len < 3)
+		goto out;
+
+	if (!issn->client)
+		goto out;
+
+	for (g_isi_sb_iter_init(sb, data, len, (sizeof *m));
+			g_isi_sb_iter_is_valid(sb);
+			g_isi_sb_iter_next(sb)) {
+		switch (g_isi_sb_iter_get_id(sb)) {
+		case CALL_MODEM_SB_NOTIFY:
+			isi_ssn_call_modem_sb_notify(sb);
+			break;
+		case CALL_MODEM_SB_SS_CODE:
+			isi_ssn_call_modem_sb_ss_code(sb, &cssi, &cssu);
+			break;
+		case CALL_MODEM_SB_SS_STATUS:
+			isi_ssn_call_modem_sb_ss_status(sb);
+			break;
+		case CALL_MODEM_SB_SS_NOTIFY:
+			isi_ssn_call_modem_sb_ss_notify(sb, &cssi, &cssu);
+			break;
+		case CALL_MODEM_SB_SS_NOTIFY_INDICATOR:
+			isi_ssn_call_modem_sb_ss_notify_ind(sb, &cssi);
+			break;
+		case CALL_MODEM_SB_SS_HOLD_INDICATOR:
+			isi_ssn_call_modem_sb_ss_hold(sb, &cssu);
+			break;
+		case CALL_MODEM_SB_SS_ECT_INDICATOR:
+			isi_ssn_call_modem_sb_ss_ect_ind(sb, &cssu);
+			break;
+		case CALL_MODEM_SB_REMOTE_ADDRESS:
+			isi_cm_sb_rem_address_sb_proc(ssn_prop, sb);
+			break;
+		case CALL_MODEM_SB_REMOTE_SUBADDRESS:
+			break;
+		case CALL_MODEM_SB_CUG_INFO:
+			cssu = isi_ssn_call_modem_sb_cug_info(sb, ssn_prop);
+			break;
+		case CALL_MODEM_SB_ORIGIN_INFO:
+			break;
+		case CALL_MODEM_SB_ALERTING_PATTERN:
+			break;
+		case CALL_MODEM_SB_ALERTING_INFO:
+			break;
+		}
+	}
+
+	isi_ssn_notify_ofono(_ssn, cssi, cssu, ssn_prop);
+out:
+	g_free(ssn_prop);
+}
+
+static gboolean isi_ssn_register(gpointer user)
+{
+	struct ofono_ssn *ssn = user;
+	struct ssn_data *sd = ofono_ssn_get_data(ssn);
+	DBG("");
+
+	g_isi_subscribe(sd->client, CALL_MODEM_NOTIFICATION_IND,
+					isi_callmodem_notif_ind_cb, ssn);
+
+	ofono_ssn_register(user);
+
+	return FALSE;
+}
+
+static void ssn_reachable_cb(GIsiClient *client, gboolean alive,
+					uint16_t object, void *opaque)
+{
+	struct ofono_ssn *ssn = opaque;
+	DBG("");
+
+	if (!alive) {
+		DBG("Unable to bootsrap ssn driver");
+		return;
+	}
+
+	DBG("PN_SSN (v%03d.%03d) reachable.",
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_idle_add(isi_ssn_register, ssn);
+}
+
+static int isi_ssn_probe(struct ofono_ssn *ssn, unsigned int vendor,
+				void *user)
+{
+	GIsiModem *idx = user;
+	struct ssn_data *data = g_try_new0(struct ssn_data, 1);
+	DBG("");
+
+	if (!data)
+		return -ENOMEM;
+
+	data->client = g_isi_client_create(idx, PN_MODEM_CALL);
+
+	if (!data->client)
+		return -ENOMEM;
+
+	ofono_ssn_set_data(ssn, data);
+	g_isi_verify(data->client, ssn_reachable_cb, ssn);
+	return 0;
+}
+
+static void isi_ssn_remove(struct ofono_ssn *ssn)
+{
+	struct ssn_data *data = ofono_ssn_get_data(ssn);
+	DBG("");
+
+	if (data) {
+		g_isi_client_destroy(data->client);
+		g_free(data);
+	}
+}
+
+static struct ofono_ssn_driver driver = {
+	.name			= "isimodem25",
+	.probe			= isi_ssn_probe,
+	.remove			= isi_ssn_remove
+};
+
+void isi_ssn_init()
+{
+	ofono_ssn_driver_register(&driver);
+}
+
+void isi_ssn_exit()
+{
+	ofono_ssn_driver_unregister(&driver);
+}
diff --git a/drivers/isimodem2.5/timeout.h b/drivers/isimodem2.5/timeout.h
new file mode 100644
index 0000000..e24471a
--- /dev/null
+++ b/drivers/isimodem2.5/timeout.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define MCE_TIMEOUT		5
+#define GPDS_TIMEOUT		120
+#define GSS_TIMEOUT		5
+#define INFO_TIMEOUT		5
+#define NETWORK_TIMEOUT		5
+#define GSS_TIMEOUT		5
+#define SIM_TIMEOUT		5
+#define CBS_TIMEOUT		5
+#define SMS_TIMEOUT		15
+#define SS_TIMEOUT		15
+#define ISI_CALL_TIMEOUT	1000
+
diff --git a/drivers/isimodem2.5/uicc.c b/drivers/isimodem2.5/uicc.c
new file mode 100644
index 0000000..4b7c1e6
--- /dev/null
+++ b/drivers/isimodem2.5/uicc.c
@@ -0,0 +1,3316 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <gisi/client.h>
+#include <gisi/iter.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/sim.h>
+
+#include <ofono/dbus.h>
+#include <glib.h>
+
+#include "debug.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "simutil.h"
+#include "timeout.h"
+#include "uicc.h"
+#include "uicc_interface.h"
+
+#define CLIENT_ID 1
+
+/* #define STATIC_FILE_INFO */
+/* #define READ_FILE_CYCLIC */
+/* #define WRITE_FILE_CYCLIC */
+/* #define WRITE_FILE_TRANSPARENT */
+/* #define QUERY_LOCKED */
+#define PIN_PROMPT
+#define STATUS_WORD_HANDLING
+
+/* File info parameters */
+#define FCP_TEMPLATE			0x62
+#define FCP_FILE_SIZE			0x80
+#define FCP_FILE_DESC			0x82
+#define FCP_FILE_ID			0x83
+#define FCP_FILE_LIFECYCLE		0x8A
+#define FCP_FILE_SECURITY_ARR		0x8B
+#define FCP_FILE_SECURITY_COMPACT	0x8C
+#define FCP_FILE_SECURITY_EXPANDED	0xAB
+#define FCP_PIN_STATUS			0xC6
+#define SIM_EFARR_FILEID		0x6f06
+#define ADF_USIM			0x7FFF
+#define MAX_SIM_APPS			10
+#define NOT_AVAILABLE			-1
+#define NOT_ACTIVATED			-1
+
+struct sim_data {
+	GIsiClient *client;
+	gboolean iccid;
+	gboolean registered;
+	gboolean uicc_app_started;
+	gboolean pin_state_received;
+	gboolean passwd_required;
+	int app_id;
+	int trying_app_id;
+	int app_type;
+	int trying_app_type;
+	uint8_t client_id;
+	uint8_t current_pin_id;
+	uint8_t pin1_id;
+	uint8_t pin2_id;
+};
+
+
+struct ofono_sim_local {
+	char *iccid;
+	char *imsi;
+	enum ofono_sim_phase phase;
+	unsigned char mnc_length;
+	GSList *own_numbers;
+	GSList *new_numbers;
+	GSList *service_numbers;
+	gboolean sdn_ready;
+	enum ofono_sim_state state;
+	enum ofono_sim_password_type pin_type;
+	gboolean locked_pins[OFONO_SIM_PASSWORD_INVALID];
+	char **language_prefs;
+	GQueue *simop_q;
+	gint simop_source;
+	unsigned char efmsisdn_length;
+	unsigned char efmsisdn_records;
+	unsigned char *efli;
+	unsigned char efli_length;
+	enum ofono_sim_cphs_phase cphs_phase;
+	unsigned char cphs_service_table[2];
+	struct ofono_watchlist *state_watches;
+	const struct ofono_sim_driver *driver;
+	void *driver_data;
+	struct ofono_atom *atom;
+	DBusMessage *pending;
+};
+
+
+struct sim_passwd_to_pin_id {
+	uint8_t passwd_type;
+	uint8_t pin_id;
+};
+
+static struct sim_passwd_to_pin_id const pin_ids[] = {
+	{OFONO_SIM_PASSWORD_NONE, 0},
+	{OFONO_SIM_PASSWORD_SIM_PIN, 1},
+	{OFONO_SIM_PASSWORD_PHSIM_PIN, 0},
+	{OFONO_SIM_PASSWORD_PHFSIM_PIN, 0},
+	{OFONO_SIM_PASSWORD_SIM_PIN2, -1},
+	{OFONO_SIM_PASSWORD_PHNET_PIN, 0x11},
+	{OFONO_SIM_PASSWORD_PHNETSUB_PIN, 0},
+	{OFONO_SIM_PASSWORD_PHSP_PIN, 0},
+	{OFONO_SIM_PASSWORD_PHCORP_PIN, 0},
+	{OFONO_SIM_PASSWORD_SIM_PUK, -1},
+	{OFONO_SIM_PASSWORD_PHFSIM_PUK, 0},
+	{OFONO_SIM_PASSWORD_SIM_PUK2, -1},
+	{OFONO_SIM_PASSWORD_PHNET_PUK, 0},
+	{OFONO_SIM_PASSWORD_PHNETSUB_PUK, 0},
+	{OFONO_SIM_PASSWORD_PHSP_PUK, 0},
+	{OFONO_SIM_PASSWORD_PHCORP_PUK, 0},
+	{OFONO_SIM_PASSWORD_INVALID, 0}
+};
+
+const uint8_t upin_id = 0x11;
+
+/* Current SIM */
+static struct ofono_sim *uicc_sim;
+/* UICC client */
+static GIsiClient *pn_uicc_client;
+static int uicc_users;
+
+struct sim_applications {
+	int app_list[MAX_SIM_APPS];
+	int app_type[MAX_SIM_APPS];
+};
+
+struct sim_applications *sim_application_list_p;
+
+struct file_info {
+	int fileid;
+	int length;
+	int structure;
+	int record_length;
+	unsigned char access[3];
+};
+
+static struct file_info const static_file_info[] = {
+	{
+		SIM_EFSPN_FILEID, 17, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		0, { 0x0e, 0xff, 0xee }
+	},
+	{
+		SIM_EF_ICCID_FILEID, 10, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		10, { 0x0f, 0xff, 0xee }
+	},
+	{
+		SIM_EFPL_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		1, { 0x0f, 0xff, 0xff }
+	}, /* not found */
+	{
+		SIM_EFLI_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		1, { 0x0f, 0xff, 0xff }
+	}, /* not found */
+	{
+		SIM_EFMSISDN_FILEID, 28, OFONO_SIM_FILE_STRUCTURE_FIXED,
+		28, { 0x01, 0xff, 0xee }
+	},
+	{
+		SIM_EFAD_FILEID, 20, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		20, { 0x0e, 0xff, 0xee }
+	},
+	{
+		SIM_EFPHASE_FILEID, 1, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		1, { 0x0e, 0xff, 0xee }
+	},
+	{
+		SIM_EFPNN_FILEID, 4 * 18, OFONO_SIM_FILE_STRUCTURE_FIXED,
+		18, { 0x0e, 0xff, 0xee }
+	}, /* 4 records, name 16 bytes */
+	{
+		SIM_EFOPL_FILEID, 4 * 24, OFONO_SIM_FILE_STRUCTURE_FIXED,
+		24, { 0x0e, 0xff, 0xee }
+	}, /* 4 records, name 16 bytes */
+	{
+		SIM_EFMBI_FILEID, 5, OFONO_SIM_FILE_STRUCTURE_FIXED,
+		5, { 0x0e, 0xff, 0xee }
+	},
+	{
+		SIM_EFMWIS_FILEID, 6, OFONO_SIM_FILE_STRUCTURE_FIXED,
+		6, { 0x01, 0xff, 0xee }
+	},
+	{
+		SIM_EFSPDI_FILEID, 64, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		64, { 0x0e, 0xff, 0xee }
+	},
+	{
+		SIM_EFECC_FILEID, 5 * 3, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		3, { 0x0e, 0xff, 0xee }
+	}, /* Can be also FIXED in 3G */
+	{
+		SIM_EFCBMIR_FILEID, 8 * 4, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		4, { 0x01, 0xff, 0xee }
+	}, /* 8 records */
+	{
+		SIM_EFCBMI_FILEID, 8 * 2, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		2, { 0x01, 0xff, 0xee }
+	}, /* 8 records */
+	{
+		SIM_EFCBMID_FILEID, 8 * 2, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		2, { 0x01, 0xff, 0x11 }
+	}, /* 8 records */
+	{
+		SIM_EFSMSP_FILEID, 56, OFONO_SIM_FILE_STRUCTURE_FIXED,
+		56, { 0x01, 0xff, 0xee }
+	},
+	{
+		SIM_EFIMSI_FILEID, 9, OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+		9, { 0x0e, 0xff, 0xee }
+	},
+};
+static uint8_t get_sfi(const int fileid);
+
+static void uicc_pin_prompt(struct ofono_sim *sim,
+				enum ofono_sim_password_type passwd_type,
+				ofono_sim_passwd_cb_t cb,
+				void *data,
+				uint8_t service);
+
+static void uicc_application_activate_req(GIsiClient *client,
+						void *opaque,
+						unsigned char appl_type,
+						unsigned char aid);
+
+static int sim_applications_get_next_index(struct sim_applications *sa,
+						int current_app)
+{
+	if (current_app < (MAX_SIM_APPS - 1)) {
+		int i;
+
+		for (i = ++current_app; i < MAX_SIM_APPS; i++) {
+			if (sa->app_list[i] &&
+				(sa->app_type[i] != UICC_APPL_TYPE_UNKNOWN))
+				return i;
+		}
+	}
+
+	return NOT_AVAILABLE;
+}
+
+static uint8_t get_pin_id(struct sim_data *sd,
+				uint8_t passwd_type,
+				int8_t *index)
+{
+#define MAX_INDEX (sizeof(pin_ids)/sizeof(struct sim_passwd_to_pin_id))
+	uint8_t i, pin_id;
+	*index = -1;
+
+	for (i = 0; i <  MAX_INDEX; i++) {
+		if (pin_ids[i].passwd_type == passwd_type)
+			*index = i;
+	}
+
+	switch (passwd_type) {
+	case OFONO_SIM_PASSWORD_SIM_PIN:
+	case OFONO_SIM_PASSWORD_SIM_PUK:
+		return sd->pin1_id;
+	case OFONO_SIM_PASSWORD_SIM_PIN2:
+	case OFONO_SIM_PASSWORD_SIM_PUK2:
+		return sd->pin2_id;
+	default:
+
+		if (*index == -1)
+			pin_id = 0;
+		else
+			pin_id = pin_ids[*index].pin_id;
+
+		return pin_id;
+	}
+}
+
+static void update_locked_pin(struct ofono_sim_local *local_sim,
+				uint8_t lock_type, uint8_t pinID)
+{
+	struct sim_data *sd = ofono_sim_get_data((struct ofono_sim *)local_sim);
+
+	switch (lock_type) {
+	case UICC_PIN_VERIFY_NEEDED:
+
+		if (pinID <= sd->pin1_id) {
+			local_sim->pin_type =
+				OFONO_SIM_PASSWORD_SIM_PIN;
+			local_sim->locked_pins[
+				OFONO_SIM_PASSWORD_SIM_PIN] = TRUE;
+			sd->passwd_required = TRUE;
+		} else if (pinID == sd->pin2_id) {
+			local_sim->pin_type =
+				OFONO_SIM_PASSWORD_SIM_PIN2;
+			local_sim->locked_pins[
+				OFONO_SIM_PASSWORD_SIM_PIN2] = TRUE;
+			sd->passwd_required = TRUE;
+		} else if (pinID == upin_id) {
+			local_sim->pin_type =
+				OFONO_SIM_PASSWORD_PHNET_PIN;
+			local_sim->locked_pins[
+				OFONO_SIM_PASSWORD_PHNET_PIN] = TRUE;
+			sd->passwd_required = TRUE;
+		}
+
+		break;
+	case UICC_PIN_UNBLOCK_NEEDED:
+
+		if (pinID == sd->pin1_id) {
+			local_sim->pin_type =
+				OFONO_SIM_PASSWORD_SIM_PUK;
+			local_sim->locked_pins[
+				OFONO_SIM_PASSWORD_SIM_PUK] = TRUE;
+			sd->passwd_required = TRUE;
+		} else if (pinID == sd->pin2_id) {
+			local_sim->pin_type =
+				OFONO_SIM_PASSWORD_SIM_PUK2;
+			local_sim->locked_pins[
+				OFONO_SIM_PASSWORD_SIM_PUK2] = TRUE;
+			sd->passwd_required = TRUE;
+		} else if (pinID == upin_id) {
+			local_sim->pin_type =
+				OFONO_SIM_PASSWORD_PHNET_PUK;
+			local_sim->locked_pins[
+				OFONO_SIM_PASSWORD_PHNET_PUK] = TRUE;
+			sd->passwd_required = TRUE;
+		}
+
+		break;
+	default:
+		break;
+	}
+}
+
+static gboolean get_fileid_path(struct ofono_sim *sim,
+				int *mf_path,
+				int *df1_path,
+				int *df2_path,
+				unsigned char *df_len,
+				int fileid)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	switch (fileid) {
+	case SIM_EFPL_FILEID:
+	case SIM_EF_ICCID_FILEID:
+		*mf_path = MF_FILEID;
+		*df1_path = 0x0000;
+		*df2_path = 0x0000;
+		*df_len = 2;
+		break;
+	case SIM_EFSMSP_FILEID:
+	case SIM_EFSDN_FILEID:
+	case SIM_EFMSISDN_FILEID:
+		*mf_path = MF_FILEID;
+
+		if (UICC_APPL_TYPE_ICC_SIM == sd->app_type)
+			*df1_path = DFTELECOM_FILEID;
+		else
+			*df1_path = ADF_USIM;
+
+		*df2_path = 0x0000;
+		*df_len = 4;
+		break;
+	case SIM_EFLI_FILEID:
+	case SIM_EFSPN_FILEID:
+	case SIM_EFAD_FILEID:
+	case SIM_EFPNN_FILEID:
+	case SIM_EFOPL_FILEID:
+	case SIM_EFMBDN_FILEID:
+	case SIM_EFMBI_FILEID:
+	case SIM_EFMWIS_FILEID:
+	case SIM_EFSPDI_FILEID:
+	case SIM_EFECC_FILEID:
+	case SIM_EFCBMI_FILEID:
+	case SIM_EFCBMIR_FILEID:
+	case SIM_EFCBMID_FILEID:
+	case SIM_EFIMSI_FILEID:
+	case SIM_EFPHASE_FILEID: /*Did not find in TS 31.102 v6.21.0*/
+	case SIM_EFARR_FILEID:
+	case SIM_EF_CPHS_INFORMATION_FILEID: /*Found from unofficial source*/
+		*mf_path = MF_FILEID;
+
+		if (UICC_APPL_TYPE_ICC_SIM == sd->app_type)
+			*df1_path = DFGSM_FILEID;
+		else
+			*df1_path = ADF_USIM;
+
+		*df2_path = 0x0000;
+		*df_len = 4;
+		break;
+		/* No info */
+	case SIM_EF_CPHS_MBDN_FILEID:
+	case SIM_EF_CPHS_MWIS_FILEID:
+		DBG("======== No path info for %04X", fileid);
+		return FALSE;
+	case SIM_EFADN_SIM_FILEID: /* Only for SIM */
+	case SIM_EFEXT1_SIM_FILEID: /* Only for SIM */
+		*mf_path = MF_FILEID;
+		*df1_path = DFTELECOM_FILEID;
+		*df2_path = 0x0000;
+		*df_len = 4;
+		break;
+	default:
+		*mf_path = MF_FILEID;
+		*df1_path = DFTELECOM_FILEID;
+		*df2_path = DFPHONEBOOK_FILEID;
+		*df_len = 6;
+		break;
+	}
+
+	return TRUE;
+}
+
+static uint8_t get_sfi(const int fileid)
+{
+	uint8_t ret;
+
+	/* SFI list from 3GPP TS 31.102 Annex H */
+	switch (fileid) {
+	case SIM_EFECC_FILEID:
+		ret = 01;
+		break;
+	case SIM_EFLI_FILEID:
+		ret = 02;
+		break;
+	case SIM_EFAD_FILEID:
+		ret = 03;
+		break;
+	case SIM_EFIMSI_FILEID:
+		ret = 07;
+		break;
+	case SIM_EFCBMID_FILEID:
+		ret = 0x0E;
+		break;
+	case SIM_EFPNN_FILEID:
+		ret = 0x19;
+		break;
+	case SIM_EFOPL_FILEID:
+		ret = 0x1A;
+		break;
+	default:
+		ret = UICC_SFI_NOT_PRESENT;
+		break;
+	}
+
+	return ret;
+}
+
+int get_app_id()
+{
+	if (uicc_sim) {
+		struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+		DBG("app_id %d", sd->app_id);
+		return sd->app_id;
+	} else
+		return -1;
+}
+
+int get_app_type()
+{
+	if (uicc_sim) {
+		struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+		DBG("app_type %d", sd->app_type);
+		return sd->app_type;
+	} else
+		return -1;
+}
+
+int get_client_id()
+{
+	if (uicc_sim) {
+		struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+		DBG("client_id %d", sd->client_id);
+		return sd->client_id;
+	} else
+		return -1;
+}
+
+GIsiClient *read_pn_uicc_client()
+{
+	return pn_uicc_client;
+}
+
+struct ofono_sim *get_sim()
+{
+	return uicc_sim;
+}
+
+/* Returns file info */
+#ifdef STATIC_FILE_INFO
+static gboolean fake_file_info(gpointer user)
+{
+	struct isi_cb_data *cbd = user;
+	ofono_sim_file_info_cb_t cb = cbd->cb;
+	struct file_info const *fi = cbd->user;
+	DBG("Returning static file info: Fileid=%04X, \
+		filelen=%d, reclen=%d, structure=%d",
+		fi->fileid, fi->length, fi->record_length, fi->structure);
+	CALLBACK_WITH_SUCCESS(cb, fi->length, fi->structure,
+				fi->record_length, fi->access, cbd->data);
+	g_free(cbd);
+	return FALSE;
+}
+#else
+static gboolean isi_file_info_resp(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_file_info_cb_t cb = cbd->cb;
+	uint16_t length = 0;
+	uint16_t record_length = 0;
+	uint8_t structure = -1;
+	uint8_t records = 0;
+	uint16_t file_id = 0;
+	uint8_t access[3] = {0, 0, 0};
+	uint8_t fcp_len = 0, read = 0, id = 0, item_len = 0;
+	uint8_t fcp = 0, desc = 0, coding = 0;
+	gboolean everything_ok = FALSE;
+	/*Access is read from static file info*/
+	struct file_info const *info = cbd->user;
+	GIsiSubBlockIter iter;
+	struct sim_data *sd = ofono_sim_get_data(uicc_sim);
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s, details %d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]), msg[3]);
+
+	if (msg[0] != UICC_APPL_CMD_RESP)
+		goto error;
+
+	if (msg[1] != UICC_APPL_FILE_INFO)
+		goto error;
+
+	if (msg[2] != UICC_STATUS_OK)
+		goto error;
+
+	if (info) {
+		access[0] = info->access[0];
+		access[1] = info->access[1];
+		access[2] = info->access[2];
+	}
+
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_FCI:
+			DBG("UICC_SB_FCI");
+			everything_ok = TRUE;
+
+			switch (sd->app_type) {
+			case UICC_APPL_TYPE_UICC_USIM:
+				DBG("UICC_APPL_TYPE_UICC_USIM");
+				(void) g_isi_sb_iter_get_byte(&iter, &fcp, 8);
+
+				if (fcp == FCP_TEMPLATE) {
+					(void) g_isi_sb_iter_get_byte(&iter,
+								      &fcp_len,
+								      9);
+
+					while (read < fcp_len) {
+						(void) g_isi_sb_iter_get_byte(
+							&iter, &id, read + 10);
+						(void) g_isi_sb_iter_get_byte(
+							&iter, &item_len,
+							read + 11);
+
+						switch (id) {
+						case FCP_FILE_SIZE:
+
+							if (item_len == 2) {
+								g_isi_sb_iter_get_word(
+									&iter,
+									&length,
+									read + 10 + 2);
+							}
+
+							break;
+						case FCP_FILE_ID:
+
+							if (item_len == 2) {
+								g_isi_sb_iter_get_word(
+									&iter,
+									&file_id,
+									read + 10 + 2);
+							}
+
+							break;
+						case FCP_FILE_DESC:
+
+							if (item_len >= 2) {
+								(void) g_isi_sb_iter_get_byte(
+									&iter,
+									&desc,
+									read + 10 + 2);
+								(void) g_isi_sb_iter_get_byte(
+									&iter,
+									&coding,
+									read + 10 + 3);
+							}
+
+							if (item_len >= 4) {
+								g_isi_sb_iter_get_word(
+									&iter,
+									&record_length,
+									read + 10 + 4);
+								(void) g_isi_sb_iter_get_byte(
+									&iter,
+									&records,
+									read + 10 + 6);
+							}
+
+							break;
+						case FCP_FILE_SECURITY_ARR:
+						case FCP_FILE_SECURITY_COMPACT:
+						case FCP_FILE_SECURITY_EXPANDED:
+
+						/* Not implemented, using static
+						 * access rules as these are
+						 * used only for cacheing See
+						 * ETSI TS 102 221, ch
+						 * 11.1.1.4.7 and
+						 * Annexes E,F and G
+						 */
+
+						case FCP_FILE_LIFECYCLE:
+						default:
+							DBG("FCP id %02X not supported",
+								id);
+							break;
+						}
+
+						/*Data length + id size + len size*/
+						read += item_len + 2;
+					}
+				}
+
+				if ((desc & 7) == 1)
+					structure =
+					  OFONO_SIM_FILE_STRUCTURE_TRANSPARENT;
+				else if ((desc & 7) == 2)
+					structure =
+					  OFONO_SIM_FILE_STRUCTURE_FIXED;
+				else if ((desc & 7) == 6)
+					structure =
+					  OFONO_SIM_FILE_STRUCTURE_CYCLIC;
+
+				break;
+			case UICC_APPL_TYPE_ICC_SIM:
+				DBG("UICC_APPL_TYPE_ICC_SIM");
+				g_isi_sb_iter_get_word(&iter, &length, 10);
+				g_isi_sb_iter_get_word(&iter, &file_id, 12);
+				(void)g_isi_sb_iter_get_byte(&iter,
+								&access[0], 16);
+				(void)g_isi_sb_iter_get_byte(&iter,
+								&access[0], 17);
+				(void)g_isi_sb_iter_get_byte(&iter,
+								&access[0], 18);
+				(void)g_isi_sb_iter_get_byte(&iter,
+								&item_len, 20);
+				(void)g_isi_sb_iter_get_byte(&iter,
+								&structure, 21);
+
+				if (item_len == 2)
+					(void)g_isi_sb_iter_get_byte(&iter,
+								     (uint8_t *)&record_length, 22);
+
+				break;
+			default:
+				DBG("UICC application type %d not supported",
+					sd->app_type);
+				break;
+			}
+
+			break;
+		default:
+			DBG("Skipping SB");
+			break;
+		}
+
+		if (g_isi_sb_iter_next(&iter) == FALSE)
+			goto error;
+	}
+
+	if (everything_ok) {
+		DBG("====Returning real file info: Fileid=%04X, filelen=%d, \
+			records=%d, reclen=%d, structure=%d",
+			file_id, length, records,
+			record_length, structure);
+		CALLBACK_WITH_SUCCESS(cb, length, structure, record_length,
+				      access, '\n', cbd->data);
+		goto out;
+	}
+
+error:
+	DBG("Error reading file info");
+	CALLBACK_WITH_FAILURE(cb, 0, 0, 0, access, '\n', cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+#endif /* STATIC_FILE_INFO */
+static void isi_read_file_info(struct ofono_sim *sim, int fileid,
+				ofono_sim_file_info_cb_t cb, void *data)
+{
+#ifdef STATIC_FILE_INFO
+	int i;
+	int N = sizeof(static_file_info) / sizeof(static_file_info[0]);
+	struct isi_cb_data *cbd = NULL;
+
+	for (i = 0; i < N; i++) {
+		if (fileid == static_file_info[i].fileid) {
+			cbd = isi_cb_data_new((void *) &static_file_info[i],
+						cb, data);
+			g_idle_add(fake_file_info, cbd);
+			return;
+		}
+	}
+
+	DBG("Not implemented (fileid = %04x)", fileid);
+	CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL, data);
+#else
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(NULL, cb, data);
+	/* Prepare for static file info used for access rights */
+	int i;
+	int N = sizeof(static_file_info) / sizeof(static_file_info[0]);
+	int mf_path = 0;
+	int df1_path = 0;
+	int df2_path = 0;
+	unsigned char df_len = 0;
+
+	DBG("File info for ID=%04X app id %d", fileid, sd->app_id);
+
+	for (i = 0; i < N; i++) {
+		if (fileid == static_file_info[i].fileid && cbd != NULL) {
+			cbd->user = (void *) &static_file_info[i];
+			continue;
+		}
+	}
+	if (!get_fileid_path(sim, &mf_path, &df1_path,
+				&df2_path, &df_len, fileid))
+		goto error;
+	if (cbd && sd) {
+		const unsigned char msg[] = {
+			UICC_APPL_CMD_REQ,
+			UICC_APPL_FILE_INFO,
+			sd->app_id,
+			UICC_SESSION_ID_NOT_USED, /*Session ID*/
+			0, /*Filler*/
+			0, /*Filler*/
+			1, /*number of subblocks*/
+		/* Subblock 1*/
+			UICC_SB_APPL_PATH >> 8,
+			UICC_SB_APPL_PATH & 0xff,
+			0,
+			16, /*Sub block length*/
+			fileid >> 8, /* UICC elementary file ID*/
+			fileid & 0xFF,
+			get_sfi(fileid), /* Elementary file short file id*/
+			0, /*filler*/
+			df_len, /*DF Path length*/
+			0, /*Filler*/
+			mf_path >> 8,
+			mf_path & 0xff,
+			df1_path >> 8, /*DF Path*/
+			df1_path & 0xFF,
+			df2_path >> 8, /*DF Path*/
+			df2_path & 0xFF,
+		};
+		g_isi_request_make(
+			sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+			isi_file_info_resp, cbd);
+		return;
+	}
+
+error:
+	DBG("Not implemented (fileid = %04x)", fileid);
+	CALLBACK_WITH_FAILURE(cb, 0, 0, 0, NULL, '\n', cbd->data);
+	g_free(cbd);
+	return;
+#endif /* STATIC_FILE_INFO */
+}
+
+static gboolean isi_read_file_transparent_resp(GIsiClient *client,
+						const void *restrict data,
+						size_t len,
+						uint16_t object,
+						void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_read_cb_t cb = cbd->cb;
+	uint32_t filelen = 0;
+	unsigned char filedata[256] = { 0xff };
+	gboolean everything_ok = FALSE;
+	GIsiSubBlockIter iter;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s, details %d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]), msg[3]);
+
+	if (msg[0] != UICC_APPL_CMD_RESP)
+		goto error;
+
+	if (msg[1] != UICC_APPL_READ_TRANSPARENT)
+		goto error;
+
+	if (msg[2] != UICC_STATUS_OK)
+		goto error;
+
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_FILE_DATA:
+			g_isi_sb_iter_get_dword(&iter, &filelen, 4);
+			memmove(&filedata, iter.start + 8, filelen);
+			everything_ok = TRUE;
+			break;
+		default:
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	if (everything_ok) {
+		DBG("Transparent EF read: 1st byte %02x, len %d",
+			filedata[0], filelen);
+		CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
+		goto out;
+	}
+
+error:
+	DBG("Error reading transparent EF");
+	CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_read_file_transparent(struct ofono_sim *sim,
+					int fileid,
+					int start,
+					int length,
+					ofono_sim_read_cb_t cb,
+					void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	int mf_path = 0;
+	int df1_path = 0;
+	int df2_path = 0;
+	unsigned char df_len = 0;
+
+	DBG("File ID=%04X, client %d, AID %d",
+		fileid, sd->client_id, sd->app_id);
+
+	if (!get_fileid_path(sim, &mf_path, &df1_path,
+			&df2_path, &df_len, fileid))
+		goto error;
+
+	if (cbd && sd) {
+		const unsigned char msg[] = {
+			UICC_APPL_CMD_REQ,
+			UICC_APPL_READ_TRANSPARENT,
+			sd->app_id,
+			UICC_SESSION_ID_NOT_USED, /*Session ID*/
+			0, /*Filler*/
+			0, /*Filler*/
+			3, /*number of subblocks*/
+		/* Subblock 1 */
+			UICC_SB_CLIENT >> 8,
+			UICC_SB_CLIENT & 0xff,
+			0,
+			8, /*Sub block length*/
+			0, 0, 0, /* Filler */
+			sd->client_id,
+		/* Subblock 2*/
+			UICC_SB_TRANSPARENT >> 8,
+			UICC_SB_TRANSPARENT & 0xff,
+			0, /*Sub block length*/
+			8, /*Sub block length*/
+			0, /*File offset (0=beginning)*/
+			0, /*File offset (0=beginning)*/
+			0, /*Data amount (0=all)*/
+			0, /*Data amount (0=all)*/
+		/* Subblock 3 */
+			UICC_SB_APPL_PATH >> 8,
+			UICC_SB_APPL_PATH & 0xff,
+			0,
+			16, /* Sub block length*/
+			fileid >> 8, /* UICC elementary file ID*/
+			fileid & 0xFF,
+			get_sfi(fileid), /* Elementary file short file id*/
+			0, /*filler*/
+			df_len, /*DF Path length*/
+			0, /*Filler*/
+			mf_path >> 8,
+			mf_path & 0xff,
+			df1_path >> 8, /*DF Path*/
+			df1_path & 0xFF,
+			df2_path >> 8, /*DF Path*/
+			df2_path & 0xFF
+		};
+		g_isi_request_make(
+			sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+			isi_read_file_transparent_resp, cbd);
+		return;
+	}
+
+error:
+	DBG("Not implemented (fileid = %04x)", fileid);
+	CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+	g_free(cbd);
+	return;
+}
+
+static gboolean isi_read_file_linear_fixed_resp(GIsiClient *client,
+						const void *restrict data,
+						size_t len,
+						uint16_t object,
+						void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_read_cb_t cb = cbd->cb;
+	uint32_t filelen = 0;
+	unsigned char filedata[256] = { 0xff };
+	gboolean everything_ok = FALSE;
+	GIsiSubBlockIter iter;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s, details %d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]), msg[3]);
+
+	if (msg[0] != UICC_APPL_CMD_RESP)
+		goto error;
+
+	if (msg[1] != UICC_APPL_READ_LINEAR_FIXED)
+		goto error;
+
+	if (msg[2] != UICC_STATUS_OK)
+		goto error;
+
+	everything_ok = FALSE;
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_FILE_DATA:
+			g_isi_sb_iter_get_dword(&iter, &filelen, 4);
+			memmove(&filedata, iter.start + 8, filelen);
+			everything_ok = TRUE;
+			break;
+		default:
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	if (everything_ok) {
+		DBG("Linear fixed EF read: 1st byte %02x, len %d",
+			filedata[0], filelen);
+		CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
+		goto out;
+	}
+
+error:
+	DBG("Error reading linear fixed EF");
+	CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_read_file_linear_fixed(struct ofono_sim *sim,
+					int fileid,
+					int record,
+					int rec_length,
+					ofono_sim_read_cb_t cb,
+					void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	int mf_path = 0;
+	int df1_path = 0;
+	int df2_path = 0;
+	unsigned char df_len = 0;
+	DBG("File ID=%04X, record %d, client %d AID %d",
+		fileid, record, sd->client_id, sd->app_id);
+	if (!get_fileid_path(sim, &mf_path,
+			&df1_path, &df2_path, &df_len, fileid))
+		goto error;
+	if (cbd && sd) {
+
+		const unsigned char msg[] = {
+			UICC_APPL_CMD_REQ,
+			UICC_APPL_READ_LINEAR_FIXED,
+			sd->app_id,
+			UICC_SESSION_ID_NOT_USED, /*Session ID*/
+			0, /*Filler*/
+			0, /*Filler*/
+			3, /*number of subblocks*/
+		/* Subblock 1*/
+			UICC_SB_CLIENT >> 8,
+			UICC_SB_CLIENT & 0xff,
+			0,
+			8, /*Sub block length */
+			0, 0, 0, /* Filler */
+			sd->client_id,
+		/* Subblock 2 */
+			UICC_SB_LINEAR_FIXED >> 8,
+			UICC_SB_LINEAR_FIXED & 0xff,
+			0, /*Sub block length*/
+			8, /*Sub block length*/
+			record, /*Record*/
+			0, /*Record offset (0=beginning)*/
+			rec_length & 0xff, /*Data amount (0=all)*/
+			0, /*Filler*/
+		/* Subblock 3*/
+			UICC_SB_APPL_PATH >> 8,
+			UICC_SB_APPL_PATH & 0xff,
+			0,
+			16, /*Sub block length*/
+			fileid >> 8, /* UICC elementary file ID*/
+			fileid & 0xFF,
+			get_sfi(fileid), /* Elementary file short file id*/
+			0, /*filler*/
+			df_len, /*DF Path length*/
+			0, /*Filler*/
+			mf_path >> 8,
+			mf_path & 0xff,
+			df1_path >> 8, /*DF Path*/
+			df1_path & 0xFF,
+			df2_path >> 8, /*DF Path*/
+			df2_path & 0xFF
+		};
+		g_isi_request_make(
+			sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+			isi_read_file_linear_fixed_resp, cbd);
+		return;
+	}
+
+error:
+	DBG("Not implemented (fileid = %04x)", fileid);
+	CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+	g_free(cbd);
+}
+
+#ifdef READ_FILE_CYCLIC
+static gboolean isi_read_file_cyclic_resp(GIsiClient *client,
+						const void *restrict data,
+						size_t len,
+						uint16_t object,
+						void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_read_cb_t cb = cbd->cb;
+	uint32_t filelen = 0;
+	unsigned char filedata[256] = { 0xff };
+	gboolean everything_ok = FALSE;
+	GIsiSubBlockIter iter;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s, details %d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]), msg[3]);
+
+	if (msg[0] != UICC_APPL_CMD_RESP)
+		goto error;
+
+	if (msg[1] != UICC_APPL_READ_CYCLIC)
+		goto error;
+
+	if (msg[2] != UICC_STATUS_OK)
+		goto error;
+
+	everything_ok = FALSE;
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_FILE_DATA:
+			g_isi_sb_iter_get_dword(&iter, &filelen, 4);
+			memmove(&filedata, iter.start + 8, filelen);
+			everything_ok = TRUE;
+			break;
+		default:
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+	if (everything_ok) {
+		DBG("Cyclic EF read: 1st byte %02x, len %d",
+			filedata[0], filelen);
+		CALLBACK_WITH_SUCCESS(cb, filedata, filelen, cbd->data);
+		goto out;
+	}
+
+error:
+	DBG("Error reading cyclic EF");
+	CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void isi_read_file_cyclic(struct ofono_sim *sim,
+					int fileid,
+					int record,
+					int rec_length,
+					ofono_sim_read_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	int mf_path = 0;
+	int df1_path = 0;
+	int df2_path = 0;
+	unsigned char df_len = 0;
+	DBG("File ID=%04X, record %d, client %d AID %d",
+		fileid, record, sd->client_id, sd->app_id);
+
+	if (!get_fileid_path(sim, &mf_path,
+			&df1_path, &df2_path, &df_len, fileid))
+		goto error;
+
+	if (cbd && sd) {
+		const unsigned char msg[] = {
+			UICC_APPL_CMD_REQ,
+			UICC_APPL_READ_LINEAR_FIXED,
+			sd->app_id,
+			UICC_SESSION_ID_NOT_USED, /*Session ID*/
+			0, /*Filler*/
+			0, /*Filler*/
+			3, /*number of subblocks*/
+		/* Subblock 1 */
+			UICC_SB_CLIENT >> 8,
+			UICC_SB_CLIENT & 0xff,
+			0,
+			8, /*Sub block length*/
+			0, 0, 0, /* Filler*/
+			sd->client_id,
+		/* Subblock 2 */
+			UICC_SB_CYCLIC >> 8,
+			UICC_SB_CYCLIC & 0xff,
+			0, /*Sub block length*/
+			8, /*Sub block length*/
+			record, /*Record*/
+			0, /*Record offset (0=beginning)*/
+			rec_length & 0xff, /*Data amount (0=all)*/
+			0, /*Filler*/
+		/* Subblock 3 */
+			UICC_SB_APPL_PATH >> 8,
+			UICC_SB_APPL_PATH & 0xff,
+			0,
+			16, /* Sub block length */
+			fileid >> 8, /* UICC elementary file ID */
+			fileid & 0xFF,
+			/* Elementary file short file id */
+			get_sfi(fileid),
+			0, /*filler*/
+			df_len, /*DF Path length*/
+			0, /*Filler*/
+			mf_path >> 8,
+			mf_path & 0xff,
+			df1_path >> 8, /*DF Path*/
+			df1_path & 0xFF,
+			df2_path >> 8, /*DF Path*/
+			df2_path & 0xFF
+		};
+		g_isi_request_make(
+			sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+			isi_read_file_cyclic_resp, cbd);
+		return;
+	}
+
+error:
+	DBG("Not implemented (fileid = %04x)", fileid);
+	CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+	g_free(cbd);
+}
+#endif
+
+static void uicc_read_imsi_resp(const struct ofono_error *error,
+				const unsigned char *data,
+				int len,
+				void *user)
+{
+#define SIM_MAX_IMSI_LENGTH     15
+	struct isi_cb_data *cbd = user;
+	ofono_sim_imsi_cb_t cb = cbd->cb;
+	/* For coding see TS 24.008 */
+	char imsi[SIM_MAX_IMSI_LENGTH + 1];
+	int i = 1; /*Skip length, the 1st byte*/
+	int j = 0;
+	int octets;
+
+	if (!data)
+		goto error;
+
+	octets = data[0];
+
+	if (octets != 8 || octets > len)
+		goto error;
+
+	/* Ignore the low-order semi-octet of the first byte */
+	imsi[j] = ((data[i] & 0xF0) >> 4) + '0';
+
+	for (i++, j++; i - 1 < octets && j < SIM_MAX_IMSI_LENGTH; i++) {
+		char nibble;
+		imsi[j++] = (data[i] & 0x0F) + '0';
+		nibble = (data[i] & 0xF0) >> 4;
+
+		if (nibble != 0x0F)
+			imsi[j++] = nibble + '0';
+	}
+
+	imsi[j] = '\0';
+	DBG("IMSI %s", imsi);
+	CALLBACK_WITH_SUCCESS(cb, imsi, cbd->data);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
+out:
+	g_free(cbd);
+	return;
+}
+
+static void uicc_read_imsi_req(struct ofono_sim *sim,
+				ofono_sim_imsi_cb_t cb,
+				void *data)
+{
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	isi_read_file_transparent(sim, SIM_EFIMSI_FILEID, 0, 9,
+					uicc_read_imsi_resp, cbd);
+}
+
+static gboolean uicc_application_activate_resp(GIsiClient *client,
+		const void *restrict data,
+		size_t len,
+		uint16_t object,
+		void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_sim *sim = opaque;
+	GIsiSubBlockIter iter;
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service=%s, status=%s details=%d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]), msg[3]);
+
+	if (msg[0] != UICC_APPLICATION_RESP)
+		goto error;
+
+	if ((msg[2] == UICC_STATUS_OK) ||
+			(msg[2] == UICC_STATUS_APPL_ACTIVE)) {
+		if (!sd->uicc_app_started) {
+			sd->app_id = sd->trying_app_id;
+			sd->app_type = sd->trying_app_type;
+			sd->uicc_app_started = TRUE;
+			DBG("UICC application activated");
+			ofono_sim_inserted_notify(sim, TRUE);
+			ofono_sim_register(sim);
+			g_free(sim_application_list_p);
+		}
+	} else {
+		int i = sim_applications_get_next_index(
+				sim_application_list_p, sd->trying_app_id);
+
+		if (i == NOT_AVAILABLE) {
+			g_free(sim_application_list_p);
+			goto error;
+		}
+
+		DBG("Activation Error, trying to activate APP with ID:%d", i);
+		uicc_application_activate_req(client, sim,
+						sim_application_list_p->app_type[i],
+						sim_application_list_p->app_list[i]);
+		goto error;
+	}
+
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_CLIENT: {
+			guint8 client = 0;
+			g_isi_sb_iter_get_byte(&iter, &client, 7);
+			DBG("Client id %d", client);
+			sd->client_id = client;
+			break;
+		}
+		case UICC_SB_FCI:
+			DBG("UICC_SB_FCI");
+
+			if (sd->app_type == UICC_APPL_TYPE_UICC_USIM) {
+				uint8_t fcp = 0, fcp_len = 0, read = 0,
+					id = 0, item_len = 0;
+				(void) g_isi_sb_iter_get_byte(&iter, &fcp, 8);
+				DBG("UICC_APPL_TYPE_UICC_USIM");
+
+				if (fcp == FCP_TEMPLATE) {
+					(void) g_isi_sb_iter_get_byte(
+						&iter, &fcp_len, 9);
+					DBG("FCP_TEMPLATE");
+
+					while (read < fcp_len) {
+						(void) g_isi_sb_iter_get_byte(
+							&iter, &id, read + 10);
+						(void) g_isi_sb_iter_get_byte(
+							&iter, &item_len,
+							read + 11);
+
+						/* See TS 102 221,
+						*  PIN status template DO */
+						switch (id) {
+							uint8_t pin_do_len, pin_len,
+								pin_tag, pin_id,
+								pin_tag_pos;
+
+						case FCP_PIN_STATUS:
+
+							DBG("PIN status");
+							g_isi_sb_iter_get_byte(&iter,
+										&pin_do_len,
+										read + 10 + 3);
+							pin_tag_pos =
+								read + 10 + 4 + pin_do_len;
+							g_isi_sb_iter_get_byte(&iter,
+										&pin_tag,
+										pin_tag_pos);
+
+							while (pin_tag == 0x83) {
+								g_isi_sb_iter_get_byte(
+									&iter,
+									&pin_len,
+									pin_tag_pos + 1);
+								g_isi_sb_iter_get_byte(
+									&iter,
+									&pin_id,
+									pin_tag_pos + 2);
+								pin_tag_pos += 2 + pin_len;
+								g_isi_sb_iter_get_byte(
+									&iter, &pin_tag,
+									pin_tag_pos);
+								DBG("PIN_len %d, PIN id %02x, \
+									PIN tag %02x", pin_len,
+									pin_id, pin_tag);
+
+								if ((0x01 <= pin_id) &&
+										(pin_id <= 0x08))
+									sd->pin1_id = pin_id;
+								else if ((0x81 <= pin_id) &&
+										(pin_id <= 0x88))
+									sd->pin2_id = pin_id;
+							}
+
+							DBG("PIN1 %02x,\
+								PIN2 %02x",
+								sd->pin1_id,
+								sd->pin2_id);
+							break;
+						default:
+							DBG("Skipping tag %02x", id);
+							break;
+						}
+
+						/*Data length + id size + len size*/
+						read += item_len + 2;
+					}
+				}
+			}
+
+			break;
+		case UICC_SB_CHV:
+			DBG("UICC_SB_CHV");
+
+			if (sd->app_type == UICC_APPL_TYPE_ICC_SIM) {
+				uint8_t chv_id = 0, pin_id = 0;
+				(void) g_isi_sb_iter_get_byte(&iter,
+							      &chv_id, 4);
+				(void) g_isi_sb_iter_get_byte(&iter,
+							      &pin_id, 5);
+				DBG("UICC_APPL_TYPE_UICC_SIM");
+
+				if (chv_id == 1)
+					sd->pin1_id = pin_id;
+				else if (chv_id == 2)
+					sd->pin2_id = pin_id;
+			}
+
+			break;
+		default:
+			DBG("Skipping sub-block: %s (%zu bytes)",
+				uicc_subblock_name(g_isi_sb_iter_get_id(&iter)),
+				g_isi_sb_iter_get_len(&iter));
+			break;
+		}
+
+		(void)g_isi_sb_iter_next(&iter);
+	}
+
+error:
+	return TRUE;
+}
+
+static void uicc_application_activate_req(GIsiClient *client,
+						void *opaque,
+						unsigned char appl_type,
+						unsigned char aid)
+{
+	const unsigned char msg[] = {
+		UICC_APPLICATION_REQ,
+		UICC_APPL_HOST_ACTIVATE,
+		2, /* number of subblocks*/
+	/* Subblock 1 */
+		UICC_SB_APPLICATION >> 8,
+		UICC_SB_APPLICATION & 0xff,
+		0, /*subblock length*/
+		8, /*subblock length*/
+		0, /*filler*/
+		0, /*filler*/
+		appl_type,
+		aid,
+	/* Subblock 2 */
+		UICC_SB_APPL_INFO >> 8,
+		UICC_SB_APPL_INFO & 0xff,
+		0, /*subblock length*/
+		8, /*subblock length*/
+		0, /*filler*/
+		0, /*filler*/
+		0, /*filler*/
+		/* whether the application initialization procedure
+		*  will follow the activation or not */
+		UICC_APPL_START_UP_INIT_PROC
+	};
+
+	DBG("Appl type %d, AID %d", appl_type, aid);
+
+	g_isi_request_make(
+		client, msg, sizeof(msg), SIM_TIMEOUT,
+		uicc_application_activate_resp, opaque);
+}
+
+static gboolean uicc_application_list_resp(GIsiClient *client,
+						const void *restrict data,
+						size_t len,
+						uint16_t object,
+						void *opaque)
+{
+	struct ofono_sim *sim = opaque;
+	const unsigned char *msg = data;
+	gboolean everything_ok = TRUE;
+	int index = NOT_AVAILABLE;
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service=%s, status=%s details=%d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]), msg[3]);
+
+	if ((msg[0] != UICC_APPLICATION_RESP) ||
+			(msg[1] != UICC_APPL_LIST))
+		return FALSE;
+
+	if (msg[2] == UICC_STATUS_FAIL)
+		everything_ok = FALSE;
+
+	sim_application_list_p = g_try_new0(struct sim_applications, 1);
+
+	if (everything_ok) {
+		GIsiSubBlockIter iter;
+		g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+		while (g_isi_sb_iter_is_valid(&iter)) {
+			DBG("Sub-block %s",
+				uicc_subblock_name(
+					g_isi_sb_iter_get_id(&iter)));
+
+			switch (g_isi_sb_iter_get_id(&iter)) {
+			case UICC_SB_APPL_DATA_OBJECT: {
+				guint8 appl_id = -1;
+				guint8 appl_type = -1;
+				guint8 status = -1;
+				gboolean ret;
+				ret = g_isi_sb_iter_get_byte(
+					      &iter, &appl_type, 6);
+				ret = g_isi_sb_iter_get_byte(
+					      &iter, &appl_id, 7);
+				(void) g_isi_sb_iter_get_byte(
+					&iter, &status, 8);
+				DBG("Appl type=%d, Appl id=%d, Appl status=%d",
+					appl_type, appl_id, status);
+
+				sim_application_list_p->app_list[appl_id] =
+					appl_id;
+				sim_application_list_p->app_type[appl_id] =
+					appl_type;
+				break;
+			}
+			default:
+				DBG("Skipping sub-block: %s (%zu bytes)",
+					uicc_subblock_name(
+						g_isi_sb_iter_get_id(&iter)),
+					g_isi_sb_iter_get_len(&iter));
+				break;
+			}
+
+			g_isi_sb_iter_next(&iter);
+		}
+	}
+
+	if (!sd->uicc_app_started) {
+		index = sim_applications_get_next_index(sim_application_list_p,
+						NOT_ACTIVATED);
+
+		if (index != NOT_AVAILABLE) {
+			DBG("Activating APP index:%d", index);
+			sd->trying_app_id =
+			  sim_application_list_p->app_list[index];
+			sd->trying_app_type =
+			  sim_application_list_p->app_type[index];
+			DBG("Activating APP ID: %d APP type: %d",
+				sd->trying_app_id, sd->trying_app_type);
+			uicc_application_activate_req(client, sim,
+						sim_application_list_p->app_type[index],
+						sim_application_list_p->app_list[index]);
+		} else
+			g_free(sim_application_list_p);
+	}
+
+error:
+	return TRUE;
+}
+
+static void uicc_application_list_req(GIsiClient *client,
+					void *opaque)
+{
+	const unsigned char msg[] = {
+		UICC_APPLICATION_REQ,
+		UICC_APPL_LIST,
+		0 /* number of subblocks*/
+	};
+	DBG("");
+
+	g_isi_request_make(
+		client, msg, sizeof(msg), SIM_TIMEOUT,
+		uicc_application_list_resp, opaque);
+}
+
+static gboolean uicc_pin_enter_resp(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ofono_sim_local *local_sim =
+					(struct ofono_sim_local *) cbd->user;
+	struct ofono_error error;
+#ifdef STATUS_WORD_HANDLING
+	GIsiSubBlockIter iter;
+#endif
+	struct sim_data *sd =
+			ofono_sim_get_data((struct ofono_sim *) local_sim);
+
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d",
+			g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]));
+
+	if (msg[2] == UICC_STATUS_OK) {
+		sd->passwd_required = FALSE;
+		error.type = OFONO_ERROR_TYPE_NO_ERROR;
+		error.error = 0;
+		goto out;
+	}
+
+error:
+#ifdef STATUS_WORD_HANDLING
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_STATUS_WORD: {
+			uint16_t status;
+			g_isi_sb_iter_get_word(&iter, &status, 6);
+			DBG("APDU status word = %04X", status);
+
+			switch (status) {
+			case 0x6983:
+			case 0x9840:
+				DBG("Authentication method blocked");
+				update_locked_pin(local_sim,
+							UICC_PIN_UNBLOCK_NEEDED,
+							sd->current_pin_id);
+				break;
+			default:
+
+				if ((status & 0xfff0) == 0x63c0)
+					DBG("Attempts left %d", status & 0xf);
+
+				break;
+			}
+
+			break;
+		}
+		default:
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+#endif
+	error.type = OFONO_ERROR_TYPE_FAILURE;
+	error.error = 1;
+out:
+	cb(&error, cbd->data);
+	g_free(cbd);
+	return TRUE;
+}
+
+static void uicc_pin_enter(struct ofono_sim *sim, const char *passwd,
+				ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	sd->current_pin_id = sd->pin1_id; /* No way to enter PIN2 */
+	DBG("PIN=%s PINID=%02x", passwd, sd->current_pin_id);
+
+	if (cbd && sd) {
+		unsigned char pinlen = strlen(passwd);
+		unsigned char msg[] = {
+			UICC_PIN_REQ,
+			UICC_PIN_VERIFY,
+			sd->app_id,
+			0, /* Filler */
+			0, /* Filler */
+			0, /* Filler */
+			1, /* number of subblocks */
+		/* Subblock 1 */
+			UICC_SB_PIN >> 8,
+			UICC_SB_PIN & 0xff,
+			0,
+			16, /* Max length */
+			sd->current_pin_id, /* PIN id */
+			UICC_PIN_OLD, /* PIN qualifier */
+			pinlen, /* PIN length */
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0
+		};
+
+		if ((pinlen < 4) || (pinlen > 8))
+			goto error;
+
+		memmove(&msg[14], passwd, pinlen);
+
+		g_isi_request_make(sd->client, msg, sizeof(msg),
+					SIM_TIMEOUT, uicc_pin_enter_resp, cbd);
+		return;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+#ifdef PIN_PROMPT
+enum ofono_sim_password_type passwd_type_for_query =
+	OFONO_SIM_PASSWORD_SIM_PIN;
+
+static gboolean uicc_pin_prompt_resp(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_passwd_cb_t cb = cbd->cb;
+	struct ofono_sim_local *local_sim =
+					(struct ofono_sim_local *) cbd->user;
+	struct sim_data *sd =
+			ofono_sim_get_data((struct ofono_sim *)local_sim);
+
+	unsigned char lock_type = -1;
+	GIsiSubBlockIter iter;
+	uint8_t status = UICC_STATUS_UNKNOWN;
+	uint8_t pin_attempts = -1;
+	uint8_t puk_attempts = -1;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]));
+
+	if (msg[0] != UICC_PIN_RESP)
+		goto error;
+
+	if (msg[1] == UICC_PIN_PROMPT_VERIFY) {
+		sd->pin_state_received = TRUE;
+		status = msg[2];
+	} else if (msg[1] == UICC_PIN_INFO) {
+		if (msg[2] != UICC_STATUS_OK)
+			goto error;
+
+		sd->pin_state_received = TRUE;
+		g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+		while (g_isi_sb_iter_is_valid(&iter)) {
+			DBG("Sub-block %s",
+				uicc_subblock_name(g_isi_sb_iter_get_id(
+							&iter)));
+
+			switch (g_isi_sb_iter_get_id(&iter)) {
+			case UICC_SB_PIN_INFO:
+				g_isi_sb_iter_get_byte(&iter, &status, 4);
+				g_isi_sb_iter_get_byte(&iter,
+							&pin_attempts, 5);
+				g_isi_sb_iter_get_byte(&iter,
+							&puk_attempts, 6);
+				DBG("Status=%s, PIN attempts=%d, \
+					PUK attempts=%d",
+					uicc_status_name(status),
+					pin_attempts, puk_attempts);
+				break;
+			default:
+				break;
+			}
+
+			g_isi_sb_iter_next(&iter);
+		}
+	}
+
+	if ((status == UICC_STATUS_OK) ||
+		(status == UICC_STATUS_PIN_ENABLED)) {
+		/* PIN query on, indication should tell
+		 * if it is verified or not
+		 */
+		if (pin_attempts == 0) {
+			DBG("PIN blocked");
+			update_locked_pin(local_sim,
+					  UICC_PIN_UNBLOCK_NEEDED,
+						sd->current_pin_id);
+		} else {
+			DBG("PIN query enabled");
+			update_locked_pin(local_sim,
+					  UICC_PIN_VERIFY_NEEDED,
+						sd->current_pin_id);
+		}
+
+		lock_type = local_sim->pin_type;
+	} else if (status == UICC_STATUS_PIN_DISABLED) {
+		if (pin_attempts == 0) {
+			DBG("PIN blocked");
+			update_locked_pin(local_sim,
+					  UICC_PIN_UNBLOCK_NEEDED,
+						sd->current_pin_id);
+			lock_type = local_sim->pin_type;
+		} else {
+			DBG("PIN query disabled");
+			local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] =
+				FALSE;
+			local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN2] =
+				FALSE;
+			lock_type = OFONO_SIM_PASSWORD_NONE;
+		}
+	}
+
+	if (msg[1] == UICC_PIN_PROMPT_VERIFY) {
+		uicc_pin_prompt(cbd->user,
+				passwd_type_for_query,
+				cb,
+				cbd->data,
+				UICC_PIN_INFO);
+	}
+
+	CALLBACK_WITH_SUCCESS(cb, lock_type, cbd->data);
+	goto out;
+error:
+	DBG("PIN prompt verify failed");
+	CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void uicc_pin_prompt(struct ofono_sim *sim,
+				enum ofono_sim_password_type passwd_type,
+				ofono_sim_passwd_cb_t cb,
+				void *data,
+				uint8_t service)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	int8_t index;
+	sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
+	DBG("PINID = %02x", sd->current_pin_id);
+
+	if ((cbd) && (sd) && (sd->current_pin_id)) {
+		unsigned char msg[] = {
+			UICC_PIN_REQ,
+			service,
+			sd->app_id,
+			0, /*Filler*/
+			0, /*Filler*/
+			0, /*Filler*/
+			1, /*number of subblocks*/
+		/* Subblock 1 */
+			UICC_SB_PIN_REF >> 8,
+			UICC_SB_PIN_REF & 0xff,
+			0, /*Sub block length.*/
+			8,
+			sd->current_pin_id, /*PIN ID*/
+			0, /*Filler*/
+			0, /*Filler*/
+			0  /*Filler*/
+		};
+		g_isi_request_make(sd->client, msg, sizeof(msg),
+				   SIM_TIMEOUT, uicc_pin_prompt_resp, cbd);
+	} else {
+		DBG("PIN info query failed");
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+		g_free(cbd);
+	}
+}
+#endif
+
+static void uicc_passwd_state_query(struct ofono_sim *sim,
+					ofono_sim_passwd_cb_t cb,
+					void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct ofono_sim_local *local_sim = (struct ofono_sim_local *)sim;
+	if (sd->pin_state_received) {
+		int lock_type = OFONO_SIM_PASSWORD_NONE;
+
+		if (sd->passwd_required) {
+			/* These should be in priority order, highest last */
+			if (local_sim->locked_pins[
+				    OFONO_SIM_PASSWORD_SIM_PIN] == TRUE)
+				lock_type = OFONO_SIM_PASSWORD_SIM_PIN;
+
+			if (local_sim->locked_pins[
+				    OFONO_SIM_PASSWORD_SIM_PIN2] == TRUE)
+				lock_type = OFONO_SIM_PASSWORD_SIM_PIN2;
+
+			if (local_sim->locked_pins[
+				    OFONO_SIM_PASSWORD_PHNET_PIN] == TRUE)
+				lock_type = OFONO_SIM_PASSWORD_PHNET_PIN;
+
+			if (local_sim->locked_pins[
+				    OFONO_SIM_PASSWORD_SIM_PUK] == TRUE)
+				lock_type = OFONO_SIM_PASSWORD_SIM_PUK;
+
+			if (local_sim->locked_pins[
+				    OFONO_SIM_PASSWORD_SIM_PUK2] == TRUE)
+				lock_type = OFONO_SIM_PASSWORD_SIM_PUK2;
+
+			if (local_sim->locked_pins[
+				    OFONO_SIM_PASSWORD_PHNET_PUK] == TRUE)
+				lock_type = OFONO_SIM_PASSWORD_PHNET_PUK;
+		}
+
+		DBG("UICC lock type=%d", lock_type);
+		CALLBACK_WITH_SUCCESS(cb, lock_type, data);
+	} else {
+#ifdef PIN_PROMPT
+
+		if (sd->uicc_app_started) {
+			/* No indication received but UICC app is
+			 * started, let's query the state
+			 */
+			DBG("Querying PIN info");
+			uicc_pin_prompt(sim, passwd_type_for_query,
+					cb, data, UICC_PIN_PROMPT_VERIFY);
+			return;
+		}
+
+#endif
+		DBG("No UICC_PIN_IND received");
+		CALLBACK_WITH_FAILURE(cb, -1, data);
+	}
+}
+
+static gboolean uicc_pin_enable_resp(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ofono_sim_local *local_sim =
+					(struct ofono_sim_local *) cbd->user;
+	struct sim_data *sd =
+			ofono_sim_get_data((struct ofono_sim *) local_sim);
+
+	gboolean everything_ok = TRUE;
+#ifdef STATUS_WORD_HANDLING
+	GIsiSubBlockIter iter;
+#endif
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s, details=%d, len=%d",
+	    uicc_message_id_name(msg[0]),
+	    uicc_service_type_name(msg[1]),
+	    uicc_status_name(msg[2]), msg[3], (int) len);
+
+	if (msg[0] != UICC_PIN_RESP)
+		goto error;
+
+	if (msg[1] != UICC_PIN_DISABLE && msg[1] != UICC_PIN_ENABLE)
+		goto error;
+
+	if (msg[2] != UICC_STATUS_OK)
+		goto error;
+
+	if (everything_ok) {
+		DBG("PIN lock/unlock succeeded");
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		goto out;
+	}
+
+error:
+#ifdef STATUS_WORD_HANDLING
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+		    uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_STATUS_WORD: {
+			uint16_t status;
+			g_isi_sb_iter_get_word(&iter, &status, 6);
+			DBG("APDU status word = %04X", status);
+
+			switch (status) {
+			case 0x6983:
+			case 0x9840:
+				DBG("Authentication method blocked");
+				update_locked_pin(local_sim,
+						  UICC_PIN_UNBLOCK_NEEDED,
+						  sd->current_pin_id);
+				break;
+			default:
+
+				if ((status & 0xfff0) == 0x63c0)
+					DBG("Attempts left %d", status & 0xf);
+
+				break;
+			}
+		}
+		default:
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+#endif
+	DBG("PIN lock/unlock failed");
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void uicc_pin_enable(struct ofono_sim *sim,
+				enum ofono_sim_password_type passwd_type,
+				int enable, const char *passwd,
+				ofono_sim_lock_unlock_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	int8_t index;
+	unsigned char service = 0;
+	sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
+
+	DBG("Lock=%d, PIN code=%s, PIN ID =%d",
+	enable, passwd, sd->current_pin_id);
+	if (enable) {
+		DBG("Enabling PIN");
+		service = UICC_PIN_ENABLE;
+	} else {
+		DBG("Disabling PIN");
+		service = UICC_PIN_DISABLE;
+	}
+	if ((cbd) && (sd) && (sd->current_pin_id)) {
+
+		unsigned char pinlen = strlen(passwd);
+
+		unsigned char msg[] = {
+			UICC_PIN_REQ,
+			service,
+			sd->app_id,
+			0, /*Filler*/
+			0, /*Filler*/
+			0, /*Filler*/
+			1, /*number of subblocks*/
+		/* Subblock 1 */
+			UICC_SB_PIN >> 8,
+			UICC_SB_PIN & 0xff,
+			0,
+			16, /*Max length*/
+			sd->current_pin_id, /* PIN id */
+			UICC_PIN_OLD, /* PIN qualifier */
+			pinlen, /* PIN length */
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0
+		};
+
+		if ((pinlen < 4) || (pinlen > 8))
+			goto error;
+		memmove(&msg[14], passwd, pinlen);
+		g_isi_request_make(
+			sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+			uicc_pin_enable_resp, cbd);
+		return;
+	}
+
+error:
+	DBG("Error");
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+	return;
+}
+
+#ifdef QUERY_LOCKED
+static gboolean uicc_query_locked_resp(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_locked_cb_t cb = cbd->cb;
+	GIsiSubBlockIter iter;
+	int lock_status = -1;
+
+	if (msg[0] < 0xf0) {
+		DBG("%s, service %s, status %s, details=%d, state=%d",
+			uicc_message_id_name(msg[0]),
+			uicc_service_type_name(msg[1]),
+			uicc_status_name(msg[2]),
+			msg[3], msg[4]);
+
+		if ((msg[0] == UICC_PIN_RESP) &&
+		    (msg[1] == UICC_PIN_INFO) &&
+		    (msg[2] == UICC_STATUS_OK)) {
+			g_isi_sb_iter_init_full(&iter, msg,
+						len, 7, TRUE, msg[6]);
+
+			while (g_isi_sb_iter_is_valid(&iter)) {
+				DBG("Sub-block %s",
+				    uicc_subblock_name(
+						g_isi_sb_iter_get_id(&iter)));
+
+				switch (g_isi_sb_iter_get_id(&iter)) {
+				case UICC_SB_PIN_INFO:
+					uint8_t pin_status;
+					uint8_t pin_attempts;
+					uint8_t puk_attempts;
+					uint8_t passwd_type;
+					(void) g_isi_sb_iter_get_byte(&iter,
+									&pin_status, 4);
+					(void) g_isi_sb_iter_get_byte(&iter,
+									&pin_attempts, 5);
+					(void) g_isi_sb_iter_get_byte(&iter,
+								       &puk_attempts, 6);
+					DBG("PIN info, state = %d, \
+						PIN attemps = %d, \
+						PUK attempts = %d",
+						pin_status,
+						pin_attempts,
+						puk_attempts);
+					passwd_type =
+						((struct sim_passwd_to_pin_id *)
+						 cbd->user)->passwd_type;
+
+					if ((passwd_type ==
+							OFONO_SIM_PASSWORD_SIM_PUK) ||
+							(passwd_type ==
+							OFONO_SIM_PASSWORD_SIM_PUK2)) {
+						DBG("Checking PUK/PUK2 status");
+
+						if (pin_attempts == 0)
+							lock_status = 1;
+						else
+							lock_status = 0;
+					} else {
+						DBG("Checking PIN/PIN2 status");
+
+						if (pin_status ==
+								UICC_STATUS_PIN_ENABLED)
+							lock_status = 1;
+
+						if (pin_status ==
+								UICC_STATUS_PIN_DISABLED)
+							lock_status = 0;
+					}
+
+					break;
+				default:
+					break;
+				}
+
+				g_isi_sb_iter_next(&iter);
+			}
+		} else if ((msg[0] == UICC_SIMLOCK_RESP) &&
+				(msg[1] == UICC_SIMLOCK_ACTIVE) &&
+				(msg[2] == UICC_STATUS_OK)) {
+			if (msg[4] == UICC_SIMLOCK_STATUS_ACTIVE)
+				lock_status = 1;
+
+			if (msg[4] == UICC_SIMLOCK_STATUS_INACTIVE)
+				lock_status = 0;
+		} else
+			goto error;
+
+		DBG("Lock status = %d", lock_status);
+
+		if (cb)
+			CALLBACK_WITH_SUCCESS(cb, lock_status, cbd->data);
+
+		goto out;
+	} else {
+		DBG("COMMON_MESSAGE, submessage %02X", msg[1]);
+	}
+
+error:
+	DBG("Querying lock status failed");
+
+	if (cb)
+		CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void uicc_query_locked(struct ofono_sim *sim,
+				enum ofono_sim_password_type type,
+				ofono_sim_locked_cb_t cb,
+				void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	uint8_t index;
+
+	if (cbd && sd) {
+		sd->current_pin_id = get_pin_id(sd, type, &index);
+
+		if (!sd->current_pin_id) {
+			DBG("SIMlock type query");
+			unsigned char simlock_msg[] = {
+				UICC_SIMLOCK_REQ,
+				UICC_SIMLOCK_ACTIVE,
+				0,
+				0
+			};
+			g_isi_request_make(
+				sd->client, simlock_msg,
+				sizeof(simlock_msg), SIM_TIMEOUT,
+				uicc_query_locked_resp, cbd);
+			return;
+		} else {
+			cbd->user = (void *) &pin_ids[index];
+			DBG("PIN/PUK type lock query, PIN %d",
+						sd->current_pin_id);
+			unsigned char pin_puk_msg[] = {
+				UICC_PIN_REQ,
+				UICC_PIN_INFO,
+				sd->app_id,
+				0, /*Filler*/
+				0, /*Filler*/
+				0, /*Filler*/
+				1, /*number of subblocks*/
+			/* Subblock 1 */
+				UICC_SB_PIN_REF >> 8,
+				UICC_SB_PIN_REF & 0xff,
+				0, /*Sub block length.*/
+				8,
+				sd->current_pin_id, /*PIN ID*/
+				0, /*Filler*/
+				0, /*Filler*/
+				0  /*Filler*/
+			};
+			g_isi_request_make(
+				sd->client, pin_puk_msg,
+				sizeof(pin_puk_msg), SIM_TIMEOUT,
+				uicc_query_locked_resp, cbd);
+		}
+	} else {
+		DBG("Error");
+
+		if (cb)
+			CALLBACK_WITH_FAILURE(cb, -1, data);
+
+		g_free(cbd);
+		return;
+	}
+}
+#endif
+
+static gboolean uicc_pin_change_resp(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ofono_sim_local *local_sim =
+					(struct ofono_sim_local *) cbd->user;
+	struct sim_data *sd =
+			ofono_sim_get_data((struct ofono_sim *) local_sim);
+
+	gboolean everything_ok = TRUE;
+#ifdef STATUS_WORD_HANDLING
+	GIsiSubBlockIter iter;
+#endif
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s, details=%d, len=%d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]), (int) msg[3], (int) len);
+
+	if (msg[0] != UICC_PIN_RESP)
+		goto error;
+
+	if (msg[1] != UICC_PIN_CHANGE)
+		goto error;
+
+	if (msg[2] != UICC_STATUS_OK)
+		goto error;
+
+	if (everything_ok) {
+		DBG("PIN change succeeded");
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		goto out;
+	}
+
+error:
+#ifdef STATUS_WORD_HANDLING
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_STATUS_WORD: {
+			uint16_t status;
+			g_isi_sb_iter_get_word(&iter, &status, 6);
+			DBG("APDU status word = %04X", status);
+
+			switch (status) {
+			case 0x6983:
+			case 0x9840:
+				DBG("Authentication method blocked");
+				update_locked_pin(local_sim,
+					UICC_PIN_UNBLOCK_NEEDED,
+						sd->current_pin_id);
+				break;
+			default:
+
+				if ((status & 0xfff0) == 0x63c0)
+					DBG("Attempts left %d", status & 0xf);
+
+				break;
+			}
+
+			break;
+		}
+		default:
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+#endif
+	DBG("PIN change failed");
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void uicc_change_pin(struct ofono_sim *sim,
+				enum ofono_sim_password_type passwd_type,
+				const char *old,
+				const char *new,
+				ofono_sim_lock_unlock_cb_t cb,
+				void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	int8_t index;
+	sd->current_pin_id = get_pin_id(sd, passwd_type, &index);
+	DBG("old=%s, new=%s, PINID=%02x",
+		old, new, sd->current_pin_id);
+
+	if ((cbd) && (sd) && (sd->current_pin_id)) {
+		unsigned char service = UICC_PIN_CHANGE;
+		unsigned char oldlen = strlen(old);
+		unsigned char newlen = strlen(new);
+
+		unsigned char msg[] = {
+			UICC_PIN_REQ,
+			service,
+			sd->app_id,
+			0, /*Filler*/
+			0, /*Filler*/
+			0, /*Filler*/
+			2, /*number of subblocks*/
+		/* Subblock 1 */
+			UICC_SB_PIN >> 8,
+			UICC_SB_PIN & 0xff,
+			0,
+			16, /* Must be fixed */
+			sd->current_pin_id, /* PIN id */
+			UICC_PIN_OLD, /* PIN qualifier */
+			oldlen, /* PIN length */
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+		/* Subblock 2 */
+			UICC_SB_PIN >> 8,
+			UICC_SB_PIN & 0xff,
+			0,
+			/* Sub block length:
+			*  "header" size + 1 (=trailing filler) + PIN length */
+			16,
+			sd->current_pin_id, /* PIN id */
+			UICC_PIN_NEW, /* PIN qualifier */
+			newlen, /* PIN length */
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0
+		};
+
+		if ((oldlen < 4) || (oldlen > 8))
+			goto error;
+
+		if ((newlen < 4) || (newlen > 8))
+			goto error;
+
+		memmove(&msg[14], old, oldlen);
+		memmove(&msg[30], new, newlen);
+		g_isi_request_make(
+			sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+			uicc_pin_change_resp, cbd);
+		return;
+	}
+
+error:
+	DBG("Error");
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+	return;
+}
+
+static gboolean uicc_pin_send_puk_resp(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_lock_unlock_cb_t cb = cbd->cb;
+	struct ofono_sim_local *local_sim =
+					(struct ofono_sim_local *) cbd->user;
+	gboolean everything_ok = TRUE;
+#ifdef STATUS_WORD_HANDLING
+	GIsiSubBlockIter iter;
+#endif
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	DBG("%s, service %s, status %s, details=%d, len=%d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]),
+		uicc_status_name(msg[2]), (int) msg[3], (int) len);
+
+	if (msg[0] != UICC_PIN_RESP)
+		goto error;
+
+	if (msg[1] != UICC_PIN_UNBLOCK)
+		goto error;
+
+	if (msg[2] != UICC_STATUS_OK)
+		goto error;
+
+	if (everything_ok) {
+		DBG("PIN reset succeeded");
+		/* Only PIN1 can be reseted, turns PIN query on */
+		local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PIN] = TRUE;
+		local_sim->locked_pins[OFONO_SIM_PASSWORD_SIM_PUK] = FALSE;
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		goto out;
+	}
+
+error:
+#ifdef STATUS_WORD_HANDLING
+	g_isi_sb_iter_init_full(&iter, msg, len, 7, TRUE, msg[6]);
+
+	while (g_isi_sb_iter_is_valid(&iter)) {
+		DBG("Sub-block %s",
+			uicc_subblock_name(g_isi_sb_iter_get_id(&iter)));
+
+		switch (g_isi_sb_iter_get_id(&iter)) {
+		case UICC_SB_STATUS_WORD: {
+			uint16_t status;
+			g_isi_sb_iter_get_word(&iter, &status, 6);
+			DBG("APDU status word = %04X", status);
+
+			switch (status) {
+			case 0x6983:
+			case 0x9840:
+				DBG("Authentication method blocked");
+				break;
+			default:
+
+				if ((status & 0xfff0) == 0x63c0)
+					DBG("Attempts left %d", status & 0xf);
+
+				break;
+			}
+
+			break;
+		}
+		default:
+			break;
+		}
+
+		g_isi_sb_iter_next(&iter);
+	}
+
+#endif
+	DBG("PIN reset failed");
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+static void uicc_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 isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	sd->current_pin_id = sd->pin1_id; /* No way to reset PIN2 */
+	DBG("PUK=%s, PIN=%s, PINID=%02x", puk, passwd, sd->current_pin_id);
+
+	if (cbd && sd) {
+		unsigned char service = UICC_PIN_UNBLOCK;
+		unsigned char pinlen = strlen(passwd);
+
+		unsigned char msg[] = {
+			UICC_PIN_REQ,
+			service,
+			sd->app_id,
+			0, /*Filler*/
+			0, /*Filler*/
+			0, /*Filler*/
+			2, /*number of subblocks*/
+		/* Subblock 1*/
+			UICC_SB_PIN >> 8,
+			UICC_SB_PIN & 0xff,
+			0,
+			16, /*Must be fixed*/
+			sd->current_pin_id, /* PIN id*/
+			UICC_PIN_NEW, /* PIN qualifier*/
+			pinlen, /* PIN length*/
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+		/* Subblock 2*/
+			UICC_SB_PUK >> 8,
+			UICC_SB_PUK & 0xff,
+			0,
+			16, /*Sub block length*/
+			sd->current_pin_id, /* PIN id*/
+			8, /* PUK length*/
+			puk[0],
+			puk[1],
+			puk[2],
+			puk[3],
+			puk[4],
+			puk[5],
+			puk[6],
+			puk[7],
+			0,
+			0
+		};
+
+		if ((pinlen < 4) || (pinlen > 8))
+			goto error;
+
+		if (strlen(puk) != 8)
+			goto error;
+		memmove(&msg[14], passwd, pinlen);
+		g_isi_request_make(
+			sd->client, msg, sizeof(msg), SIM_TIMEOUT,
+			uicc_pin_send_puk_resp, cbd);
+		return;
+	}
+
+error:
+	DBG("PIN reset error");
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+	return;
+}
+
+static gboolean check_write_resp(const uint8_t *msg, size_t len,
+					struct isi_cb_data **_cbd)
+{
+	struct isi_cb_data *cbd = *_cbd;
+	struct ofono_sim *sim = cbd->user;
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	ofono_sim_write_cb_t cb = cbd->cb;
+	DBG("");
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(sd->client));
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(*_cbd);
+		*_cbd = NULL;
+		return TRUE;
+	}
+
+	if (len < 7 || msg[0] != UICC_APPL_CMD_RESP) {
+		DBG("Invalid response");
+		return FALSE;
+	}
+
+	if (msg[2] != UICC_STATUS_OK) {
+		DBG("Failed");
+		CALLBACK_WITH_FAILURE(cb, cbd->data);
+		g_free(*_cbd);
+		*_cbd = NULL;
+		return TRUE;
+	}
+
+	return TRUE;
+}
+
+#ifdef WRITE_FILE_TRANSPARENT
+static gboolean write_file_transparent_cb(GIsiClient *client,
+						const void *restrict data,
+						size_t len,
+						uint16_t object,
+						void *opaque)
+{
+	const uint8_t *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_write_cb_t cb = cbd->cb;
+	gboolean ret = check_write_resp(msg, len, &cbd);
+	DBG("");
+
+	if (ret && cbd) {
+		if (msg[1] != UICC_APPL_UPDATE_TRANSPARENT) {
+			DBG("Invalid response");
+			return FALSE;
+		}
+
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		g_free(cbd);
+		return TRUE;
+	}
+
+	return ret;
+}
+
+static void isi_write_file_transparent(struct ofono_sim *sim, int fileid,
+					int start, int length,
+					const unsigned char *value,
+					ofono_sim_write_cb_t cb,
+					void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+	int mf_path = 0, df1_path = 0, df2_path = 0;
+	unsigned char df_len = 0;
+	size_t  i = 0;
+
+	size_t sb_file_data_legth = (2 + 2 + 4 + length + 3) & ~3;
+	size_t fill_count = sb_file_data_legth - (2 + 2 + 4 + length);
+	uint8_t *fill_data = g_try_malloc0(fill_count);
+
+	DBG("");
+
+	if (!fill_data && fill_count > 0)
+		goto error;
+
+	for (i = 0; i < fill_count; i++)
+		fill_data[i] = 0x00;
+
+	if (!sd->app_id || !sd->client_id || !sd || !sd->client || !cbd) {
+		DBG("Parameter error");
+		goto error;
+	}
+
+	if (get_fileid_path(sim, &mf_path, &df1_path,
+			&df2_path, &df_len, fileid)) {
+		uint8_t msg[] = {
+			UICC_APPL_CMD_REQ,
+			UICC_APPL_UPDATE_TRANSPARENT,
+			sd->app_id,
+			UICC_SESSION_ID_NOT_USED,
+			0x00, 0x00, /* fillers */
+			0x04, /* nro of sub blocks */
+			/* 1st subblock */
+			UICC_SB_CLIENT >> 8,
+			UICC_SB_CLIENT & 0xFF,
+			0x00, 0x08, /* subblock length */
+			0x00, 0x00, 0x00, /* fillers */
+			sd->client_id,
+			/* 2nd subblock */
+			UICC_SB_TRANSPARENT >> 8,
+			UICC_SB_TRANSPARENT & 0xFF,
+			0x00, 0x08, /* sub block length */
+			start >> 8, /* file offset (0 == beginning) */
+			start & 0xFF,
+			0x00, 0x00, /* data amount, used only for reading */
+			/* 3th subblock */
+			UICC_SB_APPL_PATH >> 8,
+			UICC_SB_APPL_PATH & 0xFF,
+			0x00, 0x10, /* subblock length */
+			fileid >> 8, /* elementary file id */
+			fileid & 0xFF,
+			get_sfi(fileid),
+			0x00, /* filler */
+			df_len, /* path length */
+			0x00, /* filler */
+			mf_path >> 8, /* DF Path MF */
+			mf_path & 0xFF,
+			df1_path >> 8, /* DF Path */
+			df1_path & 0xFF,
+			df2_path >> 8, /* DF Path */
+			df2_path & 0xFF,
+			/* 4nd subblock */
+			UICC_SB_FILE_DATA >> 8,
+			UICC_SB_FILE_DATA & 0xFF,
+			sb_file_data_legth >> 8, /* subblock length */
+			sb_file_data_legth & 0xFF,
+			length >> 24, /* data length, need to be shifted*/
+			length >> 16,
+			length >> 8,
+			length & 0xFF,
+		};
+
+		struct iovec iov[3] = {
+			{ msg, sizeof(msg) },
+			{ (uint8_t *)value, length },
+			{ fill_data, fill_count },
+		};
+
+		if (g_isi_request_vmake(sd->client, iov, 3, SIM_TIMEOUT,
+					write_file_transparent_cb, cbd))
+			goto out;
+	}
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+
+	if (cbd)
+		g_free(cbd);
+
+out:
+
+	if (fill_data)
+		g_free(fill_data);
+
+	return;
+}
+#endif
+
+static gboolean write_file_linear_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const uint8_t *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_write_cb_t cb = cbd->cb;
+	gboolean ret = check_write_resp(msg, len, &cbd);
+	DBG("");
+
+	if (ret && cbd) {
+		if (msg[1] != UICC_APPL_UPDATE_LINEAR_FIXED) {
+			DBG("Invalid response");
+			return FALSE;
+		}
+
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		g_free(cbd);
+		return TRUE;
+	}
+
+	return ret;
+}
+
+static void isi_write_file_linear(struct ofono_sim *sim, int fileid,
+					int record, int length,
+					const unsigned char *value,
+					ofono_sim_write_cb_t cb,
+					void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+
+	int mf_path = 0;
+	int df1_path = 0;
+	int df2_path = 0;
+	unsigned char df_len = 0;
+	size_t i = 0;
+
+	size_t sb_file_data_legth = (2 + 2 + 4 + length + 3) & ~3;
+	size_t fill_count = sb_file_data_legth - (2 + 2 + 4 + length);
+	uint8_t *fill_data = g_try_malloc0(fill_count);
+	DBG("");
+
+	if (!fill_data && fill_count > 0)
+		goto error;
+
+	for (i = 0; i < fill_count; i++)
+		fill_data[i] = 0x00;
+
+	if (!sd->app_id || !sd->client_id || !sd || !sd->client || !cbd) {
+		DBG("Parameter error");
+		goto error;
+	}
+
+	if (get_fileid_path(sim, &mf_path, &df1_path,
+			&df2_path, &df_len, fileid)) {
+		uint8_t msg[] = {
+			UICC_APPL_CMD_REQ,
+			UICC_APPL_UPDATE_LINEAR_FIXED,
+			sd->app_id,
+			UICC_SESSION_ID_NOT_USED,
+			0x00, 0x00, /* fillers */
+			0x04, /* nro of sub blocks */
+			/* 1st subblock */
+			UICC_SB_CLIENT >> 8,
+			UICC_SB_CLIENT & 0xFF,
+			0x00, 0x08, /* subblock length */
+			0x00, 0x00, 0x00, /* fillers */
+			sd->client_id,
+			/* 2nd subblock */
+			UICC_SB_LINEAR_FIXED >> 8,
+			UICC_SB_LINEAR_FIXED & 0xFF,
+			0x00, 0x08, /* subblock length */
+			record, /* the record in the file*/
+			0x00, /* record offset (0 == beginning) */
+			0x00, /* data amount, used only for reading */
+			0x00, /* filler */
+			/* 3th subblock */
+			UICC_SB_APPL_PATH >> 8,
+			UICC_SB_APPL_PATH & 0xFF,
+			0x00, 0x10, /* subblock length */
+			fileid >> 8, /* elementary file id */
+			fileid & 0xFF,
+			get_sfi(fileid),
+			0x00, /* filler */
+			df_len, /* path length */
+			0x00, /* filler */
+			mf_path >> 8, /* DF Path MF */
+			mf_path & 0xFF,
+			df1_path >> 8, /* DF Path */
+			df1_path & 0xFF,
+			df2_path >> 8, /* DF Path */
+			df2_path & 0xFF,
+			/* 4nd subblock */
+			UICC_SB_FILE_DATA >> 8,
+			UICC_SB_FILE_DATA & 0xFF,
+			sb_file_data_legth >> 8, /* subblock length */
+			sb_file_data_legth & 0xFF,
+			length >> 24, /* data length, need to be shifted*/
+			length >> 16,
+			length >> 8,
+			length & 0xFF,
+		};
+
+		struct iovec iov[3] = {
+			{ msg, sizeof(msg) },
+			{ (uint8_t *)value, length },
+			{ fill_data, fill_count },
+		};
+
+		if (g_isi_request_vmake(sd->client, iov, 3, SIM_TIMEOUT,
+					write_file_linear_cb, cbd))
+			goto out;
+	}
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+
+	if (cbd)
+		g_free(cbd);
+
+out:
+
+	if (fill_data)
+		g_free(fill_data);
+
+	return;
+}
+
+#ifdef WRITE_FILE_CYCLIC
+static gboolean write_file_cyclic_cb(GIsiClient *client,
+					const void *restrict data,
+					size_t len,
+					uint16_t object,
+					void *opaque)
+{
+	const uint8_t *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_sim_write_cb_t cb = cbd->cb;
+	gboolean ret = check_write_resp(msg, len, &cbd);
+	DBG("");
+
+	if (ret && cbd) {
+		if (msg[1] != UICC_APPL_UPDATE_CYCLIC) {
+			DBG("Invalid response");
+			return FALSE;
+		}
+
+		CALLBACK_WITH_SUCCESS(cb, cbd->data);
+		g_free(cbd);
+		return TRUE;
+	}
+
+	return ret;
+}
+
+static void isi_write_file_cyclic(struct ofono_sim *sim,
+					int fileid,
+					int length,
+					const unsigned char *value,
+					ofono_sim_write_cb_t cb,
+					void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct isi_cb_data *cbd = isi_cb_data_new(sim, cb, data);
+
+	int mf_path = 0;
+	int df1_path = 0;
+	int df2_path = 0;
+	unsigned char df_len = 0;
+	size_t i = 0;
+	size_t sb_file_data_legth = (2 + 2 + 4 + length + 3) & ~3;
+	size_t fill_count = sb_file_data_legth - (2 + 2 + 4 + length);
+	uint8_t *fill_data = g_try_malloc0(fill_count);
+
+	if (!fill_data && fill_count > 0)
+		goto error;
+
+	for (i = 0; i < fill_count; i++)
+		fill_data[i] = 0x00;
+
+	if (!sd->app_id || !sd->client_id || !sd || !sd->client || !cbd) {
+		DBG("Parameter error");
+		goto error;
+	}
+
+	if (get_fileid_path(sim, &mf_path, &df1_path,
+			&df2_path, &df_len, fileid)) {
+		uint8_t msg[] = {
+			UICC_APPL_CMD_REQ,
+			UICC_APPL_UPDATE_CYCLIC,
+			sd->app_id,
+			UICC_SESSION_ID_NOT_USED,
+			0x00, 0x00, /* fillers */
+			0x04, /* nro of sub blocks */
+			/* 1st subblock */
+			UICC_SB_CLIENT >> 8,
+			UICC_SB_CLIENT & 0xFF,
+			0x00, 0x08, /* subblock length */
+			0x00, 0x00, 0x00, /* fillers */
+			sd->client_id,
+			/* 2nd subblock */
+			UICC_SB_CYCLIC >> 8,
+			UICC_SB_CYCLIC & 0xFF,
+			0x00, 0x08, /* sub block length */
+			0x01, /* record, write is allowed only to first */
+			0x00, /* record offset (0 == beginning) */
+			0x00, 0x00, /* data amount, used only for reading */
+			0x00, /* filler */
+			/* 3th subblock */
+			UICC_SB_APPL_PATH >> 8,
+			UICC_SB_APPL_PATH & 0xFF,
+			0x00, 0x10, /* subblock length */
+			fileid >> 8, /* elementary file id */
+			fileid & 0xFF,
+			get_sfi(fileid),
+			0x00, /* filler */
+			df_len, /* path length */
+			0x00, /* filler */
+			mf_path >> 8, /* DF Path MF */
+			mf_path & 0xFF,
+			df1_path >> 8, /* DF Path */
+			df1_path & 0xFF,
+			df2_path >> 8, /* DF Path */
+			df2_path & 0xFF,
+			/* 4nd subblock */
+			UICC_SB_FILE_DATA >> 8,
+			UICC_SB_FILE_DATA & 0xFF,
+			sb_file_data_legth >> 8, /* subblock length */
+			sb_file_data_legth & 0xFF,
+			length >> 24, /* data length, need to be shifted*/
+			length >> 16,
+			length >> 8,
+			length & 0xFF,
+		};
+
+		struct iovec iov[3] = {
+			{ msg, sizeof(msg) },
+			{ (uint8_t *)value, length + fill_count },
+			{ fill_data, fill_count },
+		};
+
+		if (g_isi_request_vmake(sd->client, iov, 3, SIM_TIMEOUT,
+					write_file_cyclic_cb, cbd))
+			goto out;
+	}
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+
+	if (cbd)
+		g_free(cbd);
+
+out:
+
+	if (fill_data)
+		g_free(fill_data);
+
+	return;
+}
+#endif
+
+static void uicc_ind_handler(GIsiClient *client, const void *restrict data,
+				size_t len, uint16_t object, void *opaque)
+{
+	struct ofono_sim *sim = opaque;
+	const unsigned char *msg = data;
+	struct sim_data *sd = ofono_sim_get_data(sim);;
+
+	DBG("%s, service %s, card/PIN type=%d",
+		uicc_message_id_name(msg[0]),
+		uicc_service_type_name(msg[1]), msg[2]);
+
+	switch (msg[0]) {
+
+	case UICC_CARD_IND:
+		ofono_sim_inserted_notify(sim, TRUE);
+
+		if ((msg[1] == UICC_CARD_READY) && (!sd->uicc_app_started)) {
+			DBG("UICC_CARD_IND activation");
+			uicc_application_list_req(client, sim);
+		}
+		break;
+	case UICC_PIN_IND:
+		sd->pin_state_received = TRUE;
+		sd->passwd_required = FALSE;
+
+		switch (msg[1]) {
+		case UICC_PIN_VERIFY_NEEDED:
+			update_locked_pin((struct ofono_sim_local *)sim,
+						UICC_PIN_VERIFY_NEEDED, msg[2]);
+			break;
+		case UICC_PIN_UNBLOCK_NEEDED:
+			update_locked_pin((struct ofono_sim_local *)sim,
+						UICC_PIN_UNBLOCK_NEEDED, msg[2]);
+			break;
+		case UICC_PIN_PERMANENTLY_BLOCKED:
+		case UICC_PIN_VERIFIED:
+		default:
+			break;
+		}
+
+		break;
+	case UICC_IND:
+		DBG("UICC IND RECEIVED");
+
+		if (msg[1] == UICC_START_UP_COMPLETE)
+			sd->passwd_required = FALSE;
+
+		break;
+	default:
+		break;
+	}
+}
+
+static void uicc_reachable_cb(GIsiClient *client, gboolean alive,
+				uint16_t object, void *opaque)
+{
+	struct ofono_sim *sim = opaque;
+	struct sim_data *sd = ofono_sim_get_data(sim);;
+
+	if (!alive) {
+		DBG("SIM client: %s", strerror(-g_isi_client_error(client)));
+		ofono_sim_remove(sim);
+	} else {
+		DBG("%s (v%03d.%03d) reachable",
+			pn_resource_name(g_isi_client_resource(client)),
+			g_isi_version_major(client),
+			g_isi_version_minor(client));
+		g_isi_subscribe(client, UICC_IND, uicc_ind_handler, opaque);
+		g_isi_subscribe(client, UICC_CARD_IND,
+				uicc_ind_handler, opaque);
+		g_isi_subscribe(client, UICC_PIN_IND,
+				uicc_ind_handler, opaque);
+		g_isi_subscribe(client, UICC_APPLICATION_IND,
+				uicc_ind_handler, opaque);
+		if (!sd->uicc_app_started) {
+			DBG("Let's check if we have UICC applications");
+			uicc_application_list_req(client, sim);
+		}
+	}
+}
+
+static int uicc_probe(struct ofono_sim *sim, unsigned int vendor,
+			void *user)
+{
+	GIsiModem *idx = user;
+	struct sim_data *sd = g_try_new0(struct sim_data, 1);
+	int ret = 0;
+
+	if (!sd)
+		ret = -ENOMEM;
+
+	if (!ret) {
+		sd->client = get_pn_uicc_client(idx, PN_UICC);
+
+		if (!sd->client)
+			ret = -ENOMEM;
+
+		sd->uicc_app_started = FALSE;
+		sd->pin_state_received = FALSE;
+		sd->passwd_required = TRUE;
+		sd->current_pin_id = 0x01;
+		sd->pin1_id = 0x01;
+		sd->pin2_id = 0x81;
+
+		uicc_sim = sim;
+		ofono_sim_set_data(sim, sd);
+	} else
+		g_free(sd);
+
+	if (!ret && sd->client)
+		g_isi_verify(sd->client, uicc_reachable_cb, sim);
+
+	return ret;
+}
+
+static void isi_uicc_remove(struct ofono_sim *sim)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+
+	DBG("");
+
+	if (!sd)
+		return;
+
+	sd->uicc_app_started = FALSE;
+	sd->pin_state_received = FALSE;
+	sd->passwd_required = TRUE;
+
+	pn_uicc_client_destroy(sd->client);
+
+	ofono_sim_set_data(sim, NULL);
+
+	g_free(sd);
+}
+
+static struct ofono_sim_driver driver = {
+	.name			= "isimodem25",
+	.probe			= uicc_probe,
+	.remove			= isi_uicc_remove,
+	.read_file_info		= isi_read_file_info,
+	.read_file_transparent	= isi_read_file_transparent,
+	.read_file_linear	= isi_read_file_linear_fixed,
+#ifdef READ_FILE_CYCLIC
+	.read_file_cyclic	= isi_read_file_cyclic,
+#else
+	.read_file_cyclic	= NULL,
+#endif
+#ifdef WRITE_FILE_TRANSPARENT
+	.write_file_transparent	= isi_write_file_transparent,
+#else
+	.write_file_transparent	= NULL,
+#endif
+	.write_file_linear	= isi_write_file_linear,
+#ifdef WRITE_FILE_CYCLIC
+	.write_file_cyclic	= isi_write_file_cyclic,
+#else
+	.write_file_cyclic	= NULL,
+#endif
+	.read_imsi		= uicc_read_imsi_req,
+	.query_passwd_state	= uicc_passwd_state_query,
+	.send_passwd		= uicc_pin_enter,
+	.reset_passwd		= uicc_pin_send_puk,
+	.change_passwd		= uicc_change_pin,
+	.lock			= uicc_pin_enable,
+#ifdef QUERY_LOCKED
+	.query_locked		= uicc_query_locked
+#else
+	.query_locked		= NULL
+#endif
+};
+
+struct ofono_sim_driver *get_sim_driver_func()
+{
+	return &driver;
+}
+
+void isi_sim_init()
+{
+	uicc_sim = NULL;
+	pn_uicc_client = NULL;
+	uicc_users = 0;
+	ofono_sim_driver_register(&driver);
+}
+
+void isi_sim_exit()
+{
+	ofono_sim_driver_unregister(&driver);
+}
+
+GIsiClient *get_pn_uicc_client(GIsiModem *modem, uint8_t resource)
+{
+	if (!pn_uicc_client)
+		pn_uicc_client = g_isi_client_create(modem, resource);
+
+	uicc_users++;
+	return pn_uicc_client;
+}
+
+void pn_uicc_client_destroy(GIsiClient *client)
+{
+	if (uicc_users > 0)
+		uicc_users--;
+	if (!uicc_users) {
+		if (pn_uicc_client) {
+			g_isi_client_destroy(client);
+			pn_uicc_client = NULL;
+		}
+	}
+}
diff --git a/drivers/isimodem2.5/uicc.h b/drivers/isimodem2.5/uicc.h
new file mode 100644
index 0000000..84e4eee
--- /dev/null
+++ b/drivers/isimodem2.5/uicc.h
@@ -0,0 +1,253 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_UICC_H
+#define __ISIMODEM25_UICC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PN_UICC 0x8C
+
+#define UICC_APPL_ID_UNKNOWN			0x00
+#define UICC_SFI_NOT_PRESENT			0x00
+#define UICC_SESSION_ID_NOT_USED		0x00
+
+enum uicc_status {
+	UICC_STATUS_OK =			0x00,
+	UICC_STATUS_FAIL =			0x01,
+	UICC_STATUS_UNKNOWN =			0x02,
+	UICC_STATUS_NOT_READY =			0x10,
+	UICC_STATUS_START_UP_COMPLETED =	0x11,
+	UICC_STATUS_SHUTTING_DOWN =		0x12,
+	UICC_STATUS_CARD_NOT_READY =		0x20,
+	UICC_STATUS_CARD_READY =		0x21,
+	UICC_STATUS_CARD_DISCONNECTED =		0x22,
+	UICC_STATUS_CARD_NOT_PRESENT =		0x23,
+	UICC_STATUS_CARD_REJECTED =		0x24,
+	UICC_STATUS_APPL_ACTIVE =		0x30,
+	UICC_STATUS_APPL_NOT_ACTIVE =		0x31,
+	UICC_STATUS_PIN_ENABLED =		0x40,
+	UICC_STATUS_PIN_DISABLED =		0x41
+};
+
+enum uicc_subblock {
+	UICC_SB_SHUT_DOWN_CONFIG =		0x0023,
+	UICC_SB_CARD_STATUS =			0x0001,
+	UICC_SB_CARD_INFO =			0x0024,
+	UICC_SB_CARD_REJECT_CAUSE =		0x0025,
+	UICC_SB_CLIENT =			0x001F,
+	UICC_SB_APPL_DATA_OBJECT =		0x0002,
+	UICC_SB_APPLICATION =			0x0003,
+	UICC_SB_APPL_INFO =			0x0004,
+	UICC_SB_APPL_STATUS =			0x0005,
+	UICC_SB_FCP =				0x0007,
+	UICC_SB_FCI =				0x001C,
+	UICC_SB_CHV =				0x001B,
+	UICC_SB_PIN =				0x0008,
+	UICC_SB_PIN_REF =			0x0009,
+	UICC_SB_PUK =				0x000A,
+	UICC_SB_PIN_SUBST =			0x000B,
+	UICC_SB_PIN_INFO =			0x000C,
+	UICC_SB_APPL_PATH =			0x000D,
+	UICC_SB_SESSION =			0x000E,
+	UICC_SB_FILE_DATA =			0x000F,
+	UICC_SB_APDU =				0x0014,
+	UICC_SB_TRANSPARENT_READ =		0x0010,
+	UICC_SB_TRANSPARENT_UPDATE =		0x0011,
+	UICC_SB_TRANSPARENT =			0x0012,
+	UICC_SB_LINEAR_FIXED =			0x0013,
+	UICC_SB_CYCLIC =			0x0026,
+	UICC_SB_TERMINAL_PROFILE =		0x0015,
+	UICC_SB_TERMINAL_RESPONSE =		0x001D,
+	UICC_SB_ENVELOPE =			0x0021,
+	UICC_SB_POLLING_SET =			0x0016,
+	UICC_SB_REFRESH =			0x0017,
+	UICC_SB_AID =				0x0006,
+	UICC_SB_REFRESH_RESULT =		0x0018,
+	UICC_SB_APDU_ACTIONS =			0x0019,
+	UICC_SB_OBJECT_ID =			0x001A,
+	UICC_SB_STATUS_WORD =			0x0020,
+	UICC_SB_APDU_SAP_INFO =			0x0022,
+	UICC_SB_ACCESS_MODE =			0x0027,
+	UICC_SB_RESP_INFO =			0x0028,
+	UICC_SB_APDU_SAP_CONFIG =		0x0029
+
+};
+
+enum uicc_message_id {
+	UICC_REQ =				0x00,
+	UICC_RESP =				0x01,
+	UICC_IND =				0x02,
+	UICC_CARD_REQ =				0x03,
+	UICC_CARD_RESP =			0x04,
+	UICC_CARD_IND =				0x05,
+	UICC_APPLICATION_REQ =			0x06,
+	UICC_APPLICATION_RESP =			0x07,
+	UICC_APPLICATION_IND =			0x08,
+	UICC_PIN_REQ =				0x09,
+	UICC_PIN_RESP =				0x0A,
+	UICC_PIN_IND =				0x0B,
+	UICC_APPL_CMD_REQ =			0x0C,
+	UICC_APPL_CMD_RESP =			0x0D,
+	UICC_APPL_CMD_IND =			0x0E,
+	UICC_CONNECTOR_REQ =			0x0F,
+	UICC_CONNECTOR_RESP =			0x10,
+	UICC_CAT_REQ =				0x12,
+	UICC_CAT_RESP =				0x13,
+	UICC_CAT_IND =				0x14,
+	UICC_APDU_REQ =				0x15,
+	UICC_APDU_RESP =			0x16,
+	UICC_APDU_RESET_IND =			0x17,
+	UICC_REFRESH_REQ =			0x18,
+	UICC_REFRESH_RESP =			0x19,
+	UICC_REFRESH_IND =			0x1A,
+	UICC_SIMLOCK_REQ =			0x1B,
+	UICC_SIMLOCK_RESP =			0x1C,
+	UICC_APDU_SAP_REQ =			0x1E,
+	UICC_APDU_SAP_RESP =			0x1F,
+	UICC_APDU_SAP_IND =			0x20,
+	UICC_PWR_CTRL_REQ =			0x21,
+	UICC_PWR_CTRL_RESP =			0x22,
+	UICC_PWR_CTRL_IND =			0x23
+};
+
+enum uicc_service_type {
+	UICC_APPL_LIST =			0x01,
+	UICC_APPL_HOST_ACTIVATE =		0x03,
+	UICC_APPL_START_UP_COMPLETE =		0x05,
+	UICC_APPL_SHUT_DOWN_INITIATED =		0x06,
+	UICC_APPL_STATUS_GET =			0x07,
+	UICC_APPL_HOST_DEACTIVATE =		0x09,
+	UICC_PIN_VERIFY =			0x11,
+	UICC_PIN_UNBLOCK =			0x12,
+	UICC_PIN_DISABLE =			0x13,
+	UICC_PIN_ENABLE =			0x14,
+	UICC_PIN_CHANGE =			0x15,
+	UICC_PIN_SUBSTITUTE =			0x16,
+	UICC_PIN_INFO =				0x17,
+	UICC_PIN_PROMPT_VERIFY =		0x18,
+	UICC_APPL_READ_TRANSPARENT =		0x21,
+	UICC_APPL_UPDATE_TRANSPARENT =		0x22,
+	UICC_APPL_READ_LINEAR_FIXED =		0x23,
+	UICC_APPL_UPDATE_LINEAR_FIXED =		0x24,
+	UICC_APPL_FILE_INFO =			0x25,
+	UICC_APPL_APDU_SEND =			0x26,
+	UICC_APPL_CLEAR_CACHE =			0x27,
+	UICC_APPL_SESSION_START	=		0x28,
+	UICC_APPL_SESSION_END =			0x29,
+	UICC_APPL_READ_CYCLIC =			0x2A,
+	UICC_APPL_UPDATE_CYCLIC =		0x2B,
+	UICC_CONNECT =				0x31,
+	UICC_DISCONNECT =			0x32,
+	UICC_RECONNECT =			0x33,
+	UICC_CAT_ENABLE =			0x41,
+	UICC_CAT_DISABLE =			0x42,
+	UICC_CAT_TERMINAL_PROFILE =		0x43,
+	UICC_CAT_TERMINAL_RESPONSE =		0x44,
+	UICC_CAT_ENVELOPE =			0x45,
+	UICC_CAT_POLLING_SET =			0x46,
+	UICC_CAT_REFRESH =			0x47,
+	UICC_CAT_POLL =				0x48,
+	UICC_APDU_SEND =			0x51,
+	UICC_APDU_ATR_GET =			0x52,
+	UICC_APDU_CONTROL =			0x53,
+	UICC_REFRESH_STATUS =			0x61,
+	UICC_APPL_TERMINATED =			0x71,
+	UICC_APPL_RECOVERED =			0x72,
+	UICC_APPL_ACTIVATED =			0x75,
+	UICC_PIN_VERIFY_NEEDED =		0x81,
+	UICC_PIN_UNBLOCK_NEEDED =		0x82,
+	UICC_PIN_PERMANENTLY_BLOCKED =		0x83,
+	UICC_PIN_VERIFIED =			0x84,
+	UICC_CAT_FETCHED_CMD =			0x91,
+	UICC_CAT_NOT_SUPPORTED =		0x92,
+	UICC_CAT_REG_FAILED =			0x93,
+	UICC_CAT_REG_OK =			0x94,
+	UICC_REFRESH_PERMISSION =		0xA1,
+	UICC_REFRESH_STARTING =			0xA2,
+	UICC_REFRESH_CANCELLED =		0xA3,
+	UICC_REFRESH_NOW =			0xA4,
+	UICC_START_UP_COMPLETE =		0xB0,
+	UICC_STATUS_GET =			0xB1,
+	UICC_READY =				0xB2,
+	UICC_READY_FOR_ACTIVATION =		0xB3,
+	UICC_INITIALIZED =			0xB4,
+	UICC_SHUTTING_DOWN =			0xB5,
+	UICC_SHUT_DOWN_CONFIG =			0xB6,
+	UICC_ERROR =				0xB7,
+	UICC_CARD_DISCONNECTED =		0xC0,
+	UICC_CARD_REMOVED =			0xC1,
+	UICC_CARD_NOT_PRESENT =			0xC2,
+	UICC_CARD_READY =			0xC4,
+	UICC_CARD_STATUS_GET =			0xC5,
+	UICC_CARD_REJECTED =			0xC8,
+	UICC_CARD_INFO_GET =			0xC9,
+	UICC_SIMLOCK_ACTIVE =			0xD0,
+	UICC_APDU_SAP_ACTIVATE =		0xE1,
+	UICC_APDU_SAP_DEACTIVATE =		0xE2,
+	UICC_APDU_SAP_ATR_GET =			0xE3,
+	UICC_APDU_SAP_COLD_RESET =		0xE4,
+	UICC_APDU_SAP_WARM_RESET =		0xE5,
+	UICC_APDU_SAP_APDU_SEND =		0xE6,
+	UICC_APDU_SAP_RECOVERY =		0xE7,
+	UICC_APDU_SAP_CONFIG_GET =		0xE8,
+	UICC_PWR_CTRL_ENABLE =			0xF1,
+	UICC_PWR_CTRL_DISABLE =			0xF2,
+	UICC_PWR_CTRL_WAIT =			0xF3,
+	UICC_PWR_CTRL_PROCEED =			0xF4,
+	UICC_PWR_CTRL_PERMISSION =		0xFA
+};
+
+enum uicc_appl_type_table {
+	UICC_APPL_TYPE_UNKNOWN =		0x00,
+	UICC_APPL_TYPE_ICC_SIM =		0x01,
+	UICC_APPL_TYPE_UICC_USIM =		0x02
+};
+enum uicc_pin_qualifier {
+	UICC_PIN_NEW =				0x01,
+	UICC_PIN_OLD =				0x02
+};
+enum uicc_appl_start_up_type {
+	UICC_APPL_START_UP_NO_INIT_PROC =	0x00,
+	UICC_APPL_START_UP_INIT_PROC =		0x01
+};
+enum uicc_card_type {
+	UICC_CARD_TYPE_ICC =			0x01,
+	UICC_CARD_TYPE_UICC =			0x02
+};
+enum uicc_details {
+	UICC_NO_DETAILS =			0x00,
+	UICC_INVALID_PARAMETERS =		0x01,
+	UICC_FILE_NOT_FOUND =			0x02
+};
+enum uicc_simlock_status {
+	UICC_SIMLOCK_STATUS_ACTIVE =		0x01,
+	UICC_SIMLOCK_STATUS_INACTIVE =		0x02
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __ISIMODEM25_UICC_H */
diff --git a/drivers/isimodem2.5/uicc_interface.h b/drivers/isimodem2.5/uicc_interface.h
new file mode 100644
index 0000000..4b70fb7
--- /dev/null
+++ b/drivers/isimodem2.5/uicc_interface.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 __ISIMODEM25_UICC_INTERFACE_H
+#define __ISIMODEM25_UICC_INTERFACE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int get_app_id();
+int get_app_type();
+int get_client_id();
+GIsiClient *read_pn_uicc_client(); /* Only returns the exisisting client */
+GIsiClient *get_pn_uicc_client(GIsiModem *modem, uint8_t resource);
+void pn_uicc_client_destroy(GIsiClient *client);
+struct ofono_sim_driver *get_sim_driver_func();
+struct ofono_sim *get_sim();
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __ISIMODEM25_UICC_INTERFACE_H */
diff --git a/drivers/isimodem2.5/ussd.c b/drivers/isimodem2.5/ussd.c
new file mode 100644
index 0000000..9fd19a5
--- /dev/null
+++ b/drivers/isimodem2.5/ussd.c
@@ -0,0 +1,341 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+
+#include <gisi/client.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/ussd.h>
+
+#include <glib.h>
+
+#include "debug.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "smsutil.h"
+#include "ss.h"
+#include "util.h"
+
+struct ussd_data {
+	GIsiClient *client;
+};
+
+/**
+ * Convert type to status
+ * @param type
+ */
+static inline int isi_type_to_status(uint8_t type)
+{
+	switch (type) {
+	case SS_GSM_USSD_MT_REPLY:
+		return OFONO_USSD_STATUS_LOCAL_CLIENT_RESPONDED;
+	case SS_GSM_USSD_COMMAND:
+		return OFONO_USSD_STATUS_ACTION_REQUIRED;
+	case SS_GSM_USSD_NOTIFY:
+		return OFONO_USSD_STATUS_NOTIFY;
+	case SS_GSM_USSD_END:
+		return OFONO_USSD_STATUS_TERMINATED;
+	case SS_GSM_USSD_REQUEST:
+	default:
+		return OFONO_USSD_STATUS_NOT_SUPPORTED;
+	}
+}
+
+/**
+ * Parse ussd
+ * @param ussd
+ * @param restrict_data
+ * @param len
+ */
+static void ussd_parse(struct ofono_ussd *ussd, const void *restrict data,
+	    size_t len)
+{
+	const unsigned char *msg = data;
+	int status = OFONO_USSD_STATUS_NOT_SUPPORTED;
+
+	if (!msg || len < 4)
+		ofono_ussd_notify(ussd, status, 0, NULL, 0);
+
+	status = isi_type_to_status(msg[2]);
+
+	if (msg[3] == 0 || (size_t)(msg[3] + 4) > len)
+		ofono_ussd_notify(ussd, status, msg[1], msg + 4, msg[3]);
+}
+
+/**
+ * Callback for ussd send response
+ * @param client
+ * @param restrict_data
+ * @param len
+ * @param object
+ * @param opaque
+ */
+static gboolean ussd_send_resp_cb(GIsiClient *client,
+					const void *restrict data, size_t len,
+					uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_ussd_cb_t cb = (cbd) ? cbd->cb : NULL;
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	if (!cbd || !cb)
+		goto error;
+
+	DBG("%s", ss_message_id_name(msg[0]));
+
+	if (len < 3)
+		return FALSE;
+
+	if (msg[0] == SS_SERVICE_FAILED_RESP)
+		goto error;
+
+	if (len < 4 || msg[0] != SS_GSM_USSD_SEND_RESP)
+		return FALSE;
+
+	CALLBACK_WITH_SUCCESS(cb, cbd->data);
+	ussd_parse(cbd->user, data, len);
+	goto out;
+error:
+	CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+	g_free(cbd);
+	return TRUE;
+}
+
+/**
+ * Send a USSD ISI request
+ * @param ussd
+ * @param str
+ * @param cb
+ * @param data
+ */
+static void isi_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 isi_cb_data *cbd = isi_cb_data_new(ussd, cb, data);
+	uint8_t filled_len = (4 + len + 3) & ~3;
+	const uint8_t padding_bytes[] = {0, 0, 0, 0, 0, 0, 0, 0};
+	const uint8_t msg[] = {
+		SS_GSM_USSD_SEND_REQ,
+		SS_GSM_USSD_COMMAND,
+		0x01, /* subblock count */
+		/* Sub-block 1*/
+		SS_GSM_USSD_STRING,
+		filled_len, /* subblock length */
+		dcs, /* DCS */
+		len, /* string length */
+		/* USSD string goes here */
+	};
+	const struct iovec iov[3] = {
+		{ (uint8_t *) msg, sizeof(msg) },
+		{ (uint8_t *)pdu, len },
+		{ (uint8_t *) padding_bytes, (filled_len - len - 4) }
+	};
+	DBG("");
+	DBG("len=%d", (int) len);
+
+	if (!cbd || !ud)
+		goto error;
+
+	if (g_isi_request_vmake(ud->client, (struct iovec *) iov, 3,
+		SS_TIMEOUT, ussd_send_resp_cb, data))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+/**
+  * Cancel USSD ISI request
+  * @param ussd
+  * @param cb
+  * @param data
+  */
+static void isi_cancel(struct ofono_ussd *ussd,
+			ofono_ussd_cb_t cb, void *data)
+{
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+	struct isi_cb_data *cbd = isi_cb_data_new(ussd, cb, data);
+	const unsigned char msg[] = {
+		SS_GSM_USSD_SEND_REQ,
+		SS_GSM_USSD_END,
+		0x00 /* subblock count */
+	};
+	DBG("");
+
+	if (!cbd || !ud)
+		goto error;
+
+	if (g_isi_request_make(ud->client, msg, sizeof(msg), SS_TIMEOUT,
+				ussd_send_resp_cb, cbd))
+		return;
+
+error:
+	CALLBACK_WITH_FAILURE(cb, data);
+	g_free(cbd);
+}
+
+/**
+ * USSD indication callback
+ * @param client
+ * @param restrict_data
+ * @param len
+ * @param object
+ * @param opaque
+ */
+static void ussd_ind_cb(GIsiClient *client,
+			const void *restrict data, size_t len,
+			uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct ofono_ussd *ussd = opaque;
+	DBG("%s", ss_message_id_name(msg[0]));
+
+	if (!msg || len < 4 || msg[0] != SS_GSM_USSD_RECEIVE_IND)
+		return;
+
+	ussd_parse(ussd, data, len);
+}
+
+/**
+  * Subscribe to USSD
+  * @param user
+  */
+static gboolean isi_ussd_register(gpointer user)
+{
+	struct ofono_ussd *ussd = user;
+	struct ussd_data *ud = ofono_ussd_get_data(ussd);
+	g_isi_subscribe(ud->client, SS_GSM_USSD_RECEIVE_IND, ussd_ind_cb, ussd);
+	ofono_ussd_register(ussd);
+	return FALSE;
+}
+
+/**
+  * USSD reachable callback
+  * @param client
+  * @param alive
+  * @param object
+  * @param opaque
+  */
+static void ussd_reachable_cb(GIsiClient *client,
+				gboolean alive, uint16_t object,
+				void *opaque)
+{
+	struct ofono_ussd *ussd = opaque;
+
+	if (!alive) {
+		DBG("Unable to bootstrap ussd driver");
+		return;
+	}
+
+	DBG("%s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_idle_add(isi_ussd_register, ussd);
+}
+
+/**
+ * Probe USSD server
+ * @param ussd
+ * @param vendor
+ * @param user
+ */
+static int isi_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
+				void *user)
+{
+	GIsiModem *idx = user;
+	struct ussd_data *ud = g_try_new0(struct ussd_data, 1);
+
+	if (!ud)
+		return -ENOMEM;
+
+	ud->client = get_pn_ss_client(idx, PN_SS);
+
+	if (!ud->client) {
+		g_free(ud);
+		return -ENOMEM;
+	}
+
+	ofono_ussd_set_data(ussd, ud);
+	g_isi_verify(ud->client, ussd_reachable_cb, ussd);
+	return 0;
+}
+
+/**
+ * Remove USSD
+ * @param ussd
+ */
+static void isi_ussd_remove(struct ofono_ussd *ussd)
+{
+	struct ussd_data *data = ofono_ussd_get_data(ussd);
+
+	if (!data)
+		return;
+
+	ofono_ussd_set_data(ussd, NULL);
+	pn_ss_client_destroy(data->client);
+	g_free(data);
+}
+
+static struct ofono_ussd_driver driver = {
+	.name		= "isimodem25",
+	.probe		= isi_ussd_probe,
+	.remove		= isi_ussd_remove,
+	.request	= isi_request,
+	.cancel		= isi_cancel
+};
+
+/**
+ * Init USSD
+ */
+void isi_ussd_init()
+{
+	ofono_ussd_driver_register(&driver);
+}
+
+/**
+ * Unregister USSD
+ */
+void isi_ussd_exit()
+{
+	ofono_ussd_driver_unregister(&driver);
+}
diff --git a/drivers/isimodem2.5/voicecall.c b/drivers/isimodem2.5/voicecall.c
new file mode 100644
index 0000000..ecb0d0d
--- /dev/null
+++ b/drivers/isimodem2.5/voicecall.c
@@ -0,0 +1,1555 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2010.
+ *
+ * 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 <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <ofono/modem.h>
+#include <ofono/call-settings.h>
+#include <gisi/client.h>
+#include <src/common.h>
+#include <gisi/iter.h>
+#include <gisi/netlink.h>
+#include <ofono/log.h>
+#include <ofono/voicecall.h>
+
+#include "debug.h"
+#include "call.h"
+#include "isimodem.h"
+#include "isiutil.h"
+#include "timeout.h"
+
+struct isi_call {
+	uint8_t id, call_id, status, mode, mode_info, cause_type, cause;
+	uint8_t addr_type, presentation;
+	uint8_t reason;
+	char address[30], addr_pad[4];
+};
+
+struct isi_voicecall {
+	GIsiClient *client;
+
+	struct isi_call_req_context *queue;
+
+	struct isi_call calls[8];
+
+	void *control_req_irc;
+};
+
+/* ------------------------------------------------------------------------- */
+
+static void isi_call_notify(struct ofono_voicecall *ovc,
+				struct isi_call *call);
+static void isi_call_release(struct ofono_voicecall *, struct isi_call *);
+static struct ofono_call isi_call_as_ofono_call(struct isi_call const *);
+static int isi_call_status_to_clcc(struct isi_call const *call);
+static struct isi_call *isi_call_set_idle(struct isi_call *call);
+static struct isi_call_req_context *isi_call_status_req(
+	struct ofono_voicecall *ovc,
+	uint8_t id,
+	uint8_t mode,
+	ofono_voicecall_cb_t cb,
+	void *data);
+
+static void isi_call_status_ind_cb(GIsiClient *,
+					void const *restrict,
+					size_t,
+					uint16_t,
+					void *);
+
+typedef void GIsiVerify(GIsiClient *client, gboolean alive, uint16_t object,
+			void *opaque);
+
+typedef gboolean GIsiResponse(GIsiClient *client,
+				void const *restrict data, size_t len,
+				uint16_t object, void *opaque);
+
+static GIsiVerify isi_call_verify_cb;
+static gboolean isi_call_register(gpointer);
+
+/* ------------------------------------------------------------------------- */
+/* Request context for voicecall cb */
+
+struct isi_call_req_context;
+
+typedef void isi_call_req_step(struct isi_call_req_context *, int reason);
+
+struct isi_call_req_context {
+	struct isi_call_req_context *next, **prev;
+	isi_call_req_step *step;
+	struct ofono_voicecall *ovc;
+	ofono_voicecall_cb_t cb;
+	void *data;
+};
+
+/* ------------------------------------------------------------------------- */
+
+static struct isi_call_req_context *isi_call_req(
+	struct ofono_voicecall *ovc,
+	void const *restrict req,
+	size_t len,
+	GIsiResponse *handler,
+	ofono_voicecall_cb_t cb,
+	void *data) {
+
+	struct isi_voicecall *ivc;
+	struct isi_call_req_context *irc;
+
+	ivc = ofono_voicecall_get_data(ovc);
+	DBG("");
+
+	irc = g_try_new0(struct isi_call_req_context, 1);
+
+	if (irc) {
+		irc->ovc = ovc;
+		irc->cb = cb;
+		irc->data = data;
+
+		if (g_isi_request_make(ivc->client, req, len,
+					ISI_CALL_TIMEOUT, handler, irc))
+			return irc;
+	}
+
+	g_free(irc);
+
+	if (cb)
+		CALLBACK_WITH_FAILURE(cb, data);
+
+	return NULL;
+}
+
+static void isi_ctx_queue(struct isi_call_req_context *irc,
+				isi_call_req_step *next)
+{
+	DBG("");
+
+	if (irc->prev == NULL) {
+		struct isi_voicecall *ivc = ofono_voicecall_get_data(irc->ovc);
+
+		if (ivc->queue) {
+			irc->next = ivc->queue;
+			irc->next->prev = &irc->next;
+		}
+
+		irc->prev = &ivc->queue;
+		ivc->queue = irc;
+	}
+
+	irc->step = next;
+}
+
+static void isi_ctx_remove(struct isi_call_req_context *irc)
+{
+	DBG("");
+
+	if (irc->prev) {
+		*irc->prev = irc->next;
+
+		if (irc->next) {
+			irc->next->prev = irc->prev;
+			irc->next = NULL;
+		}
+
+		irc->prev = NULL;
+	}
+}
+
+static void isi_ctx_free(struct isi_call_req_context *irc)
+{
+	DBG("");
+
+	if (irc) {
+		isi_ctx_remove(irc);
+		g_free(irc);
+	}
+}
+
+static gboolean isi_ctx_return(struct isi_call_req_context *irc,
+				enum ofono_error_type type,
+				int error)
+{
+	DBG("");
+
+	if (!irc)
+		return TRUE;
+
+	if (irc->cb) {
+		struct ofono_error e = { .type = type, .error = error };
+		irc->cb(&e, irc->data);
+	}
+
+	isi_ctx_free(irc);
+	return TRUE;
+}
+
+static gboolean isi_ctx_return_failure(struct isi_call_req_context *irc)
+{
+	DBG("");
+	return isi_ctx_return(irc, OFONO_ERROR_TYPE_FAILURE, 0);
+}
+
+static gboolean isi_ctx_return_success(struct isi_call_req_context *irc)
+{
+	DBG("");
+
+	if (irc && irc->step) {
+		irc->step(irc, 0);
+		return TRUE;
+	}
+
+	return isi_ctx_return(irc, OFONO_ERROR_TYPE_NO_ERROR, 0);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Decoding subblocks */
+
+static void isi_call_any_address_sb_proc(struct isi_voicecall *ivc,
+						struct isi_call *call,
+						GIsiSubBlockIter const *sb)
+{
+	uint8_t addr_type, presentation, addr_len;
+	char *address;
+
+	if (!g_isi_sb_iter_get_byte(sb, &addr_type, 2) ||
+		!g_isi_sb_iter_get_byte(sb, &presentation, 3) ||
+		/* fillerbyte */
+		!g_isi_sb_iter_get_byte(sb, &addr_len, 5) ||
+		!g_isi_sb_iter_get_alpha_tag(sb, &address, 2 * addr_len, 6))
+		return;
+
+	call->addr_type = addr_type | 0x80;
+	call->presentation = presentation;
+	strncpy(call->address, address, sizeof call->address);
+	g_free(address);
+}
+
+static void isi_call_origin_address_sb_proc(struct isi_voicecall *ivc,
+						struct isi_call *call,
+						GIsiSubBlockIter const *sb)
+{
+	if (!call->address[0])
+		isi_call_any_address_sb_proc(ivc, call, sb);
+}
+
+static void isi_call_destination_address_sb_proc(struct isi_voicecall *ivc,
+						struct isi_call *call,
+						GIsiSubBlockIter const *sb)
+{
+	if (!call->address[0])
+		isi_call_any_address_sb_proc(ivc, call, sb);
+}
+
+static void isi_call_mode_sb_proc(struct isi_voicecall *ivc,
+					struct isi_call *call,
+					GIsiSubBlockIter const *sb)
+{
+	uint8_t mode, mode_info;
+
+	if (!g_isi_sb_iter_get_byte(sb, &mode, 2) ||
+			!g_isi_sb_iter_get_byte(sb, &mode_info, 3))
+		return;
+
+	call->mode = mode;
+	call->mode_info = mode_info;
+}
+
+static void isi_call_cause_sb_proc(struct isi_voicecall *ivc,
+					struct isi_call *call,
+					GIsiSubBlockIter const *sb)
+{
+	uint8_t cause_type, cause;
+
+	if (!g_isi_sb_iter_get_byte(sb, &cause_type, 2) ||
+			!g_isi_sb_iter_get_byte(sb, &cause, 3))
+		return;
+
+	call->cause_type = cause_type;
+	call->cause = cause;
+}
+
+static void isi_call_status_sb_proc(struct isi_voicecall *ivc,
+					struct isi_call *call,
+					GIsiSubBlockIter const *sb,
+					struct ofono_voicecall *ovc)
+{
+	uint8_t status;
+
+	if (!g_isi_sb_iter_get_byte(sb, &status, 2))
+		return;
+
+	if ((status != CALL_MODEM_STATUS_ANSWERED) &&
+	    (status != CALL_MODEM_STATUS_COMING) &&
+	    (status != CALL_MODEM_STATUS_PROCEEDING) &&
+	    (status != CALL_MODEM_STATUS_MT_ALERTING))
+		call->status = status;
+
+	if (status == CALL_MODEM_STATUS_MT_ALERTING) {
+		isi_call_status_req(ovc,
+			call->call_id,
+			CALL_MODEM_STATUS_MODE_ADDR_AND_ORIGIN,
+			NULL, NULL);
+	}
+}
+
+static struct isi_call *isi_call_status_info_sb_proc(
+	struct isi_voicecall *ivc,
+	struct isi_call calls[8],
+	GIsiSubBlockIter const *sb) {
+	struct isi_call *call = NULL;
+	int i;
+	uint8_t call_id;
+	uint8_t mode;
+	uint8_t mode_info;
+	uint8_t status;
+
+	if (!g_isi_sb_iter_get_byte(sb, &call_id, 2) ||
+			!g_isi_sb_iter_get_byte(sb, &mode, 3) ||
+			!g_isi_sb_iter_get_byte(sb, &mode_info, 4) ||
+			!g_isi_sb_iter_get_byte(sb, &status, 5))
+		return NULL;
+
+	i = call_id & 7;
+
+	if (1 <= i && i <= 7) {
+		call = &calls[i];
+		call->call_id = call_id;
+
+		if ((status != CALL_MODEM_STATUS_ANSWERED) &&
+		    (status != CALL_MODEM_STATUS_COMING) &&
+		    (status != CALL_MODEM_STATUS_PROCEEDING))
+			call->status = status;
+
+		call->mode = mode;
+		call->mode_info = mode_info;
+	}
+
+	return call;
+}
+
+static struct isi_call *isi_call_addr_and_status_info_sb_proc(
+	struct isi_voicecall *ivc,
+	struct isi_call calls[8],
+	GIsiSubBlockIter const *sb) {
+	struct isi_call *call = NULL;
+	int i;
+	uint8_t call_id;
+	uint8_t mode;
+	uint8_t mode_info;
+	uint8_t status;
+	uint8_t addr_type;
+	uint8_t presentation;
+	uint8_t addr_len;
+	char *address;
+
+	if (!g_isi_sb_iter_get_byte(sb, &call_id, 2) ||
+		!g_isi_sb_iter_get_byte(sb, &mode, 3) ||
+		!g_isi_sb_iter_get_byte(sb, &mode_info, 4) ||
+		!g_isi_sb_iter_get_byte(sb, &status, 5) ||
+		/*filler*/
+		/*link id*/
+		!g_isi_sb_iter_get_byte(sb, &addr_type, 8) ||
+		!g_isi_sb_iter_get_byte(sb, &presentation, 9) ||
+		/*filler*/
+		!g_isi_sb_iter_get_byte(sb, &addr_len, 11) ||
+		!g_isi_sb_iter_get_alpha_tag(sb, &address, 2 * addr_len, 12))
+		return NULL;
+
+	i = call_id & 7;
+
+	if (1 <= i && i <= 7) {
+		call = &calls[i];
+		call->call_id = call_id;
+
+		if ((status != CALL_MODEM_STATUS_ANSWERED) &&
+			(status != CALL_MODEM_STATUS_COMING) &&
+			(status != CALL_MODEM_STATUS_PROCEEDING))
+			call->status = status;
+
+		call->mode = mode;
+		call->mode_info = mode_info;
+		call->addr_type = addr_type | 0x80;
+		call->presentation = presentation;
+		strncpy(call->address, address, sizeof call->address);
+	}
+
+	free(address);
+
+	return call;
+}
+
+/* ------------------------------------------------------------------------- */
+/* PN_CALL messages */
+
+static GIsiResponse isi_call_status_resp,
+	isi_call_create_resp,
+	isi_call_answer_resp,
+	isi_call_release_resp,
+	isi_call_control_resp,
+	isi_call_dtmf_send_resp;
+
+static struct isi_call_req_context *isi_call_create_req(
+	struct ofono_voicecall *ovc,
+	uint8_t presentation,
+	uint8_t addr_type,
+	char const address[21],
+	ofono_voicecall_cb_t cb,
+	void *data) {
+
+	size_t addr_len = strlen(address);
+	size_t sub_len = (6 + 2 * addr_len + 3) & ~3;
+	size_t i, offset = 3 + 4 + 4 + 6;
+	uint8_t req[3 + 4 + 4 + 6 + 40] = {
+		CALL_MODEM_CREATE_REQ,
+		0, /* No id */
+		3, /* Subblock count: Mode, Clir, Number */
+		/* MODE SB */
+		/* (CALL__MODEM_MODE_INFO '0' indicates a local origination) */
+		/*sb id, len, mode, filler*/
+		CALL_MODEM_SB_MODE, 4, CALL_MODEM_MODE_SPEECH, 0,
+		/* ORIGIN_INFO SB */
+		/*sb id, len, presentation, filler*/
+		CALL_MODEM_SB_LINE_ID, 4, presentation, 0,
+		/* DESTINATION ADDRESS SB */
+		CALL_MODEM_SB_DESTINATION_ADDRESS,
+		sub_len,
+		addr_type & 0x7F,
+		0, 0,   /*filler*/
+		addr_len,
+		/* uint16_t addr[20] */
+	};
+	size_t rlen = 3 + 4 + 4 + sub_len;
+	struct isi_call_req_context *irc = NULL;
+	DBG("");
+
+	if (addr_len > 20) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return NULL;
+	}
+
+	for (i = 0; i < addr_len; i++)
+		req[offset + 2 * i + 1] = address[i];
+
+	irc = isi_call_req(ovc, req, rlen, isi_call_create_resp, cb, data);
+
+	return irc;
+}
+
+static gboolean isi_call_create_resp(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *irc)
+{
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	DBG("");
+
+	if (m != NULL && len < (sizeof *m))
+		return FALSE;
+
+	if (m == NULL)
+		return isi_ctx_return_failure(irc);
+
+	if (m->message_id != CALL_MODEM_CREATE_RESP)
+		return FALSE;
+
+	DBG("call id: %02X", m->call_id);
+
+	if (m->call_id != CALL_MODEM_ID_NONE && m->sub_blocks == 0)
+		return isi_ctx_return_success(irc);
+
+	/* Cause ? */
+	return isi_ctx_return_failure(irc);
+}
+
+static void isi_call_status_ind_cb(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *_ovc)
+{
+	struct ofono_voicecall *ovc = _ovc;
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	struct isi_call *call;
+	uint8_t old;
+	GIsiSubBlockIter sb[1];
+	DBG("");
+
+	if (len < 3)
+		return; /* runt */
+
+	if ((m->call_id & 7) == 0)
+		return;
+
+	call = &ivc->calls[m->call_id & 7];
+	old = call->status;
+	call->call_id = m->call_id;
+
+	for (g_isi_sb_iter_init(sb, data, len, (sizeof *m));
+			g_isi_sb_iter_is_valid(sb);
+			g_isi_sb_iter_next(sb)) {
+		switch (g_isi_sb_iter_get_id(sb)) {
+		case CALL_MODEM_SB_ORIGIN_ADDRESS:
+			isi_call_origin_address_sb_proc(ivc, call, sb);
+			break;
+		case CALL_MODEM_SB_STATUS:
+			isi_call_status_sb_proc(ivc, call, sb, ovc);
+			break;
+		case CALL_MODEM_SB_MODE:
+			isi_call_mode_sb_proc(ivc, call, sb);
+			break;
+		case CALL_MODEM_SB_CAUSE:
+			isi_call_cause_sb_proc(ivc, call, sb);
+			break;
+		case CALL_MODEM_SB_DESTINATION_ADDRESS:
+			isi_call_destination_address_sb_proc(ivc, call, sb);
+			break;
+		case CALL_MODEM_SB_DETAILED_CAUSE:
+		case CALL_MODEM_SB_DESTINATION_PRE_ADDRESS:
+		case CALL_MODEM_SB_DESTINATION_POST_ADDRESS:
+		case CALL_MODEM_SB_DESTINATION_SUBADDRESS:
+		case CALL_MODEM_SB_NW_CAUSE:
+			break;
+		}
+	}
+
+	DBG("    call id: %02X, mode: %02X status: %02X",
+		call->call_id, call->mode, call->status);
+
+	if (old != call->status) {
+		if (call->status == CALL_MODEM_STATUS_IDLE) {
+			isi_call_notify(ovc, call);
+			isi_call_set_idle(call);
+			return;
+		}
+	}
+
+	isi_call_notify(ovc, call);
+}
+
+static struct isi_call_req_context *isi_call_answer_req(
+				struct ofono_voicecall *ovc,
+				uint8_t call_id,
+				ofono_voicecall_cb_t cb,
+				void *data)
+{
+	uint8_t const req[] = {
+		CALL_MODEM_ANSWER_REQ, call_id, 0
+	};
+	size_t rlen = sizeof req;
+	DBG("");
+
+	return isi_call_req(ovc, req, rlen, isi_call_answer_resp, cb, data);
+}
+
+static gboolean isi_call_answer_resp(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *irc)
+{
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	DBG("");
+
+	if (m != NULL && len < (sizeof *m))
+		return FALSE;
+
+	if (m == NULL)
+		return isi_ctx_return_failure(irc);
+
+	if (m->message_id != CALL_MODEM_ANSWER_RESP)
+		return FALSE;
+
+	if (m->call_id != CALL_MODEM_ID_NONE && m->sub_blocks == 0)
+		return isi_ctx_return_success(irc);
+
+	/* Cause ? */
+	return isi_ctx_return_failure(irc);
+}
+
+static struct isi_call_req_context *isi_call_release_req(
+	struct ofono_voicecall *ovc,
+	uint8_t call_id,
+	uint8_t cause_type,
+	uint8_t cause,
+	ofono_voicecall_cb_t cb,
+	void *data) {
+
+	uint8_t const req[] = {
+		CALL_MODEM_RELEASE_REQ,
+		call_id,
+		1, /*Subblock count*/
+		CALL_MODEM_SB_CAUSE,
+		4, /*Subblock length*/
+		cause_type,
+		cause,
+	};
+
+	size_t rlen = sizeof req;
+
+	struct isi_call_req_context *irc =
+		isi_call_req(ovc, req, rlen, isi_call_release_resp, cb, data);
+	DBG("");
+
+	return irc;
+}
+
+static gboolean isi_call_release_resp(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *irc)
+{
+	const unsigned char *msg = data;
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	GIsiSubBlockIter i[1];
+	uint8_t cause_type = 0, cause = 0;
+	DBG("");
+
+	if (m != NULL && len < (sizeof *m))
+		return FALSE;
+
+	if (m == NULL)
+		return isi_ctx_return_failure(irc);
+
+	if (m->message_id != CALL_MODEM_RELEASE_RESP)
+		return FALSE;
+
+	for (g_isi_sb_iter_init(i, msg, len, (sizeof *m));
+			g_isi_sb_iter_is_valid(i);
+			g_isi_sb_iter_next(i)) {
+		if (g_isi_sb_iter_get_id(i) != CALL_MODEM_SB_CAUSE ||
+				!g_isi_sb_iter_get_byte(i, &cause_type, 2) ||
+				!g_isi_sb_iter_get_byte(i, &cause, 3))
+			continue;
+	}
+
+	DBG("cause type: %02X, cause: %02X", cause_type, cause);
+
+	if ((cause_type == CALL_MODEM_CAUSE_TYPE_SERVER ||
+			cause_type == CALL_MODEM_CAUSE_TYPE_CLIENT) &&
+			(cause == CALL_MODEM_CAUSE_RELEASE_BY_USER ||
+			cause == CALL_MODEM_CAUSE_BUSY_USER_REQUEST))
+		return isi_ctx_return_success(irc);
+	else
+		return isi_ctx_return_failure(irc);
+}
+
+static struct isi_call_req_context *isi_call_status_req(
+	struct ofono_voicecall *ovc,
+	uint8_t id,
+	uint8_t mode,
+	ofono_voicecall_cb_t cb,
+	void *data) {
+
+	unsigned char req[] = {
+		CALL_MODEM_STATUS_REQ,
+		id, /*Call id*/
+		1, /*Subblock count*/
+		CALL_MODEM_SB_STATUS_MODE,
+		4, /*Subblock length*/
+		mode,
+		0, /*filler*/
+	};
+	size_t rlen = sizeof req;
+	DBG("");
+
+	return isi_call_req(ovc, req, rlen, isi_call_status_resp, cb, data);
+}
+
+
+static gboolean isi_call_status_resp(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *_irc)
+{
+	struct isi_call_req_context *irc = _irc;
+	struct ofono_voicecall *ovc = irc->ovc;
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	GIsiSubBlockIter sb[1];
+	struct isi_call *call = NULL;
+	DBG("");
+
+	if (m != NULL && len < (sizeof *m))
+		return FALSE;
+
+	if (m == NULL)
+		return isi_ctx_return_failure(irc);
+
+	if (m->message_id != CALL_MODEM_STATUS_RESP)
+		return FALSE;
+
+	for (g_isi_sb_iter_init(sb, m, len, (sizeof *m));
+			g_isi_sb_iter_is_valid(sb);
+			g_isi_sb_iter_next(sb)) {
+		switch (g_isi_sb_iter_get_id(sb)) {
+		case CALL_MODEM_SB_STATUS_INFO:
+			call = isi_call_status_info_sb_proc(
+					ivc, ivc->calls, sb);
+			break;
+		case CALL_MODEM_SB_ADDR_AND_STATUS_INFO:
+			call = isi_call_addr_and_status_info_sb_proc(
+					ivc, ivc->calls, sb);
+
+			if (call)
+				isi_call_notify(ovc, call);
+
+			break;
+		case CALL_MODEM_SB_CAUSE:
+
+			if (call)
+				isi_call_cause_sb_proc(ivc, call, sb);
+
+			break;
+		}
+	}
+
+	return isi_ctx_return_success(irc);
+}
+
+static struct isi_call_req_context *isi_call_control_req(
+	struct ofono_voicecall *ovc,
+	uint8_t call_id,
+	uint8_t op,
+	uint8_t info,
+	ofono_voicecall_cb_t cb,
+	void *data) {
+
+	uint8_t const req[] = {
+		CALL_MODEM_CONTROL_REQ,
+		call_id,
+		1, /*Subblock count*/
+		CALL_MODEM_SB_OPERATION,
+		4, /*Subblock length*/
+		op,
+		info, /*filler*/
+	};
+	size_t rlen = sizeof req;
+	DBG("");
+
+	return isi_call_req(ovc, req, rlen, isi_call_control_resp, cb, data);
+}
+
+static gboolean isi_call_control_resp(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *irc)
+{
+	struct isi_call_req_context *resp_irc = irc;
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	GIsiSubBlockIter i[1];
+	uint8_t cause_type = 0, cause = 0;
+	DBG("");
+
+	if (m != NULL && len < sizeof *m)
+		return FALSE;
+
+	if (m == NULL)
+		return isi_ctx_return_failure(irc);
+
+	if (m->message_id != CALL_MODEM_CONTROL_RESP)
+		return FALSE;
+
+	for (g_isi_sb_iter_init(i, m, len, (sizeof *m));
+			g_isi_sb_iter_is_valid(i);
+			g_isi_sb_iter_next(i)) {
+		if (g_isi_sb_iter_get_id(i) != CALL_MODEM_SB_CAUSE ||
+				!g_isi_sb_iter_get_byte(i, &cause_type, 2) ||
+				!g_isi_sb_iter_get_byte(i, &cause, 3))
+			continue;
+	}
+
+	if (cause) {
+		struct isi_voicecall *ivc = ofono_voicecall_get_data(
+							resp_irc->ovc);
+		gboolean ret = isi_ctx_return_failure(irc);
+		ivc->control_req_irc = NULL;
+		return ret;
+	}
+
+	return TRUE;
+}
+
+static void isi_call_control_ind_cb(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *_ovc)
+{
+	struct ofono_voicecall *ovc = _ovc;
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	GIsiSubBlockIter i[1];
+	uint8_t cause_type = 0, cause = 0;
+	DBG("");
+
+	if (len < 3 || m == NULL)
+		return;
+
+	if (m->message_id != CALL_MODEM_CONTROL_IND)
+		return;
+
+	for (g_isi_sb_iter_init(i, m, len, (sizeof *m));
+			g_isi_sb_iter_is_valid(i);
+			g_isi_sb_iter_next(i)) {
+		if (g_isi_sb_iter_get_id(i) != CALL_MODEM_SB_CAUSE ||
+				!g_isi_sb_iter_get_byte(i, &cause_type, 2) ||
+				!g_isi_sb_iter_get_byte(i, &cause, 3))
+			continue;
+	}
+
+	if (ivc->control_req_irc) {
+		if (!cause)
+			isi_ctx_return_success(ivc->control_req_irc);
+		else
+			isi_ctx_return_failure(ivc->control_req_irc);
+
+		ivc->control_req_irc = NULL;
+	}
+}
+
+static struct isi_call_req_context *isi_call_dtmf_send_req(
+	struct ofono_voicecall *ovc,
+	uint8_t call_id,
+	char const *string,
+	ofono_voicecall_cb_t cb,
+	void *data) {
+
+	size_t str_len = strlen(string);
+	size_t sub_len = 4 + ((2 * str_len + 3) & ~3);
+	size_t i, offset = 3 + 4 + 8 + 4;
+	size_t rlen = 3 + 4 + 8 + sub_len;
+	uint8_t req[3 + 4 + 8 + (255 & ~3)] = {
+		CALL_MODEM_DTMF_SEND_REQ,
+		call_id,
+		3, /* Subblock count */
+		CALL_MODEM_SB_DTMF_INFO,
+		4, /* Subblock length */
+		CALL_MODEM_DTMF_ENABLE_TONE_IND_SEND,
+		0, /*filler*/
+		CALL_MODEM_SB_DTMF_TIMERS,
+		8, /* Subblock length */
+		0, 200, /* duration in ms */
+		0, 100, /* gap in ms */
+		0, 0, /* filler */
+		CALL_MODEM_SB_DTMF_STRING,
+		sub_len,
+		CALL_MODEM_DTMF_PAUSE_1S, /* pause length */
+		str_len,
+		/* string */
+	};
+	DBG("");
+
+	if (sub_len >= 256) {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return FALSE;
+	}
+
+	for (i = 0; i < str_len; i++)
+		req[offset + 2 * i + 1] = string[i];
+
+	return isi_call_req(ovc, req, rlen, isi_call_dtmf_send_resp, cb, data);
+}
+
+static gboolean isi_call_dtmf_send_resp(GIsiClient *client,
+					void const *restrict data,
+					size_t len,
+					uint16_t object,
+					void *irc)
+{
+	struct {
+		uint8_t message_id, call_id, sub_blocks;
+	} const *m = data;
+	GIsiSubBlockIter i[1];
+	uint8_t cause_type = 0, cause = 0;
+	DBG("");
+
+	if (m != NULL && len < (sizeof *m))
+		return FALSE;
+
+	if (m == NULL)
+		return isi_ctx_return_failure(irc);
+
+	if (m->message_id != CALL_MODEM_DTMF_SEND_RESP)
+		return FALSE;
+
+	if (m->sub_blocks == 0)
+		return isi_ctx_return_success(irc);
+
+	for (g_isi_sb_iter_init(i, m, len, (sizeof *m));
+			g_isi_sb_iter_is_valid(i);
+			g_isi_sb_iter_next(i)) {
+		if (g_isi_sb_iter_get_id(i) != CALL_MODEM_SB_CAUSE ||
+				!g_isi_sb_iter_get_byte(i, &cause_type, 2) ||
+				!g_isi_sb_iter_get_byte(i, &cause, 3))
+			continue;
+	}
+
+	if (!cause)
+		return isi_ctx_return_success(irc);
+	else
+		return isi_ctx_return_failure(irc);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Notify */
+
+static void isi_call_notify(struct ofono_voicecall *ovc,
+				struct isi_call *call)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	struct isi_call_req_context *irc, **queue;
+	struct ofono_call ocall;
+	DBG("");
+
+	for (queue = &ivc->queue; (irc = *queue);) {
+		irc->step(irc, call->status);
+
+		if (*queue == irc)
+			queue = &irc->next;
+	}
+
+	switch (call->status) {
+	case CALL_MODEM_STATUS_IDLE:
+		return;
+	case CALL_MODEM_STATUS_MO_RELEASE:
+	case CALL_MODEM_STATUS_MT_RELEASE:
+		isi_call_release(ovc, call);
+		return;
+	default:
+		break;
+	}
+
+	ocall = isi_call_as_ofono_call(call);
+	DBG("    id: %u, %s, status: %u, \"%s\", num.type: %u, clpi type: %u",
+		ocall.id,
+		ocall.direction ? "MT" : "MO",
+		ocall.status,
+		ocall.phone_number.number,
+		ocall.phone_number.type,
+		ocall.clip_validity);
+	ofono_voicecall_notify(ovc, &ocall);
+}
+
+static void isi_call_release(struct ofono_voicecall *ovc,
+				struct isi_call *call)
+{
+	struct ofono_error error = { OFONO_ERROR_TYPE_NO_ERROR, 0 };
+	enum ofono_disconnect_reason reason;
+	DBG("");
+
+	switch (call->status) {
+	case CALL_MODEM_STATUS_IDLE:
+		reason = OFONO_DISCONNECT_REASON_UNKNOWN;
+		break;
+	case CALL_MODEM_STATUS_MO_RELEASE:
+		reason = OFONO_DISCONNECT_REASON_LOCAL_HANGUP;
+		break;
+	case CALL_MODEM_STATUS_MT_RELEASE:
+		reason = OFONO_DISCONNECT_REASON_REMOTE_HANGUP;
+		break;
+	default:
+		reason = OFONO_DISCONNECT_REASON_ERROR;
+		break;
+	}
+
+	if (!call->reason) {
+		call->reason = reason;
+		DBG("disconnected id: %02X, reason: %u", call->id, reason);
+		ofono_voicecall_disconnected(ovc, call->id, reason, &error);
+	}
+
+	if (!reason)
+		isi_call_set_idle(call);
+}
+
+static struct ofono_call isi_call_as_ofono_call(struct isi_call const *call)
+{
+	struct ofono_call ocall = { call->id };
+	struct ofono_phone_number *number = &ocall.phone_number;
+
+	ocall.type = 0; /* Voice call */
+	ocall.direction = call->mode_info & CALL_MODEM_MODE_ORIGINATOR;
+	ocall.status = isi_call_status_to_clcc(call);
+	memmove(number->number, call->address, sizeof number->number);
+	number->type = 0x80 | call->addr_type;
+	ocall.clip_validity = call->presentation & 3;
+
+	if (ocall.clip_validity == 0 && strlen(number->number) == 0)
+		ocall.clip_validity = 2;
+
+	return ocall;
+}
+
+/** Get +CLCC status */
+static int isi_call_status_to_clcc(struct isi_call const *call)
+{
+	switch (call->status) {
+	case CALL_MODEM_STATUS_CREATE:
+		return CALL_STATUS_DIALING;
+	case CALL_MODEM_STATUS_COMING:
+	case CALL_MODEM_STATUS_MT_ALERTING:
+		return CALL_STATUS_INCOMING;
+	case CALL_MODEM_STATUS_PROCEEDING:
+		if ((call->mode_info & CALL_MODEM_MODE_ORIGINATOR))
+			return CALL_STATUS_INCOMING;
+		else
+			return CALL_STATUS_DIALING;
+
+	case CALL_MODEM_STATUS_MO_ALERTING:
+		return CALL_STATUS_ALERTING;
+	case CALL_MODEM_STATUS_WAITING:
+		return CALL_STATUS_WAITING;
+	case CALL_MODEM_STATUS_ANSWERED:
+	case CALL_MODEM_STATUS_ACTIVE:
+	case CALL_MODEM_STATUS_MO_RELEASE:
+	case CALL_MODEM_STATUS_MT_RELEASE:
+	case CALL_MODEM_STATUS_HOLD_INITIATED:
+	case CALL_MODEM_STATUS_RECONNECT_PENDING:
+		return CALL_STATUS_ACTIVE;
+	case CALL_MODEM_STATUS_HOLD:
+	case CALL_MODEM_STATUS_RETRIEVE_INITIATED:
+		return CALL_STATUS_HELD;
+	case CALL_MODEM_STATUS_IDLE:
+		return CALL_STATUS_DISCONNECTED;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static struct isi_call *isi_call_set_idle(struct isi_call *call)
+{
+	uint8_t id;
+
+	if (call) {
+		id = call->id;
+		memset(call, 0, sizeof *call);
+		call->id = id;
+	}
+
+	return call;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void isi_dial(struct ofono_voicecall *ovc,
+			const struct ofono_phone_number *restrict number,
+			enum ofono_clir_option clir,
+			enum ofono_cug_option cug,
+			ofono_voicecall_cb_t cb,
+			void *data)
+{
+	unsigned char presentation = CALL_MODEM_PRESENT_DEFAULT;
+	DBG("");
+
+	if (clir == OFONO_CLIR_OPTION_DEFAULT)
+		clir = get_clir_status();
+
+	switch (clir) {
+	case OFONO_CLIR_OPTION_DEFAULT:
+		presentation = CALL_MODEM_PRESENT_DEFAULT;
+		break;
+	case OFONO_CLIR_OPTION_INVOCATION:
+		presentation = CALL_MODEM_PRESENT_RESTRICTED;
+		break;
+	case OFONO_CLIR_OPTION_SUPPRESSION:
+		presentation = CALL_MODEM_PRESENT_ALLOWED;
+		break;
+	default:
+		break;
+	}
+
+	if (cug == OFONO_CUG_OPTION_INVOCATION) {
+		/* Not implemented */
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	isi_call_create_req(ovc, presentation,
+				number->type,
+				number->number,
+				cb, data);
+}
+
+static void isi_answer(struct ofono_voicecall *ovc,
+			ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	uint8_t call_id;
+	DBG("");
+
+	for (call_id = 1; call_id <= 7; call_id++) {
+		if (ivc->calls[call_id].status ==
+			CALL_MODEM_STATUS_MT_ALERTING ||
+			ivc->calls[call_id].status == CALL_MODEM_STATUS_WAITING)
+			break;
+	}
+
+	isi_call_answer_req(ovc, call_id, cb, data);
+}
+
+
+static void isi_hangup(struct ofono_voicecall *ovc,
+			ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+
+	uint8_t call_id;
+	DBG("");
+
+	for (call_id = 1; call_id <= 7; call_id++) {
+		if (ivc->calls[call_id].status ==
+				CALL_MODEM_STATUS_CREATE ||
+		    ivc->calls[call_id].status ==
+				CALL_MODEM_STATUS_MO_ALERTING ||
+		    ivc->calls[call_id].status ==
+				CALL_MODEM_STATUS_PROCEEDING ||
+		    ivc->calls[call_id].status == CALL_MODEM_STATUS_ACTIVE)
+			break;
+	}
+
+	DBG("");
+	isi_call_release_req(ovc, call_id, CALL_MODEM_CAUSE_TYPE_CLIENT,
+				CALL_MODEM_CAUSE_RELEASE_BY_USER,
+				cb, data);
+}
+
+static void isi_hangup_all(struct ofono_voicecall *ovc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	DBG("");
+	isi_call_release_req(ovc, CALL_MODEM_ID_ALL,
+				CALL_MODEM_CAUSE_TYPE_CLIENT,
+				CALL_MODEM_CAUSE_RELEASE_BY_USER,
+				cb, data);
+}
+
+static void isi_release_all_held(struct ofono_voicecall *ovc,
+				 ofono_voicecall_cb_t cb, void *data)
+{
+	DBG("");
+	isi_call_release_req(ovc, CALL_MODEM_ID_HOLD,
+				CALL_MODEM_CAUSE_TYPE_CLIENT,
+				CALL_MODEM_CAUSE_RELEASE_BY_USER,
+				cb, data);
+}
+
+static void isi_set_udub(struct ofono_voicecall *ovc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	int id;
+	DBG("");
+
+	for (id = 1; id <= 7; id++) {
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_WAITING)
+			break;
+
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_MT_ALERTING)
+			break;
+
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_COMING)
+			break;
+	}
+
+	if (id <= 7)
+		isi_call_release_req(ovc, id,
+					CALL_MODEM_CAUSE_TYPE_CLIENT,
+					CALL_MODEM_CAUSE_BUSY_USER_REQUEST,
+					cb, data);
+	else
+		CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void isi_retrieve(struct ofono_voicecall *ovc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	DBG("");
+
+	ivc->control_req_irc = isi_call_control_req(ovc, CALL_MODEM_ID_HOLD,
+				CALL_MODEM_OP_RETRIEVE, 0, cb, data);
+}
+
+static isi_call_req_step isi_wait_and_answer, isi_wait_and_retrieve;
+
+static void isi_release_all_active(struct ofono_voicecall *ovc,
+					ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	int id, waiting = 0, active = 0, hold = 0;
+	DBG("");
+
+	for (id = 1; id <= 7; id++) {
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_WAITING)
+			waiting++;
+
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_HOLD)
+			hold++;
+
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_ACTIVE)
+			active++;
+	}
+
+	if (active) {
+		struct isi_call_req_context *irc;
+		irc = isi_call_release_req(ovc, CALL_MODEM_ID_ACTIVE,
+					   CALL_MODEM_CAUSE_TYPE_CLIENT,
+					   CALL_MODEM_CAUSE_RELEASE_BY_USER,
+					   cb, data);
+
+		if (irc == NULL)
+			;
+		else if (waiting)
+			isi_ctx_queue(irc, isi_wait_and_answer);
+		else if (hold)
+			isi_ctx_queue(irc, isi_wait_and_retrieve);
+	} else
+		CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void isi_wait_and_answer(struct isi_call_req_context *irc,
+				int event)
+{
+	DBG("");
+	DBG("irc: %p, event: %u", (void *) irc, event);
+
+	switch (event) {
+	case CALL_MODEM_STATUS_IDLE:
+		isi_answer(irc->ovc, irc->cb, irc->data);
+		isi_ctx_free(irc);
+		break;
+	default:
+		break;
+	}
+}
+
+static void isi_wait_and_retrieve(struct isi_call_req_context *irc,
+					int event)
+{
+	DBG("");
+	DBG("irc: %p, event: %u", (void *) irc, event);
+
+	switch (event) {
+	case CALL_MODEM_STATUS_IDLE:
+		isi_retrieve(irc->ovc, irc->cb, irc->data);
+		isi_ctx_free(irc);
+		break;
+	default:
+		break;
+	}
+}
+
+static void isi_hold_all_active(struct ofono_voicecall *ovc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	int id, op = 0, waiting = 0, active = 0, hold = 0;
+	DBG("");
+
+	for (id = 1; id <= 7; id++) {
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_WAITING)
+			waiting++;
+
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_HOLD)
+			hold++;
+
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_ACTIVE)
+			active++;
+	}
+
+	if (waiting) {
+		isi_call_answer_req(ovc, CALL_MODEM_ID_WAITING, cb, data);
+	} else if (hold) {
+		if (active)
+			id = CALL_MODEM_ID_ACTIVE, op = CALL_MODEM_OP_SWAP;
+		else
+			id = CALL_MODEM_ID_HOLD, op = CALL_MODEM_OP_RETRIEVE;
+
+		ivc->control_req_irc = isi_call_control_req(ovc, id, op, 0,
+					cb, data);
+	} else if (active) {
+		id = CALL_MODEM_ID_ACTIVE, op = CALL_MODEM_OP_HOLD;
+		ivc->control_req_irc = isi_call_control_req(ovc, id, op, 0,
+					cb, data);
+	} else {
+		CALLBACK_WITH_FAILURE(cb, data);
+	}
+}
+
+static void isi_release_specific(struct ofono_voicecall *ovc, int id,
+				 ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	DBG("");
+
+	if (1 <= id && id <= 7) {
+		struct isi_call const *status = &ivc->calls[id];
+		uint8_t cause = CALL_MODEM_CAUSE_RELEASE_BY_USER;
+
+		switch (status->status) {
+		case CALL_MODEM_STATUS_MT_ALERTING:
+		case CALL_MODEM_STATUS_WAITING:
+			cause = CALL_MODEM_CAUSE_BUSY_USER_REQUEST;
+			break;
+		case CALL_MODEM_STATUS_PROCEEDING:
+
+			if ((status->mode_info & CALL_MODEM_MODE_ORIGINATOR))
+				cause = CALL_MODEM_CAUSE_BUSY_USER_REQUEST;
+
+			break;
+		default:
+			break;
+		}
+
+		isi_call_release_req(ovc, id,
+					CALL_MODEM_CAUSE_TYPE_CLIENT, cause,
+					cb, data);
+	} else
+		CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void isi_private_chat(struct ofono_voicecall *ovc, int id,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	DBG("");
+
+	if (1 <= id && id <= 7)
+		ivc->control_req_irc = isi_call_control_req(ovc,
+					id, CALL_MODEM_OP_CONFERENCE_SPLIT, 0,
+					cb, data);
+	else
+		CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void isi_create_multiparty(struct ofono_voicecall *ovc,
+					ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	DBG("");
+
+	ivc->control_req_irc = isi_call_control_req(ovc,
+				CALL_MODEM_ID_ACTIVE,
+				CALL_MODEM_OP_CONFERENCE_BUILD,
+				0, cb, data);
+}
+
+static void isi_transfer(struct ofono_voicecall *ovc,
+				ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	uint8_t id;
+	DBG("");
+
+	for (id = 1; id <= 7; id++) {
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_MO_ALERTING)
+			break;
+	}
+
+	if (id > 7)
+		id = CALL_MODEM_ID_HOLD;
+
+	ivc->control_req_irc = isi_call_control_req(ovc,
+				id, CALL_MODEM_OP_TRANSFER, 0,
+				cb, data);
+}
+
+static void isi_swap_without_accept(struct ofono_voicecall *ovc,
+					ofono_voicecall_cb_t cb, void *data)
+{
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	int id, op = 0, active = 0, hold = 0;
+	DBG("");
+
+	for (id = 1; id <= 7; id++) {
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_HOLD)
+			hold++;
+
+		if (ivc->calls[id].status == CALL_MODEM_STATUS_ACTIVE)
+			active++;
+	}
+
+	if (hold && active) {
+		id = CALL_MODEM_ID_ACTIVE, op = CALL_MODEM_OP_SWAP;
+	} else if (active) {
+		id = CALL_MODEM_ID_ACTIVE, op = CALL_MODEM_OP_HOLD;
+	} else if (hold) {
+		id = CALL_MODEM_ID_HOLD, op = CALL_MODEM_OP_RETRIEVE;
+	} else {
+		CALLBACK_WITH_FAILURE(cb, data);
+		return;
+	}
+
+	ivc->control_req_irc = isi_call_control_req(ovc, id, op, 0, cb, data);
+}
+
+static void isi_send_tones(struct ofono_voicecall *ovc, const char *tones,
+				 ofono_voicecall_cb_t cb, void *data)
+{
+	DBG("");
+	isi_call_dtmf_send_req(ovc, CALL_MODEM_ID_ALL, tones, cb, data);
+}
+
+static int isi_voicecall_probe(struct ofono_voicecall *ovc,
+				unsigned int vendor,
+				void *user)
+{
+	GIsiModem *idx = user;
+	struct isi_voicecall *ivc = g_try_new0(struct isi_voicecall, 1);
+	int id;
+	DBG("");
+
+	if (!ivc)
+		return -ENOMEM;
+
+	for (id = 0; id <= 7; id++)
+		ivc->calls[id].id = id;
+
+	ivc->client = g_isi_client_create(idx, PN_MODEM_CALL);
+
+	if (!ivc->client) {
+		g_free(ivc);
+		return -ENOMEM;
+	}
+
+	ofono_voicecall_set_data(ovc, ivc);
+
+	if (!g_isi_verify(ivc->client, isi_call_verify_cb, ovc))
+		DBG("unable to verify reachability");
+
+	return 0;
+}
+
+static void isi_call_verify_cb(GIsiClient *client,
+				gboolean alive, uint16_t object,
+				void *ovc)
+{
+	DBG("");
+
+	if (!alive) {
+		DBG("unable to bootstrap voice call driver");
+		return;
+	}
+
+	DBG("    %s (v%03d.%03d) reachable",
+		pn_resource_name(g_isi_client_resource(client)),
+		g_isi_version_major(client),
+		g_isi_version_minor(client));
+	g_idle_add(isi_call_register, ovc);
+}
+
+static gboolean isi_call_register(gpointer _ovc)
+{
+	struct ofono_voicecall *ovc = _ovc;
+	struct isi_voicecall *ivc = ofono_voicecall_get_data(ovc);
+	DBG("");
+
+	g_isi_subscribe(ivc->client,
+			CALL_MODEM_STATUS_IND, isi_call_status_ind_cb,
+			ovc);
+	g_isi_subscribe(ivc->client,
+			CALL_MODEM_CONTROL_IND, isi_call_control_ind_cb,
+			ovc);
+
+	if (!isi_call_status_req(ovc,
+				CALL_MODEM_ID_ALL,
+				CALL_MODEM_STATUS_MODE_ADDR_AND_ORIGIN,
+				NULL, NULL))
+		DBG("    failed to request call status");
+
+	ofono_voicecall_register(ovc);
+	return FALSE;
+}
+
+static void isi_voicecall_remove(struct ofono_voicecall *call)
+{
+	struct isi_voicecall *data = ofono_voicecall_get_data(call);
+	DBG("");
+
+	if (data) {
+		g_isi_client_destroy(data->client);
+		g_free(data);
+	}
+}
+
+static struct ofono_voicecall_driver driver = {
+	.name				= "isimodem25",
+	.probe				= isi_voicecall_probe,
+	.remove				= isi_voicecall_remove,
+	.dial				= isi_dial,
+	.answer				= isi_answer,
+	.hangup_active			= isi_hangup,
+	.hangup_all			= isi_hangup_all,
+	.hold_all_active		= isi_hold_all_active,
+	.release_all_held		= isi_release_all_held,
+	.set_udub			= isi_set_udub,
+	.release_all_active		= isi_release_all_active,
+	.release_specific		= isi_release_specific,
+	.private_chat			= isi_private_chat,
+	.create_multiparty		= isi_create_multiparty,
+	.transfer			= isi_transfer,
+	.swap_without_accept		= isi_swap_without_accept,
+	.send_tones			= isi_send_tones,
+};
+
+void isi_voicecall_init()
+{
+	DBG("");
+	ofono_voicecall_driver_register(&driver);
+}
+
+void isi_voicecall_exit()
+{
+	DBG("");
+	ofono_voicecall_driver_unregister(&driver);
+}
-- 
1.7.3.2


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

end of thread, other threads:[~2010-12-09 11:36 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-08  8:34 [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5 Jessica Nilsson
2010-12-08  9:30 ` Marcel Holtmann
2010-12-08 13:25   ` Jessica Nilsson
2010-12-08 13:42     ` Mika.Liljeberg
2010-12-08 15:19     ` Marcel Holtmann
2010-12-09  8:45       ` Jessica Nilsson
2010-12-09  6:26 ` Aki Niemi
2010-12-09 11:36   ` Jessica Nilsson

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.