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

* Re: [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5
  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-09  6:26 ` Aki Niemi
  1 sibling, 1 reply; 8+ messages in thread
From: Marcel Holtmann @ 2010-12-08  9:30 UTC (permalink / raw)
  To: ofono

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

Hi Jessica,

> 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

this is not gonna work this way. No one can review such a massive patch.
Actually Evolution even refused to format this for me.

So please split this into one patch per atom driver.

In addition, I don't a point in a filename. So isimodem25 or isimodem2
or something like that please. I am open for proposals.

Regards

Marcel



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

* Re: [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5
  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
  0 siblings, 2 replies; 8+ messages in thread
From: Jessica Nilsson @ 2010-12-08 13:25 UTC (permalink / raw)
  To: ofono

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

Hi Marcel,

thanks for your input.

>
> this is not gonna work this way. No one can review such a massive patch.
> Actually Evolution even refused to format this for me.
>    
:-)
Right you are, it's huge

> So please split this into one patch per atom driver.
>    
We are starting to look at this split up.
Do you have any other suggestions?

> In addition, I don't a point in a filename. So isimodem25 or isimodem2
> or something like that please. I am open for proposals.
>    
Let's go for isimodem25

Best Regards,
Jessica Nilsson


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

* RE: [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5
  2010-12-08 13:25   ` Jessica Nilsson
@ 2010-12-08 13:42     ` Mika.Liljeberg
  2010-12-08 15:19     ` Marcel Holtmann
  1 sibling, 0 replies; 8+ messages in thread
From: Mika.Liljeberg @ 2010-12-08 13:42 UTC (permalink / raw)
  To: ofono

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

Hi, 

> > In addition, I don't a point in a filename. So isimodem25 
> or isimodem2
> > or something like that please. I am open for proposals.
> >    
> Let's go for isimodem25

Quite a bit of the code is practically a copy-paste from the isimodem driver. Have you looked into the possibility of supporting both ISI interface versions in the same driver, or at least sharing some of the atom drivers?

	MikaL

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

* Re: [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5
  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
  1 sibling, 1 reply; 8+ messages in thread
From: Marcel Holtmann @ 2010-12-08 15:19 UTC (permalink / raw)
  To: ofono

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

Hi Jessica,

> > So please split this into one patch per atom driver.
> >    
> We are starting to look at this split up.
> Do you have any other suggestions?

I really want one patch per atom driver.

> > In addition, I don't a point in a filename. So isimodem25 or isimodem2
> > or something like that please. I am open for proposals.
> >    
> Let's go for isimodem25

Please sync with Aki if it might not be better to do the vendor quirk
system that we are using with atmodem. I am open here for suggestions
and you guys have more experience in what can be shared and what is
different.

Regards

Marcel



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

* Re: [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5
  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-09  6:26 ` Aki Niemi
  2010-12-09 11:36   ` Jessica Nilsson
  1 sibling, 1 reply; 8+ messages in thread
From: Aki Niemi @ 2010-12-09  6:26 UTC (permalink / raw)
  To: ofono

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

Hi Jessica,

2010/12/8 Jessica Nilsson <jessica.j.nilsson@stericsson.com>:
> +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);
> +}

The CBS topics set is simply not implemented in the current cbs
driver. I suggest you create a patch for adding that into the current
driver.

> +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);
> +}

And same for the clear_topics callback.

> diff --git a/drivers/isimodem2.5/checkpatch.pl b/drivers/isimodem2.5/checkpatch.pl
> new file mode 100755
> index 0000000..a4d7434

This has no business being in the isimodem driver. I suppose it was
included by mistake.

> +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);
> +}

So the IMEI is not stored on the modem at all. This obviously needs a
quirk, but I wonder if it would be cleaner to handle this in the modem
plugin. See for example how GPIO lines are handled in the n900 driver.

> diff --git a/drivers/isimodem2.5/gpds-context.c b/drivers/isimodem2.5/gpds-context.c
> new file mode 100644
> index 0000000..5bc9d17

Is there actually anything different here, except for the name change?
It's using a forked version of GIsiPipe, but I'm pretty sure we can
just add the missing bits into the existing GIsiPipe class.

Anyway, the gprs-context driver has changed quite drastically
recently, as the oFono core GPRS support for multiple contexts changed
the way the drivers are allocated.

> +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;
> +}

Just adding the decoding for NET_MODEM_ subblocks here would be
enough. In fact, these subblocks look almost identical to the existing
NET_ subblocks, so adding just extra case statements with the new
codepoints would probably work, too.

> +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);
> +}

I think this is a bad idea. I know you're using NET_CS_CONTROL_REQ
here to implement the unregister callback, but the this is basically
just wrapping existing PN_MTC functionality. In general, ISI modems
don't seem to understand what a deregister even means.

In fact, even the D-Bus method seems of little value, and I would
remove it altogether. In any case, leaving this unimplemented is my
preference.

> +       /* TODO Here we should notify framework once it
> +        * supports this indication e.g.
> +        * ofono_netreg_name_notify(netreg, op.name);
> +        */

Right, we need to figure out how NITZ names are to be supported,
particularly with ISI modems.

I've sent some TODO items for this, but we need to figure out how this
is going to work with AT modems as well.

> +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 */

This is different from the current netreg driver. However, it's easy
enough to alternate, see below.

> +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;
> +}

I would suggest probing for both PN_NETWORK and PN_MODEM_NETWORK here.
Then which ever answers first gets used. After we know with which
resource we're working with, overloading a few of the ISI messages is
enough to make this driver work with both versions of modems.

I didn't go through all of the patch, but from what I can see, we can
pretty well fold the WG2.5 modem support into the existing drivers.

Cheers,
Aki

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

* Re: [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5
  2010-12-08 15:19     ` Marcel Holtmann
@ 2010-12-09  8:45       ` Jessica Nilsson
  0 siblings, 0 replies; 8+ messages in thread
From: Jessica Nilsson @ 2010-12-09  8:45 UTC (permalink / raw)
  To: ofono

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

Hi Marcel,
> Please sync with Aki if it might not be better to do the vendor quirk
> system that we are using with atmodem. I am open here for suggestions
> and you guys have more experience in what can be shared and what is
> different.
>    

we will sync with Aki if there is a better way of implementing this,
we have got a couple of really good review comments from him already.

(Thanks also to Mika Liljeberg for suggesting something similar)


I guess the question is what will be most efficient and easiest to maintain.


Best Regards,
Jessica Nilsson









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

* Re: [PATCH 3/4] isimodem2.5: Changes to add isimodem2.5
  2010-12-09  6:26 ` Aki Niemi
@ 2010-12-09 11:36   ` Jessica Nilsson
  0 siblings, 0 replies; 8+ messages in thread
From: Jessica Nilsson @ 2010-12-09 11:36 UTC (permalink / raw)
  To: ofono

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

Hi Aki,
> The CBS topics set is simply not implemented in the current cbs
> driver. I suggest you create a patch for adding that into the current
> driver.
>
>    

> And same for the clear_topics callback.
Yes, I  might be able to do that. I can not test it though, I haven't 
got any isimodem HW.
I assume you mean submitting a patch to the isimodem for this?

> This has no business being in the isimodem driver. I suppose it was
> included by mistake.
>    
Yes, sorry.
>
> So the IMEI is not stored on the modem at all. This obviously needs a
> quirk, but I wonder if it would be cleaner to handle this in the modem
> plugin. See for example how GPIO lines are handled in the n900 driver.
>
>    
Right, we will look into that and probably get back to you on this with 
questions.


> Is there actually anything different here, except for the name change?
> It's using a forked version of GIsiPipe, but I'm pretty sure we can
> just add the missing bits into the existing GIsiPipe class.
>    
Yes, that could be a solution.
> Just adding the decoding for NET_MODEM_ subblocks here would be
> enough. In fact, these subblocks look almost identical to the existing
> NET_ subblocks, so adding just extra case statements with the new
> codepoints would probably work, too.
>    
That would certainly look neater.  :-)

> I think this is a bad idea. I know you're using NET_CS_CONTROL_REQ
> here to implement the unregister callback, but the this is basically
> just wrapping existing PN_MTC functionality. In general, ISI modems
> don't seem to understand what a deregister even means.
>
> In fact, even the D-Bus method seems of little value, and I would
> remove it altogether. In any case, leaving this unimplemented is my
> preference.
>    
Ok, we can see if this works for us, but you are probably right.

> This is different from the current netreg driver. However, it's easy
> enough to alternate, see below.
>    
> I would suggest probing for both PN_NETWORK and PN_MODEM_NETWORK here.
> Then which ever answers first gets used. After we know with which
> resource we're working with, overloading a few of the ISI messages is
> enough to make this driver work with both versions of modems.
>    

Seems pretty straighforward.

> I didn't go through all of the patch, but from what I can see, we can
> pretty well fold the WG2.5 modem support into the existing drivers.
>    
We'll get back to you on that when we have had another look at this and 
your other suggestions.

Thanks for your comments.  :-)


Best Regards,
Jessica

^ permalink raw reply	[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.